Expect
При написании тестов часто необходимо проверять, что значения соответствуют определенным условиям. expect
предоставляет доступ к ряду "матчеров", которые позволяют проверять различные вещи в объектах browser
, element
или mock
.
Параметры по умолчанию
Эти параметры по умолчанию связаны с опциями waitforTimeout
и waitforInterval
, установленными в конфигурации.
Устанавливайте параметры ниже только в том случае, если вы хотите установить специальные тайм-ауты для ваших проверок.
{
wait: 2000, // мс ожидания успешного выполнения проверки
interval: 100, // интервал между попытками
}
Если вы хотите установить другие значения тайм-аутов и интервалов, задайте эти параметры следующим образом:
// wdio.conf.js
import { setOptions } from 'expect-webdriverio'
export const config = {
// ...
before () {
setOptions({ wait: 5000 })
},
// ...
}
Параметры матчеров
Каждый матчер может принимать несколько параметров, которые позволяют модифицировать проверку:
Параметры команды
Имя | Тип | Описание |
---|---|---|
wait | number | время в мс для ожидания успешной проверки. По умолчанию: 3000 |
interval | number | интервал между попытками. По умолчанию: 100 |
beforeAssertion | function | функция, которая будет вызвана перед проверкой |
afterAssertion | function | функция, которая будет вызвана после проверки и содержит результаты проверки |
message | string | пользовательское сообщение, которое будет добавлено перед сообщением об ошибке проверки |
Параметры для строк
Эти параметры могут применяться дополнительно к параметрам команды при проверке строк.
Имя | Тип | Описание |
---|---|---|
ignoreCase | boolean | применить toLowerCase к фактическому и ожидаемому значениям |
trim | boolean | применить trim к фактическому значению |
replace | Replacer | Replacer[] | заменить части фактического значения, которые соответствуют строке/RegExp. Replacer может быть строкой или функцией |
containing | boolean | ожидание, что фактическое значение содержит ожидаемое значение, в противном случае строгое равенство |
asString | boolean | может быть полезно для принудительного преобразования значения свойства в строку |
atStart | boolean | ожидание, что фактическое значение начинается с ожидаемого значения |
atEnd | boolean | ожидание, что фактическое значение заканчивается ожидаемым значением |
atIndex | number | ожидание, что фактическое значение имеет ожидаемое значение по указанному индексу |
Параметры для чисел
Эти параметры могут применяться дополнительно к параметрам команды при проверке чисел.
Имя | Тип | Описание |
---|---|---|
eq | number | равно |
lte | number | меньше или равно |
gte | number | больше или равно |
Обработка HTML-сущностей
HTML-сущность — это фрагмент текста ("строка"), который начинается с амперсанда (&
) и заканчивается точкой с запятой (;
). Сущности часто используются для отображения зарезервированных символов (которые иначе были бы интерпретированы как HTML-код) и невидимых символов (таких как неразрывные пробелы, например,
).
Для поиска или взаимодействия с таким элементом используйте Unicode-эквивалент сущности. Например:
<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')
Все ссылки на Unicode можно найти в спецификации HTML.
Примечание: Unicode не чувствителен к регистру, поэтому \u00a0
и \u00A0
работают одинаково. Чтобы найти элемент в инспекторе браузера, удалите u
из Unicode, например: div[data="Some\00a0Value"]
Матчеры для браузера
toHaveUrl
Проверяет, находится ли браузер на определенной странице.
Использование
await browser.url('https://webdriver.io/')
await expect(browser).toHaveUrl('https://webdriver.io')
Использование
await browser.url('https://webdriver.io/')
await expect(browser).toHaveUrl(expect.stringContaining('webdriver'))
toHaveTitle
Проверяет, имеет ли веб-сайт определенный заголовок.
Использование
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
Проверяет, содержит ли буфер обмена браузера определенный текст.
Использование
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'))
Матчеры для элементов
toBeDisplayed
Вызывает isDisplayed
для указанного элемента.
Использование
const elem = await $('#someElem')
await expect(elem).toBeDisplayed()
toExist
Вызывает isExisting
для указанного элемента.
Использование
const elem = await $('#someElem')
await expect(elem).toExist()
toBePresent
То же, что и toExist
.
Использование
const elem = await $('#someElem')
await expect(elem).toBePresent()
toBeExisting
То же, что и toExist
.
Использование
const elem = await $('#someElem')
await expect(elem).toBeExisting()
toBeFocused
Проверяет, находится ли элемент в фокусе. Эта проверка работает только в веб-контексте.
Использование
const elem = await $('#someElem')
await expect(elem).toBeFocused()
toHaveAttribute
Проверяет, имеет ли элемент определенный атрибут с конкретным значением.
Использование
const myInput = await $('input')
await expect(myInput).toHaveAttribute('class', 'form-control')
await expect(myInput).toHaveAttribute('class', expect.stringContaining('control'))
toHaveAttr
То же, что и toHaveAttribute
.
Использование
const myInput = await $('input')
await expect(myInput).toHaveAttr('class', 'form-control')
await expect(myInput).toHaveAttr('class', expect.stringContaining('control'))
toHaveElementClass
Проверяет, имеет ли элемент определенное имя класса. Также может вызываться с массивом в качестве параметра, когда элемент может иметь несколько имен классов.
Использование
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
Проверяет, имеет ли элемент определенное свойство.
Использование
const elem = await $('#elem')
await expect(elem).toHaveElementProperty('height', 23)
await expect(elem).not.toHaveElementProperty('height', 0)
toHaveValue
Проверяет, имеет ли элемент ввода определенное значение.
Использование
const myInput = await $('input')
await expect(myInput).toHaveValue('admin-user', { ignoreCase: true })
await expect(myInput).toHaveValue(expect.stringContaining('user'), { ignoreCase: true })
toBeClickable
Проверяет, можно ли кликнуть по элементу, вызывая isClickable
для элемента.
Использование
const elem = await $('#elem')
await expect(elem).toBeClickable()
toBeDisabled
Проверяет, отключен ли элемент, вызывая isEnabled
для элемента.
Использование
const elem = await $('#elem')
await expect(elem).toBeDisabled()
// то же самое, что и
await expect(elem).not.toBeEnabled()
toBeEnabled
Проверяет, включен ли элемент, вызывая isEnabled
для элемента.
Использование
const elem = await $('#elem')
await expect(elem).toBeEnabled()
// то же самое, что и
await expect(elem).not.toBeDisabled()
toBeSelected
Проверяет, выбран ли элемент, вызывая isSelected
для элемента.
Использование
const elem = await $('#elem')
await expect(elem).toBeSelected()
toBeChecked
То же, что и toBeSelected
.
Использование
const elem = await $('#elem')
await expect(elem).toBeChecked()
toHaveComputedLabel
Проверяет, имеет ли элемент определенную вычисленную метку WAI-ARIA. Также может вызываться с массивом в качестве параметра, если элемент может иметь разные метки.
Использование
await browser.url('https://webdriver.io/')
const elem = await $('a[href="https://github.com/webdriverio/webdriverio"]')
await expect(elem).toHaveComputedLabel('GitHub repository')
await expect(elem).toHaveComputedLabel(expect.stringContaining('repository'))
Использование
await browser.url('https://webdriver.io/')
const elem = await $('a[href="https://github.com/webdriverio/webdriverio"]')
await expect(elem).toHaveComputedLabel(['GitHub repository', 'Private repository'])
await expect(elem).toHaveComputedLabel([expect.stringContaining('GitHub'), expect.stringContaining('Private')])
toHaveComputedRole
Проверяет, имеет ли элемент определенную вычисленную роль WAI-ARIA. Также может вызываться с массивом в качестве параметра, если элемент может иметь разные метки.
Использование
await browser.url('https://webdriver.io/')
const elem = await $('[aria-label="Skip to main content"]')
await expect(elem).toHaveComputedRole('region')
await expect(elem).toHaveComputedRole(expect.stringContaining('ion'))
Использование
await browser.url('https://webdriver.io/')
const elem = await $('[aria-label="Skip to main content"]')
await expect(elem).toHaveComputedRole(['region', 'section'])
await expect(elem).toHaveComputedRole([expect.stringContaining('reg'), expect.stringContaining('sec')])
toHaveHref
Проверяет, имеет ли элемент ссылки определенную целевую ссылку.
Использование
const link = await $('a')
await expect(link).toHaveHref('https://webdriver.io')
await expect(link).toHaveHref(expect.stringContaining('webdriver.io'))
toHaveLink
То же, что и toHaveHref
.
Использование
const link = await $('a')
await expect(link).toHaveLink('https://webdriver.io')
await expect(link).toHaveLink(expect.stringContaining('webdriver.io'))
toHaveId
Проверяет, имеет ли элемент определенный атрибут id
.
Использование
const elem = await $('#elem')
await expect(elem).toHaveId('elem')
toHaveText
Проверяет, имеет ли элемент определенный текст. Также может вызываться с массивом в качестве параметра, если элемент может иметь разные тексты.
Использование
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(expect.stringContaining('test framework for Node.js'))
await expect(elem).toHaveText(['Next-gen browser and mobile automation test framework for Node.js', 'Get Started'])
await expect(elem).toHaveText([expect.stringContaining('test framework for Node.js'), expect.stringContaining('Started')])
В случае, если в div есть список элементов:
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
Вы можете проверить их, используя массив:
const elem = await $$('ul > li')
await expect(elem).toHaveText(['Coffee', 'Tea', 'Milk'])
toHaveHTML
Проверяет, имеет ли элемент определенный HTML. Также может вызываться с массивом в качестве параметра, если элемент может иметь разные тексты.
Использование
await browser.url('https://webdriver.io/')
const elem = await $('.hero__subtitle')
await expect(elem).toHaveHTML('<p class="hero__subtitle">Next-gen browser and mobile automation test framework for Node.js</p>')
await expect(elem).toHaveHTML(expect.stringContaining('Next-gen browser and mobile automation test framework for Node.js'))
await expect(elem).toHaveHTML('Next-gen browser and mobile automation test framework for Node.js', { includeSelectorTag: false })
Использование
await browser.url('https://webdriver.io/')
const elem = await $('.hero__subtitle')
await expect(elem).toHaveHTML(['Next-gen browser and mobile automation test framework for Node.js', 'Get Started'], { includeSelectorTag: false })
await expect(elem).toHaveHTML([expect.stringContaining('automation test framework for Node.js'), expect.stringContaining('Started')], { includeSelectorTag: false })
toBeDisplayedInViewport
Проверяет, находится ли элемент в области просмотра, вызывая isDisplayedInViewport
для элемента.
Использование
const elem = await $('#elem')
await expect(elem).toBeDisplayedInViewport()
toHaveChildren
Проверяет количество дочерних элементов путем вызова команды element.$('./*')
.
Использование
const list = await $('ul')
await expect(list).toHaveChildren() // список имеет хотя бы один элемент
// то же самое, что и
await expect(list).toHaveChildren({ gte: 1 })
await expect(list).toHaveChildren(3) // список имеет 3 элемента
// то же самое, что и
await expect(list).toHaveChildren({ eq: 3 })
toHaveWidth
Проверяет, имеет ли элемент определенную ширину.
Использование
await browser.url('http://github.com')
const logo = await $('.octicon-mark-github')
await expect(logo).toHaveWidth(32)
toHaveHeight
Проверяет, имеет ли элемент определенную высоту.
Использование
await browser.url('http://github.com')
const logo = await $('.octicon-mark-github')
await expect(logo).toHaveHeight(32)
toHaveSize
Проверяет, имеет ли элемент определенный размер.
Использование
await browser.url('http://github.com')
const logo = await $('.octicon-mark-github')
await expect(logo).toHaveSize({ width: 32, height: 32 })
toBeElementsArrayOfSize
Проверяет количество извлеченных элементов с помощью команды $$
.
Примечание: Этот матчер обновит переданный массив последними элементами, если проверка пройдет успешно. Однако, если вы переназначили переменную, вам нужно будет снова получить элементы.
Использование
const listItems = await $$('ul>li')
await expect(listItems).toBeElementsArrayOfSize(5) // 5 элементов в списке
await expect(listItems).toBeElementsArrayOfSize({ lte: 10 })
// то же самое, что и
assert.ok(listItems.length <= 10)
Матчеры для сети
toBeRequested
Проверяет, что мок был вызван
Использование
const mock = browser.mock('**/api/todo*')
await expect(mock).toBeRequested()
toBeRequestedTimes
Проверяет, что мок был вызван ожидаемое количество раз
Использование
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 }) // запрос вызван не менее 5 раз, но не более 10
toBeRequestedWith
Проверяет, что мок был вызван в соответствии с ожидаемыми параметрами.
Большинство параметров поддерживает частичные матчеры expect/jasmine, такие как expect.objectContaining
Использование
const mock = browser.mock('**/api/todo*', { method: 'POST' })
await expect(mock).toBeRequestedWith({
url: 'http://localhost:8080/api/todo', // [опционально] string | function | custom matcher
method: 'POST', // [опционально] string | array
statusCode: 200, // [опционально] number | array
requestHeaders: { Authorization: 'foo' }, // [опционально] object | function | custom matcher
responseHeaders: { Authorization: 'bar' }, // [опционально] object | function | custom matcher
postData: { title: 'foo', description: 'bar' }, // [опционально] object | function | custom matcher
response: { success: true }, // [опционально] object | function | custom matcher
})
await expect(mock).toBeRequestedWith({
url: expect.stringMatching(/.*\/api\/.*/i),
method: ['POST', 'PUT'], // либо POST, либо PUT
statusCode: [401, 403], // либо 401, либо 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
})
Матчер для снимков
WebdriverIO поддерживает как базовые тесты снимков, так и тестирование снимков DOM.
toMatchSnapshot
Проверяет, соответствует ли произвольный объект определенному значению. Если вы передаете WebdriverIO.Element
, он автоматически сделает снимок его состояния outerHTML
.
Использование
// снимок произвольных объектов (здесь не нужен "await")
expect({ foo: 'bar' }).toMatchSnapshot()
// снимок `outerHTML` WebdriverIO.Element (снимок DOM, требуется "await")
await expect($('elem')).toMatchSnapshot()
// снимок результата команды элемента
await expect($('elem').getCSSProperty('background-color')).toMatchSnapshot()
toMatchInlineSnapshot
Аналогично вы можете использовать toMatchInlineSnapshot()
для хранения снимка внутри тестового файла. Например:
await expect($('img')).toMatchInlineSnapshot()
Вместо создания файла снимка WebdriverIO напрямую изменит тестовый файл, чтобы обновить снимок в виде строки:
await expect($('img')).toMatchInlineSnapshot(`"<img src="/public/apple-touch-icon-precomposed.png">"`)
Матчеры визуальных снимков
Следующие матчеры реализованы как часть плагина @wdio/visual-service
и доступны только при настройке сервиса. Убедитесь, что вы следуете инструкциям по настройке соответствующим образом.
toMatchElementSnapshot
Проверяет, соответствует ли данный элемент снимку из базовой линии.
Использование
await expect($('.hero__title-logo')).toMatchElementSnapshot('wdioLogo', 0, {
// опции
})
Ожидаемый результат по умолчанию равен 0
, поэтому вы можете записать ту же проверку следующим образом:
await expect($('.hero__title-logo')).toMatchElementSnapshot('wdioLogo', {
// опции
})
или вообще не передавать никаких опций:
await expect($('.hero__title-logo')).toMatchElementSnapshot()
toMatchScreenSnapshot
Проверяет, соответствует ли текущий экран снимку из базовой линии.
Использование
await expect(browser).toMatchScreenSnapshot('partialPage', 0, {
// опции
})
Ожидаемый результат по умолчанию равен 0
, поэтому вы можете записать ту же проверку следующим образом:
await expect(browser).toMatchScreenSnapshot('partialPage', {
// опции
})
или вообще не передавать никаких опций:
await expect(browser).toMatchScreenSnapshot('partialPage')
toMatchFullPageSnapshot
Проверяет, соответствует ли снимок всей страницы снимку из базовой линии.
Использование
await expect(browser).toMatchFullPageSnapshot('fullPage', 0, {
// опции
})
Ожидаемый результат по умолчанию равен 0
, поэтому вы можете записать ту же проверку следующим образом:
await expect(browser).toMatchFullPageSnapshot('fullPage', {
// опции
})
или вообще не передавать никаких опций:
await expect(browser).toMatchFullPageSnapshot('fullPage')
toMatchTabbablePageSnapshot
Проверяет, соответствует ли снимок всей страницы с табами снимку из базовой линии.
Использование
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0, {
// опции
})
Ожидаемый результат по умолчанию равен 0
, поэтому вы можете записать ту же проверку следующим образом:
await expect(browser).toMatchTabbablePageSnapshot('tabbable', {
// опции
})
или вообще не передавать никаких опций:
await expect(browser).toMatchTabbablePageSnapshot('tabbable')
Использование регулярных выражений
Вы также можете напрямую использовать регулярные выражения для всех матчеров, которые выполняют сравнение текста.
Использование
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(browser).toHaveTitle(/webdriverio/i)
await expect(browser).toHaveUrl(/webdriver\.io/)
await expect(elem).toHaveElementClass(/Container/i)
Стандартные матчеры
В дополнение к матчерам expect-webdriverio
вы можете использовать встроенные проверки Jest expect или expect/expectAsync для Jasmine.
Асимметричные матчеры
WebdriverIO поддерживает использование асимметричных матчеров везде, где вы сравниваете текстовые значения, например:
await expect(browser).toHaveTitle(expect.stringContaining('some title'))
или
await expect(browser).toHaveTitle(expect.not.stringContaining('some title'))
TypeScript
Если вы используете WDIO Testrunner, все будет настроено автоматически. Просто следуйте руководству по настройке из документации. Однако, если вы запускаете WebdriverIO с другим тестраннером или в простом скрипте Node.js, вам нужно будет добавить expect-webdriverio
в поле types
в tsconfig.json
.
"expect-webdriverio"
для всех, кроме пользователей Jasmine/Jest."expect-webdriverio/jasmine"
для Jasmine"expect-webdriverio/jest"
для Jest
JavaScript (VSCode)
Для работы автодополнения в обычном js необходимо создать jsconfig.json
в корне проекта и указать в нем определения типов.
{
"include": [
"**/*.js",
"**/*.json",
"node_modules/expect-webdriverio"
]
}
Добавление собственных матчеров
Подобно тому, как expect-webdriverio
расширяет матчеры Jasmine/Jest, вы можете добавить свои собственные матчеры.
- Для Jasmine см. документацию по пользовательским матчерам
- Для всех остальных см. Jest's expect.extend
Пользовательские матчеры следует добавлять в хуке wdio before
// wdio.conf.js
{
async before () {
const { addCustomMatchers } = await import('./myMatchers')
addCustomMatchers()
}
}
// myMatchers.js - пример для Jest
export function addCustomMatchers () {
if (global.expect.expect !== undefined) { // Временное решение. См. 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' }
}
})
}