Expect
在编写测试时,您通常需要检查值是否满足某些条件。expect
让您可以访问许多“匹配器”,这些匹配器允许您验证browser
、element
或mock
对象上的不同内容。
默认选项
以下默认选项与配置中设置的waitforTimeout
和waitforInterval
选项相关。
仅当您希望为断言等待特定超时时,才设置以下选项。
{
wait: 2000, // ms to wait for expectation to succeed
interval: 100, // interval between attempts
}
如果您希望选择不同的超时和间隔,请按如下方式设置这些选项
// wdio.conf.js
import { setOptions } from 'expect-webdriverio'
export const config = {
// ...
before () {
setOptions({ wait: 5000 })
},
// ...
}
匹配器选项
每个匹配器都可以接受多个选项,允许您修改断言
命令选项
名称 | 类型 | 详情 |
---|---|---|
等待 | 数字 | 等待期望成功的毫秒数。默认值:3000 |
间隔 | 数字 | 尝试之间的间隔。默认值:100 |
beforeAssertion | 函数 | 在进行断言之前要调用的函数 |
afterAssertion | 函数 | 在进行断言后要调用的函数,其中包含断言结果 |
消息 | 字符串 | 要在断言错误之前添加的用户消息 |
字符串选项
断言字符串时,除了命令选项外,还可以应用此选项。
名称 | 类型 | 详情 |
---|---|---|
忽略大小写 | 布尔值 | 对实际值和预期值都应用toLowerCase |
修剪 | 布尔值 | 对实际值应用trim |
替换 | 替换器 | 替换器[] | 替换与字符串/正则表达式匹配的实际值的某些部分。替换器可以是字符串或函数。 |
包含 | 布尔值 | 期望实际值包含预期值,否则严格相等。 |
asString | 布尔值 | 可能有助于强制将属性值转换为字符串 |
atStart | 布尔值 | 期望实际值以预期值开头 |
atEnd | 布尔值 | 期望实际值以预期值结尾 |
atIndex | 数字 | 期望实际值在给定索引处具有预期值 |
数字选项
断言数字时,除了命令选项外,还可以应用此选项。
名称 | 类型 | 详情 |
---|---|---|
eq | 数字 | 等于 |
lte | 数字 | 小于等于 |
gte | 数字 | 大于或等于 |
处理 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')
您可以在HTML 规范中找到所有 Unicode 引用。
注意:Unicode 不区分大小写,因此\u00a0
和\u00A0
都适用。要在浏览器检查中查找元素,请从 Unicode 中删除u
,例如:div[data="Some\00a0Value"]
浏览器匹配器
toHaveUrl
检查浏览器是否在特定页面上。
用法
await browser.url('https://webdriverio.node.org.cn/')
await expect(browser).toHaveUrl('https://webdriverio.node.org.cn')
用法
await browser.url('https://webdriverio.node.org.cn/')
await expect(browser).toHaveUrl(expect.stringContaining('webdriver'))
toHaveTitle
检查网站是否具有特定标题。
用法
await browser.url('https://webdriverio.node.org.cn/')
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
检查元素是否具有焦点。此断言仅在 Web 上下文中有效。
用法
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()
// same as
await expect(elem).not.toBeEnabled()
toBeEnabled
通过在元素上调用isEnabled
来检查元素是否已启用。
用法
const elem = await $('#elem')
await expect(elem).toBeEnabled()
// same as
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://webdriverio.node.org.cn/')
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://webdriverio.node.org.cn/')
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://webdriverio.node.org.cn/')
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://webdriverio.node.org.cn/')
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://webdriverio.node.org.cn')
await expect(link).toHaveHref(expect.stringContaining('webdriver.io'))
toHaveLink
与 toHaveHref
相同。
用法
const link = await $('a')
await expect(link).toHaveLink('https://webdriverio.node.org.cn')
await expect(link).toHaveLink(expect.stringContaining('webdriver.io'))
toHaveId
检查元素是否具有特定的 id
属性。
用法
const elem = await $('#elem')
await expect(elem).toHaveId('elem')
toHaveText
检查元素是否具有特定的文本。如果元素可以具有不同的文本,也可以使用数组作为参数调用。
用法
await browser.url('https://webdriverio.node.org.cn/')
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
检查元素是否具有特定的文本。如果元素可以具有不同的文本,也可以使用数组作为参数调用。
用法
await browser.url('https://webdriverio.node.org.cn/')
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://webdriverio.node.org.cn/')
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() // 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 })
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 items in the list
await expect(listItems).toBeElementsArrayOfSize({ lte: 10 })
// same as
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 }) // request called at least 5 times but less than 11
toBeRequestedWith
检查模拟是否根据预期的选项被调用。
大多数选项支持 expect/jasmine 部分匹配器,例如 expect.objectContaining
用法
const mock = browser.mock('**/api/todo*', { method: 'POST' })
await expect(mock).toBeRequestedWith({
url: 'https://127.0.0.1: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
})
快照匹配器
WebdriverIO 支持基本的快照测试以及 DOM 快照测试。
toMatchSnapshot
检查任何任意对象是否与某个值匹配。如果您传入一个 WebdriverIO.Element
,它将自动对其 outerHTML
状态进行快照。
用法
// snapshot arbitrary objects (no "await" needed here)
expect({ foo: 'bar' }).toMatchSnapshot()
// snapshot `outerHTML` of WebdriverIO.Element (DOM snapshot, requires "await")
await expect($('elem')).toMatchSnapshot()
// snapshot result of element command
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, {
// options
})
预期结果默认为 0
,因此您可以将相同的断言写为
await expect($('.hero__title-logo')).toMatchElementSnapshot('wdioLogo', {
// options
})
或者根本不传递任何选项
await expect($('.hero__title-logo')).toMatchElementSnapshot()
toMatchScreenSnapshot
检查当前屏幕是否与基线的快照匹配。
用法
await expect(browser).toMatchScreenSnapshot('partialPage', 0, {
// options
})
预期结果默认为 0
,因此您可以将相同的断言写为
await expect(browser).toMatchScreenSnapshot('partialPage', {
// options
})
或者根本不传递任何选项
await expect(browser).toMatchScreenSnapshot('partialPage')
toMatchFullPageSnapshot
检查完整页面截图是否与基线的快照匹配。
用法
await expect(browser).toMatchFullPageSnapshot('fullPage', 0, {
// options
})
预期结果默认为 0
,因此您可以将相同的断言写为
await expect(browser).toMatchFullPageSnapshot('fullPage', {
// options
})
或者根本不传递任何选项
await expect(browser).toMatchFullPageSnapshot('fullPage')
toMatchTabbablePageSnapshot
检查包含选项卡标记的完整页面截图是否与基线的快照匹配。
用法
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0, {
// options
})
预期结果默认为 0
,因此您可以将相同的断言写为
await expect(browser).toMatchTabbablePageSnapshot('tabbable', {
// options
})
或者根本不传递任何选项
await expect(browser).toMatchTabbablePageSnapshot('tabbable')
使用正则表达式
您还可以直接对所有进行文本比较的匹配器使用正则表达式。
用法
await browser.url('https://webdriverio.node.org.cn/')
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 断言或 Jasmine 的 expect/expectAsync。
非对称匹配器
WebdriverIO 支持在您比较文本值时使用非对称匹配器,例如
await expect(browser).toHaveTitle(expect.stringContaining('some title'))
或
await expect(browser).toHaveTitle(expect.not.stringContaining('some title'))
TypeScript
如果您使用的是 WDIO 测试运行器,一切都会自动设置。只需按照文档中的 设置指南 操作即可。但是,如果您使用不同的测试运行器或在简单的 Node.js 脚本中运行 WebdriverIO,则需要在 tsconfig.json
中的 types
中添加 expect-webdriverio
。
- 除 Jasmine/Jest 用户外,所有人都使用
"expect-webdriverio"
。 - Jasmine 使用
"expect-webdriverio/jasmine"
- Jest 使用
"expect-webdriverio/jest"
JavaScript (VSCode)
需要在项目根目录中创建 jsconfig.json
并引用类型定义以使自动完成功能在普通 js 中工作。
{
"include": [
"**/*.js",
"**/*.json",
"node_modules/expect-webdriverio"
]
}
添加您自己的匹配器
与 expect-webdriverio
如何扩展 Jasmine/Jest 匹配器类似,可以添加自定义匹配器。
- 有关 Jasmine,请参阅 自定义匹配器 文档
- 其他所有人请参阅 Jest 的 expect.extend
自定义匹配器应在 wdio 的 before
钩子中添加
// 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' }
}
})
}