Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,5 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm install --force
- name: Build
run: npm run build
- name: Run Tests
run: npm test
- name: Run All Checks
run: npm run checks:all
Comment on lines +24 to +25
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting on merge of #1991

69 changes: 49 additions & 20 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

When you're writing tests, you often need to check that values meet certain conditions. `expect` gives you access to a number of "matchers" that let you validate different things on the `browser`, an `element` or `mock` object.

**Note:** Multi-remote is not yet supported; any working case is coincidental and could break or change until fully supported.

## Soft Assertions

Soft assertions allow you to continue test execution even when an assertion fails. This is useful when you want to check multiple conditions in a test and collect all failures rather than stopping at the first failure. Failures are collected and reported at the end of the test.
Expand Down Expand Up @@ -252,15 +254,49 @@ await expect(browser).toHaveClipboardText(expect.stringContaining('clipboard tex

## Element Matchers

### Multiples Elements Support

All element matchers support arrays (e.g., `$$()` results).

- Each element must pass the matcher for the assertion to succeed; if any fail, the assertion fails.
- `toHaveText` differ and keep it's legacy behavior.
- See [MultipleElements.md](MultipleElements.md) for details.

#### Usage

```ts
await expect($$('#someElem')).toBeDisplayed()
await expect(await $$('#someElem')).toBeDisplayed()
```

```ts
const elements = await $$('#someElem')

// Single value: checked against every element
await expect(elements).toHaveAttribute('class', 'form-control')

// Array: each value checked at corresponding element index (must match length)
await expect(elements).toHaveAttribute('class', ['control1', 'control2'])

// Use asymmetric matchers for flexible matching
await expect(elements).toHaveAttribute('class', [expect.stringContaining('control1'), 'control2'])

// Use RegEx `i` for case insensitive
await expect(elements).toHaveAttribute('class', [/'Control1'/i, 'control2'])


// Works with filtered arrays too
await expect($$('#someElem').filter(el => el.isDisplayed())).toHaveAttribute('class', ['control1', 'control2'])
```

### toBeDisplayed

Calls [`isDisplayed`](https://webdriver.io/docs/api/element/isDisplayed/) on given element.

##### Usage

```js
const elem = await $('#someElem')
await expect(elem).toBeDisplayed()
await expect($('#someElem')).toBeDisplayed()
```

### toExist
Expand All @@ -270,8 +306,7 @@ Calls [`isExisting`](https://webdriver.io/docs/api/element/isExisting) on given
##### Usage

```js
const elem = await $('#someElem')
await expect(elem).toExist()
await expect($('#someElem')).toExist()
```

### toBePresent
Expand All @@ -281,8 +316,7 @@ Same as `toExist`.
##### Usage

```js
const elem = await $('#someElem')
await expect(elem).toBePresent()
await expect($('#someElem')).toBePresent()
```

### toBeExisting
Expand Down Expand Up @@ -375,8 +409,7 @@ Checks if an element can be clicked by calling [`isClickable`](https://webdriver
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toBeClickable()
await expect($('#elem')).toBeClickable()
```

### toBeDisabled
Expand Down Expand Up @@ -412,8 +445,7 @@ Checks if an element is enabled by calling [`isSelected`](https://webdriver.io/d
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toBeSelected()
await expect($('#elem')).toBeSelected()
```

### toBeChecked
Expand All @@ -423,8 +455,7 @@ Same as `toBeSelected`.
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toBeChecked()
await expect($('#elem')).toBeChecked()
```

### toHaveComputedLabel
Expand Down Expand Up @@ -502,8 +533,7 @@ Checks if element has a specific `id` attribute.
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toHaveId('elem')
await expect($('#elem')).toHaveId('elem')
```

### toHaveStyle
Expand All @@ -513,8 +543,7 @@ Checks if an element has specific `CSS` properties. By default, values must matc
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toHaveStyle({
await expect($('#elem')).toHaveStyle({
'font-family': 'Faktum',
'font-weight': '500',
'font-size': '12px',
Expand Down Expand Up @@ -549,10 +578,11 @@ In case there is a list of elements in the div below:
You can assert them using an array:

```js
const elem = await $$('ul > li')
await expect(elem).toHaveText(['Coffee', 'Tea', 'Milk'])
await expect($$('ul > li')).toHaveText(['Coffee', 'Tea', 'Milk'])
```

**Note:** Assertion with multiple elements will pass if the element text's matches any of the text in the arrays. Strict array matching is not yet supported.

### toHaveHTML

Checks if element has a specific text. Can also be called with an array as parameter in the case where the element can have different texts.
Expand Down Expand Up @@ -583,8 +613,7 @@ Checks if an element is within the viewport by calling [`isDisplayedInViewport`]
##### Usage

```js
const elem = await $('#elem')
await expect(elem).toBeDisplayedInViewport()
await expect($('#elem')).toBeDisplayedInViewport()
```

### toHaveChildren
Expand Down
42 changes: 42 additions & 0 deletions docs/MultipleElements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Multiple Elements Support

Matchers element array support (e.g., `$$()`):

- **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.
- An error is thrown if no elements are found (except with `toBeElementsArrayOfSize`).
- Options like `StringOptions` or `HTMLOptions` apply to the whole array; `NumberOptions` behaves like any expected provided value.
- The assertion passes only if **all** elements match.
- Using `.not` means all elements must **not** match.

**Note:** Strict Index-based matching does not apply to `toHaveText`, since an existing behavior was already in placed.

## Limitations
- Instead of `StringOptions` for a single expected value, use RegExp or asymmetric matchers.
- For `ignoreCase` use RegEx (`/MyExample/i`)
- For `containing` use Asymmetric Matchers (`expect.stringContaining('Example')`)
- Passing an array of "containing" values is deprecated and not supported outside `toHaveText`.

## 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:
```ts
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')` is $expectedText", function () {
expect($$('label')[index]).toHaveText(expectedText);
});
});
});
```
Loading