跳至主要内容

Expect

在编写测试时,您通常需要检查值是否满足某些条件。expect 让您可以访问许多“匹配器”,这些匹配器允许您验证browserelementmock对象上的不同内容。

默认选项

以下默认选项与配置中设置的waitforTimeoutwaitforInterval选项相关。

仅当您希望为断言等待特定超时时,才设置以下选项。

{
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&nbsp;Value">Some&nbsp;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'))

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 匹配器类似,可以添加自定义匹配器。

自定义匹配器应在 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' }
}
})
}

欢迎!我如何提供帮助?

WebdriverIO AI Copilot