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.
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 |
message | string | user message to prepend before assertion error |
String Optionsβ
This options 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 |
containing | boolean | expect actual value to contain expected value, otherwise strict equal. |
asString | boolean | might be helpful to force converting property value to string |
Number Optionsβ
This options 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')
toHaveUrlContainingβ
Checks if browser is on a page URL that contains a value.
Usageβ
await browser.url('https://webdriver.io/')
await expect(browser).toHaveUrlContaining('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')
toHaveTitleContainingβ
Checks if website has a specific title that contains a value.
Usageβ
await browser.url('https://webdriver.io/')
await expect(browser).toHaveTitleContaining('WebdriverIO')
Element Matchersβ
toBeDisplayedβ
Calls isDisplayed
on given element.
Usageβ
const elem = await $('#someElem')
await expect(elem).toBeDisplayed()
toExistβ
Calls isExisting
on given element.
Usageβ
const elem = await $('#someElem')
await expect(elem).toExist()
toBePresentβ
Same as toExist
.
Usageβ
const elem = await $('#someElem')
await expect(elem).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')
toHaveAttrβ
Same as toHaveAttribute
.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveAttr('class', 'form-control')
toHaveAttributeContainingβ
Checks if an element has a certain attribute that contains a value.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveAttributeContaining('class', 'form')
toHaveAttrContainingβ
Same as toHaveAttributeContaining
.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveAttrContaining('class', 'form')
toHaveElementClassβ
Checks if an element has a certain class name.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveElementClass('form-control', { message: 'Not a form control!', })
toHaveElementClassContainingβ
Checks if an element has a certain class name that contains provided value.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveElementClassContaining('form')
toHaveElementPropertyβ
Checks if an element has a certain property.
Usageβ
const elem = await $('#elem')
await expect(elem).toHaveElementProperty('height', 23)
await expect(elem).not.toHaveElementProperty('height', 0)
toHaveValueβ
Checks if an input element has a certain value.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveValue('user', { ignoreCase: true })
toHaveValueContainingβ
Checks if an input element contains a certain value.
Usageβ
const myInput = await $('input')
await expect(myInput).toHaveValueContaining('us')
toBeClickableβ
Checks if an element can be clicked by calling isClickable
on the element.
Usageβ
const elem = await $('#elem')
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β
const elem = await $('#elem')
await expect(elem).toBeSelected()
toBeCheckedβ
Same as toBeSelected
.
Usageβ
const elem = await $('#elem')
await expect(elem).toBeChecked()
toHaveHrefβ
Checks if link element has a specific link target.
Usageβ
const link = await $('a')
await expect(link).toHaveHref('https://webdriver.io')
toHaveLinkβ
Same as toHaveHref
.
Usageβ
const link = await $('a')
await expect(link).toHaveLink('https://webdriver.io')
toHaveHrefContainingβ
Checks if link element contains a specific link target.
Usageβ
const link = await $('a')
await expect(link).toHaveHrefContaining('webdriver.io')
toHaveLinkContainingβ
Same as toHaveHrefContaining
.
Usageβ
const link = await $('a')
await expect(link).toHaveLinkContaining('webdriver.io')
toHaveIdβ
Checks if element has a specific id
attribute.
Usageβ
const elem = await $('#elem')
await expect(elem).toHaveId('elem')
toHaveTextβ
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.
Usageβ
await browser.url('https://webdriver.io/')
const elem = await $('.container')
await expect(elem).toHaveText('Next-gen browser and mobile automation test framework for Node.js')
await expect(elem).toHaveText(['Next-gen browser and mobile automation test framework for Node.js', 'Get Started'])
toHaveTextContainingβ
Checks if element contains a specific text. Can also be called with an array as parameter in the case where the element can have different texts.
Usageβ
await browser.url('https://webdriver.io/')
const elem = await $('.container')
await expect(elem).toHaveTextContaining('browser and mobile automation test framework')
await expect(elem).toHaveTextContaining(['browser and mobile automation test framework', 'Started'])
toBeDisplayedInViewportβ
Checks if an element is within the viewport by calling isDisplayedInViewport
on the element.
Usageβ
const elem = await $('#elem')
await expect(elem).toBeDisplayedInViewport()
toHaveChildrenβ
Checks amount of the fetched element's children by calling element.$('./*')
command.
Usageβ
const list = await $('ul')
await expect(list).toHaveChildren() // the list has at least one item
// same as
await expect(list).toHaveChildren({ gte: 1 })
await expect(list).toHaveChildren(3) // the list has 3 items
// same as
await expect(list).toHaveChildren({ eq: 3 })
toBeElementsArrayOfSizeβ
Checks amount of fetched elements using $$
command.
Usageβ
const listItems = await $$('ul>li')
await expect(listItems).toBeElementsArrayOfSize(5) // 5 items in the list
await expect(listItems).toBeElementsArrayOfSize({ lte: 10 })
// same as
assert.ok(listItems.length <= 10)
Network Matchersβ
toBeRequestedβ
Checks that mock was called
Usageβ
const mock = browser.mock('**/api/todo*')
await expect(mock).toBeRequested()
toBeRequestedTimesβ
Checks that mock was called for the expected amount of times
Usageβ
const mock = browser.mock('**/api/todo*')
await expect(mock).toBeRequestedTimes(2) // await expect(mock).toBeRequestedTimes({ eq: 2 })
await expect(mock).toBeRequestedTimes({ gte: 5, lte: 10 }) // request called at least 5 times but less than 11
toBeRequestedWithβ
Checks that mock was called according to the expected options.
Most of the options supports expect/jasmine partial matchers like expect.objectContaining
Usageβ
const mock = browser.mock('**/api/todo*', { method: 'POST' })
await expect(mock).toBeRequestedWith({
url: 'http://localhost:8080/api/todo', // [optional] string | function | custom matcher
method: 'POST', // [optional] string | array
statusCode: 200, // [optional] number | array
requestHeaders: { Authorization: 'foo' }, // [optional] object | function | custom matcher
responseHeaders: { Authorization: 'bar' }, // [optional] object | function | custom matcher
postData: { title: 'foo', description: 'bar' }, // [optional] object | function | custom matcher
response: { success: true }, // [optional] object | function | custom matcher
})
await expect(mock).toBeRequestedWith({
url: expect.stringMatching(/.*\/api\/.*/i),
method: ['POST', 'PUT'], // either POST or PUT
statusCode: [401, 403], // either 401 or 403
requestHeaders: headers => headers.Authorization.startsWith('Bearer '),
postData: expect.objectContaining({ released: true, title: expect.stringContaining('foobar') }),
response: r => Array.isArray(r) && r.data.items.length === 20
})
Using regular expressionsβ
You can also directly use regular expressions for all matchers that do text comparison.
Usageβ
await browser.url('https://webdriver.io/')
const elem = await $('.container')
await expect(elem).toHaveText(/node\.js/i)
await expect(elem).toHaveText([/node\.js/i, 'Get Started'])
await expect(elem).toHaveTextContaining([/node\.js/i, 'Started'])
await expect(browser).toHaveTitle(/webdriverio/i)
await expect(browser).toHaveUrl(/webdriver\.io/)
await expect(elem).toHaveElementClass(/Container/i)
Default Matchersβ
In addition to the expect-webdriverio
matchers you can use builtin Jest's expect assertions or expect/expectAsync for Jasmine.
TypeScriptβ
If you are using the WDIO Testrunner everything will be automatically setup. Just follow the setup guide from the docs. However if you run WebdriverIO with a different testrunner or in a simple Node.js script you will need to add expect-webdriverio
to types
in the tsconfig.json
.
"expect-webdriverio"
for everyone except of Jasmine/Jest users."expect-webdriverio/jasmine"
Jasmine"expect-webdriverio/jest"
Jest
JavaScript (VSCode)β
It's required to create jsconfig.json
in project root and refer to the type definitions to make autocompletion work in vanilla js.
{
"include": [
"**/*.js",
"**/*.json",
"node_modules/expect-webdriverio"
]
}
Adding your own matchersβ
Similar to how expect-webdriverio
extends Jasmine/Jest matchers it's possible to add custom matchers.
- Jasmine see custom matchers doc
- Everyone else see Jest's expect.extend
Custom matchers should be added in wdio before
hook
// wdio.conf.js
{
async before () {
const { addCustomMatchers } = await import('./myMatchers')
addCustomMatchers()
}
}
// myMatchers.js - Jest example
export function addCustomMatchers () {
if (global.expect.expect !== undefined) { // Temporary workaround. See https://github.com/webdriverio/expect-webdriverio/issues/835
global.expect = global.expect.expect;
}
expect.extend({
myMatcher (actual, expected) {
return { pass: actual === expected, message: () => 'some message' }
}
})
}