Expect
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 scenario is coincidental and may break or change without notice 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.
Usage
// Mocha example
it('product page smoke', async () => {
// These won't throw immediately if they fail
await expect.soft(await $('h1').getText()).toEqual('Basketball Shoes');
await expect.soft(await $('#price').getText()).toMatch(/€\d+/);
// Also work with basic matcher
const h1Text = await $('h1').getText()
expect.soft(h1Text).toEqual('Basketball Shoes');
// Regular assertions still throw immediately
await expect(await $('.add-to-cart').isClickable()).toBe(true);
});
// At the end of the test, all soft assertion failures
// will be reported together with their details
Soft Assertion API
expect.soft()
Creates a soft assertion that collects failures instead of immediately throwing errors.
await expect.soft(actual).toBeDisplayed();
await expect.soft(actual).not.toHaveText('Wrong text');
expect.getSoftFailures()
Get all collected soft assertion failures for the current test.
const failures = expect.getSoftFailures();
console.log(`There are ${failures.length} soft assertion failures`);
expect.assertSoftFailures()
Manually assert all collected soft failures. This will throw an aggregated error if any soft assertions have failed.
// Manually throw if any soft assertions have failed
expect.assertSoftFailures();
expect.clearSoftFailures()
Clear all collected soft assertion failures for the current test.
// Clear all collected failures
expect.clearSoftFailures();
Integration with Test Frameworks
The soft assertions feature integrates with WebdriverIO's test runner automatically. By default, it will report all soft assertion failures at the end of each test (Mocha) or step (Cucumber).
To use with WebdriverIO, add the SoftAssertionService to your services list:
// wdio.conf.js
import { SoftAssertionService } from 'expect-webdriverio'
export const config = {
// ...
services: [
// ...other services
[SoftAssertionService, {}]
],
// ...
}
Configuration Options
The SoftAssertionService can be configured with options to control its behavior:
// wdio.conf.js
import { SoftAssertionService } from 'expect-webdriverio'
export const config = {
// ...
services: [
// ...other services
[SoftAssertionService, {
// Disable automatic assertion at the end of tests (default: true)
autoAssertOnTestEnd: false
}]
],
// ...
}
autoAssertOnTestEnd
- Type:
boolean - Default:
true
When set to true (default), the service will automatically assert all soft assertions at the end of each test and throw an aggregated error if any failures are found. When set to false, you must manually call expect.assertSoftFailures() to verify soft assertions.
This is useful if you want full control over when soft assertions are verified or if you want to handle soft assertion failures in a custom way.
Known limitations
The soft assertions service is not supported under Jasmine (e.g. @wdio/jasmine-framework) using the global import because Jasmine is already designed to provide similar behavior out of the box.
Default Options
These default options below are connected to the waitforTimeout and waitforInterval options set in the config.
Only set the options below if you want to wait for specific timeouts for your assertions.
{
wait: 2000, // ms to wait for expectation to succeed
interval: 100, // interval between attempts
}
If you like to pick different timeouts and intervals, set these options like this:
// wdio.conf.js
import { setOptions } from 'expect-webdriverio'
export const config = {
// ...
before () {
setOptions({ wait: 5000 })
},
// ...
}
Matcher Options
Every matcher can take several options that allows you to modify the assertion:
Command Options
| Name | Type | Details |
|---|---|---|
wait | number | time in ms to wait for expectation to succeed. Default: 3000 |
interval | number | interval between attempts. Default: 100 |
beforeAssertion | function | function to be called before assertion is made |
afterAssertion | function | function to be called after assertion is made containing assertion results |
message | string | user message to prepend before assertion error |
String Options
This option can be applied in addition to the command options when strings are being asserted.
| Name | Type | Details |
|---|---|---|
ignoreCase | boolean | apply toLowerCase to both actual and expected values |
trim | boolean | apply trim to actual value |
replace | Replacer | Replacer[] | replace parts of the actual value that match the string/RegExp. The replacer can be a string or a function. |
containing | boolean | expect actual value to contain expected value, otherwise strict equal. |
asString | boolean | might be helpful to force converting property value to string |
atStart | boolean | expect actual value to start with the expected value |
atEnd | boolean | expect actual value to end with the expected value |
atIndex | number | expect actual value to have the expected value at the given index |
Number Options
This option can be applied in addition to the command options when numbers are being asserted.
| Name | Type | Details |
|---|---|---|
eq | number | equals |
lte | number | less then equals |
gte | number | greater than or equals |
Handling HTML Entities
An HTML entity is a piece of text (“string”) that begins with an ampersand (&) and ends with a semicolon (;). Entities are frequently used to display reserved characters (which would otherwise be interpreted as HTML code), and invisible characters (like non-breaking spaces, e.g. ).
To find or interact with such element use unicode equivalent of the entity. e.g.:
<div data="Some Value">Some Text</div>
const myElem = await $('div[data="Some\u00a0Value"]')
await expect(myElem).toHaveAttribute('data', 'div[Some\u00a0Value')
await expect(myElem).toHaveText('Some\u00a0Text')
You can find all unicode references in the HTML spec.
Note: unicode is case-insensitive hence both \u00a0 and \u00A0 works. To find element in browser inspect, remove u from unicode e.g.: div[data="Some\00a0Value"]
Browser Matchers
toHaveUrl
Checks if browser is on a specific page.
Usage
await browser.url('https://webdriver.io/')
await expect(browser).toHaveUrl('https://webdriver.io')
Usage
await browser.url('https://webdriver.io/')
await expect(browser).toHaveUrl(expect.stringContaining('webdriver'))
toHaveTitle
Checks if website has a specific title.
Usage
await browser.url('https://webdriver.io/')
await expect(browser).toHaveTitle('WebdriverIO · Next-gen browser and mobile automation test framework for Node.js')
await expect(browser).toHaveTitle(expect.stringContaining('WebdriverIO'))
toHaveClipboardText
Checks if the browser has a specific text stored in its clipboard.
Usage
import { Key } from 'webdriverio'
await browser.keys([Key.Ctrl, 'a'])
await browser.keys([Key.Ctrl, 'c'])
await expect(browser).toHaveClipboardText('some clipboard text')
await expect(browser).toHaveClipboardText(expect.stringContaining('clipboard text'))
toHaveLocalStorageItem
Checks if browser has a specific item in localStorage with an optional value.
Usage
await browser.url('https://webdriver.io/')
// Check if localStorage item exists
await expect(browser).toHaveLocalStorageItem('existingKey')
// Check localStorage item with exact value
await expect(browser).toHaveLocalStorageItem('someLocalStorageKey', 'someLocalStorageValue')
// Check with case insensitive
await expect(browser).toHaveLocalStorageItem('key', 'uppercase', { ignoreCase: true })
// Check with trim
await expect(browser).toHaveLocalStorageItem('key', 'value', { trim: true })
// Check with containing
await expect(browser).toHaveLocalStorageItem('key', 'long', { containing: true })
// Check with regex
await expect(browser).toHaveLocalStorageItem('userId', /^user_\d+$/)
Element Matchers
toBeDisplayed
Calls isDisplayed on given element.
Usage
await expect($('#someElem')).toBeDisplayed()
toExist
Calls isExisting on given element.
Usage
await expect($('#someElem')).toExist()
toBePresent
Same as toExist.
Usage
await expect($('#someElem')).toBePresent()
toBeExisting
Same as toExist.
Usage
const elem = await $('#someElem')
await expect(elem).toBeExisting()
toBeFocused
Checks if element has focus. This assertion only works in a web context.
Usage
const elem = await $('#someElem')
await expect(elem).toBeFocused()
toHaveAttribute
Checks if an element has a certain attribute with a specific value.
Usage
const myInput = await $('input')
await expect(myInput).toHaveAttribute('class', 'form-control')
await expect(myInput).toHaveAttribute('class', expect.stringContaining('control'))
Checks if an element has a specific attribute.
Usage
const myInput = await $('input')
await expect(myInput).toHaveAttribute('class')
// With options
await expect(myInput).toHaveAttribute('class', expect.anything(), { wait: 1000 })
Checks if an element does not have the specified attribute.
Usage
const myInput = await $('input')
await expect(myInput).not.toHaveAttribute('class')
// With options
await expect(myInput).not.toHaveAttribute('class', expect.anything(), { wait: 1000 })
toHaveElementClass
Checks if an element has a single class name. Can also be called with an array as a parameter when the element can have multiple class names.
Usage
const myInput = await $('input')
await expect(myInput).toHaveElementClass('form-control', { message: 'Not a form control!' })
await expect(myInput).toHaveElementClass(['form-control' , 'w-full'], { message: 'not full width' })
await expect(myInput).toHaveElementClass(expect.stringContaining('form'), { message: 'Not a form control!' })
toHaveElementProperty
Checks if an element has a certain property and value
Usage
const elem = await $('#elem')
await expect(elem).toHaveElementProperty('height', 23)
await expect(elem).not.toHaveElementProperty('height', 0)
Checks if an element has a certain property.
Usage
const elem = await $('#elem')
await expect(elem).toHaveElementProperty('height')
// With options
await expect(elem).toHaveElementProperty('height', expect.anything(), { wait : 1 })
// Does not have height property
await expect(elem).not.toHaveElementProperty('height')
// With options
await expect(elem).not.toHaveElementProperty('height', expect.anything(), { wait : 1 })
toHaveValue
Checks if an input element has a certain value.
Usage
const myInput = await $('input')
await expect(myInput).toHaveValue('admin-user', { ignoreCase: true })
await expect(myInput).toHaveValue(expect.stringContaining('user'), { ignoreCase: true })
toBeClickable
Checks if an element can be clicked by calling isClickable on the element.
Usage
await expect($('#elem')).toBeClickable()
toBeDisabled
Checks if an element is disabled by calling isEnabled on the element.
Usage
const elem = await $('#elem')
await expect(elem).toBeDisabled()
// same as
await expect(elem).not.toBeEnabled()
toBeEnabled
Checks if an element is enabled by calling isEnabled on the element.
Usage
const elem = await $('#elem')
await expect(elem).toBeEnabled()
// same as
await expect(elem).not.toBeDisabled()
toBeSelected
Checks if an element is enabled by calling isSelected on the element.
Usage
await expect($('#elem')).toBeSelected()
toBeChecked
Same as toBeSelected.
Usage
await expect($('#elem')).toBeChecked()
toHaveComputedLabel
Checks if element has a specific computed WAI-ARIA label. Can also be called with an array as parameter in the case where the element can have different labels.