Multiple Elements Support
August 17, 2026 ยท View on GitHub
Matchers support an element array returned from $$():
- Strict Index-based Matching: If an array of expected values is provided, it must match the elements' count; each value is checked at its index.
- If a single value is provided, every element is compared to it.
- Asymmetric matchers (e.g.,
expect.stringContaining) work within expected value arrays. - Assertion fails if no elements are found, except with
toBeElementsArrayOfSizeand existing matcherstoExist,toBeExistingandtoBePresent. - Options like
StringOptionsorHTMLOptionsapply to the whole array;NumberMatcherbehaves like any expected provided value. - The assertion passes only if all elements match.
- Using
.notmeans all elements must not match. - On failures, the element array is automatically re-fetched until the matcher passes or times out, ensuring reliability against dynamic DOM changes.
Note: To apply strict index-based matching to the toHaveText matcher, useToHaveTextStrictMultiElementsCompareStrategy must be enabled. Else legacy behavior applies.
// On the matcher directly
expect($$('elements')).toHaveText(['text1','text2'], { featureFlags: { useToHaveTextStrictMultiElementsCompareStrategy : true } })
// Before hook
before(() => {
setFeatureFlags({ useToHaveTextStrictMultiElementsCompareStrategy : true })
})
// Globally in wdio.conf file
before: function (_capabilities, _specs) {
setFeatureFlags({ useToHaveTextStrictMultiElementsCompareStrategy : true })
}
Limitations
- Instead of
StringOptionsfor a single expected value, use RegExp or asymmetric matchers.- For
ignoreCaseuse RegEx (/MyExample/i) - For
containinguse Asymmetric Matchers (expect.stringContaining('Example'))
- For
- Passing an array of "containing" values is a legacy behavior and only used by default with
toHaveTextwhenuseToHaveTextStrictMultiElementsCompareStrategyis disabled.
Browser Runner
Since the Browser Runner uses standard expect by only extending the expect-webdriverio matchers, expect.oneOf and some are not currently supported.
Supported types
You can pass any of these element types to expect:
ChainablePromiseArray(the non-awaited case)ElementArray(the awaited case)Element[](the filtered case)
Alternative
For more granular or explicit per-element validation, use a parameterized test of your framework. Example in Mocha:
describe('Element at index of `$$`', function () {
[ { expectedText: 'one', index: 0 },
{ expectedText: 'two', index: 2 },
{ expectedText: 'four', index: 4 },
].forEach(function ( { expectedText, index } ) {
it(`Element at ${index} of `$$('label')` have text "${expectedText}"`, function () {
await expect($$('label')[index]).toHaveText(expectedText);
});
});
});
Example
useToHaveTextStrictMultiElementsCompareStrategy is assumed to be enabled
import { some } from 'expect-webdriverio/api'
const elements = $$('myElements')
// Single expected value
// Every element in the list must match this exact text.
await expect(elements).toHaveText('myValue1');
// Every element in the list must match either option.
await expect(elements).toHaveText(/optionA|optionB/);
// NOT Equivalent to:
await expect(elements).toHaveText(['optionA', 'optionB']);
// but equivalent to
await expect(elements).toHaveText(expect.oneOf('optionA', 'optionB'));
// Multiple expected values
// Elements must match index-by-index: element 0 must be 'valueForIndex0' AND element 1 must be 'valueForIndex1'.
await expect(elements).toHaveText(['valueForIndex0', 'valueForIndex1']);
// Element at index 0 must match either `index0OptionA` or `index0OptionB` AND element 1 must match the exact string `index1OptionC`.
await expect(elements).toHaveText([
/index0OptionA|index0OptionB/,
'index1OptionC'
]);
// Equivalent as
await expect(elements).toHaveText([
expect.oneOf('index0OptionA','index0OptionB'),
'index1OptionC'
]);
// Negation with `.not`
// Every element in the list must NOT match the regex pattern.
await expect(elements).not.toHaveText(/forbiddenTextA|forbiddenTextB/);
// Allow to succeed only if one element matches (or not match)
// Succeeds if at least one element matches either 'optionA' or 'optionB'
await expect(some(elements)).toHaveText(expect.oneOf('optionA', 'optionB'));
// Succeeds if at least one element does not matches either 'forbiddenTextA' or 'forbiddenTextB'
await expect(some(elements)).not.toHaveText(/forbiddenTextA|forbiddenTextB/);
// Succeeds if the first element matches 'valueForIndex0' OR the second matches 'valueForIndex1'
await expect(some(elements)).toHaveText(['valueForIndex0', 'valueForIndex1']);
COMING SOON
- Refresh ElementArrays automatically on failures for more robust assertions