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 })
},
// ...
}
匹配器選項
每個匹配器都可以採用多個選項,讓您可以修改斷言
命令選項
名稱 | 類型 | 詳細資訊 |
---|---|---|
wait | number | 等待預期成功的時間(毫秒)。預設值:3000 |
interval | number | 嘗試之間的間隔。預設值:100 |
beforeAssertion | function | 在進行斷言之前要呼叫的函式 |
afterAssertion | function | 在進行斷言之後要呼叫的函式,其中包含斷言結果 |
message | string | 要附加在斷言錯誤之前的用戶訊息 |
字串選項
當斷言字串時,除了命令選項之外,還可以套用此選項。
名稱 | 類型 | 詳細資訊 |
---|---|---|
ignoreCase | boolean | 將 toLowerCase 套用至實際和預期的值 |
trim | boolean | 將 trim 套用至實際值 |
replace | Replacer | Replacer[] | 取代符合字串/RegExp 的實際值的部分。取代字串可以是字串或函式。 |
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')
您可以在 HTML 規格中找到所有 Unicode 參考資料。
注意:Unicode 不區分大小寫,因此 \u00a0
和 \u00A0
都可以運作。若要在瀏覽器中找到元素,請檢查並從 Unicode 中移除 u
,例如:div[data="Some\00a0Value"]
瀏覽器匹配器
toHaveUrl
檢查瀏覽器是否在特定頁面上。
用法
await browser.url('https://webdriverio.dev.org.tw/')
await expect(browser).toHaveUrl('https://webdriverio.dev.org.tw')
用法
await browser.url('https://webdriverio.dev.org.tw/')
await expect(browser).toHaveUrl(expect.stringContaining('webdriver'))
toHaveTitle
檢查網站是否有特定的標題。
用法
await browser.url('https://webdriverio.dev.org.tw/')
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.dev.org.tw/')
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.dev.org.tw/')
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.dev.org.tw/')
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.dev.org.tw/')
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.dev.org.tw')
await expect(link).toHaveHref(expect.stringContaining('webdriver.io'))
toHaveLink
與 toHaveHref
相同。
用法
const link = await $('a')
await expect(link).toHaveLink('https://webdriverio.dev.org.tw')
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.dev.org.tw/')
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.dev.org.tw/')
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.dev.org.tw/')
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
檢查 mock 是否被呼叫
用法
const mock = browser.mock('**/api/todo*')
await expect(mock).toBeRequested()
toBeRequestedTimes
檢查 mock 是否被呼叫了預期的次數
用法
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
檢查 mock 是否根據預期的選項被呼叫。
大多數選項都支援 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
檢查包含 Tab 標記的完整頁面螢幕截圖是否與基準快照匹配。
用法
await expect(browser).toMatchTabbablePageSnapshot('tabbable', 0, {
// options
})
預期結果預設為 0
,因此您可以將相同的斷言寫成
await expect(browser).toMatchTabbablePageSnapshot('tabbable', {
// options
})
或完全不傳入任何選項
await expect(browser).toMatchTabbablePageSnapshot('tabbable')
使用正規表示式
您也可以直接對所有執行文字比較匹配的匹配器使用正規表示式。
用法
await browser.url('https://webdriverio.dev.org.tw/')
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
。
"expect-webdriverio"
適用於除了 Jasmine/Jest 使用者之外的所有人。"expect-webdriverio/jasmine"
適用於 Jasmine"expect-webdriverio/jest"
適用於 Jest
JavaScript (VSCode)
需要在專案根目錄中建立 jsconfig.json
並參照類型定義,才能在原始 JavaScript 中啟用自動完成功能。
{
"include": [
"**/*.js",
"**/*.json",
"node_modules/expect-webdriverio"
]
}
加入您自己的匹配器
與 expect-webdriverio
擴展 Jasmine/Jest 匹配器的方式類似,您可以加入自訂匹配器。
- Jasmine 請參閱 自訂匹配器 文件
- 其他使用者請參閱 Jest 的 expect.extend
自訂匹配器應加入 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' }
}
})
}