斷言 API
Vitest 開箱即用提供多種 DOM 斷言,這些斷言源自於 @testing-library/jest-dom
函式庫,並增加了對定位器(locators)的支援和內建的重試功能。
TypeScript 支援
若您正在使用 TypeScript 或希望 expect
能夠提供正確的型別提示,請確保您已在某處引用了 @vitest/browser/context
。如果您從未從中匯入,您可以在 tsconfig.json
所涵蓋的任何檔案中添加一個 reference
註釋:
/// <reference types="@vitest/browser/context" />
瀏覽器中的測試由於其非同步特性,可能會出現不穩定的失敗情況。因此,即使條件延遲(例如,由於超時、網路請求或動畫效果),也需要一種方法來確保斷言能夠成功。為此,Vitest 開箱即用提供了可重試的斷言,透過 expect.poll
和 expect.element
API:
import { expect, test } from 'vitest';
import { page } from '@vitest/browser/context';
test('error banner is rendered', async () => {
triggerError();
// 這會建立一個定位器,當其任何方法被呼叫時,便會嘗試尋找元素。
// 此呼叫本身並不會檢查元素是否存在。
const banner = page.getByRole('alert', {
name: /error/i,
});
// Vitest 提供 `expect.element`,具有內建的重試功能
// 它會重複檢查元素是否存在於 DOM 中,以及 `element.textContent` 的內容是否等於 "Error!" 直到所有條件都滿足。
await expect.element(banner).toHaveTextContent('Error!');
});
我們建議在使用 page.getBy*
定位器時始終使用 expect.element
,以減少測試的脆弱性。請注意,expect.element
接受第二個選項:
interface ExpectPollOptions {
// 斷言重試的間隔時間(毫秒)
// 預設為 "expect.poll.interval" 配置選項
interval?: number;
// 斷言重試的超時時間(毫秒)
// 預設為 "expect.poll.timeout" 配置選項
timeout?: number;
// 斷言失敗時顯示的訊息
message?: string;
}
TIP
expect.element
是 expect.poll(() => element)
的簡寫,並且工作方式完全相同。
toHaveTextContent
和所有其他斷言仍然可以在一般的 expect
上使用,但沒有內建的重試機制:
// 如果 .textContent 不為 `'Error!'`,則會立即失敗
expect(banner).toHaveTextContent('Error!');
toBeDisabled
function toBeDisabled(): Promise<void>;
允許您檢查元素在使用者介面中是否處於禁用狀態。
如果元素是表單控制項,且其本身或其所屬的表單元素指定了 disabled
屬性,則匹配。
請注意,只有原生控制元素,例如 HTML button
、input
、select
、textarea
、option
、optgroup
,可以透過設定「disabled」屬性來禁用。「disabled」屬性在其他元素上會被忽略,除非該元素是自訂元素。
<button data-testid="button" type="submit" disabled>submit</button>
await expect.element(getByTestId('button')).toBeDisabled(); // ✅
await expect.element(getByTestId('button')).not.toBeDisabled(); // ❌
toBeEnabled
function toBeEnabled(): Promise<void>;
允許您檢查元素是否從使用者角度來看未被禁用。
其工作方式類似於 not.toBeDisabled()
。使用此匹配器可避免測試中的雙重否定。
<button data-testid="button" type="submit" disabled>submit</button>
await expect.element(getByTestId('button')).toBeEnabled(); // ✅
await expect.element(getByTestId('button')).not.toBeEnabled(); // ❌
toBeEmptyDOMElement
function toBeEmptyDOMElement(): Promise<void>;
這允許您斷言元素對使用者而言是否沒有可見內容。它會忽略註釋,但如果元素包含空白字元則會失敗。
<span data-testid="not-empty"><span data-testid="empty"></span></span>
<span data-testid="with-whitespace"> </span>
<span data-testid="with-comment"><!-- comment --></span>
await expect.element(getByTestId('empty')).toBeEmptyDOMElement();
await expect.element(getByTestId('not-empty')).not.toBeEmptyDOMElement();
await expect.element(getByTestId('with-whitespace')).not.toBeEmptyDOMElement();
toBeInTheDocument
function toBeInTheDocument(): Promise<void>;
斷言元素是否存在於文件中。
<svg data-testid="svg-element"></svg>
await expect.element(getByTestId('svg-element')).toBeInTheDocument();
await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument();
WARNING
此匹配器找不到脫離文件的元素。元素必須被添加到文件中,toBeInTheDocument
才能找到它。如果您需要在脫離文件的元素中搜尋,請使用:toContainElement
。
toBeInvalid
function toBeInvalid(): Promise<void>;
這允許您檢查元素目前是否處於無效狀態。
如果元素具有沒有值或值為 "true"
的 aria-invalid
屬性,或者如果 checkValidity()
的結果為 false
,則該元素無效。
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />
<form data-testid="valid-form">
<input />
</form>
<form data-testid="invalid-form">
<input required />
</form>
await expect.element(getByTestId('no-aria-invalid')).not.toBeInvalid();
await expect.element(getByTestId('aria-invalid')).toBeInvalid();
await expect.element(getByTestId('aria-invalid-value')).toBeInvalid();
await expect.element(getByTestId('aria-invalid-false')).not.toBeInvalid();
await expect.element(getByTestId('valid-form')).not.toBeInvalid();
await expect.element(getByTestId('invalid-form')).toBeInvalid();
toBeRequired
function toBeRequired(): Promise<void>;
這允許您檢查表單元素目前是否為必填項。
如果元素具有 required
或 aria-required="true"
屬性,則該元素為必填項。
<input data-testid="required-input" required />
<input data-testid="aria-required-input" aria-required="true" />
<input data-testid="conflicted-input" required aria-required="false" />
<input data-testid="aria-not-required-input" aria-required="false" />
<input data-testid="optional-input" />
<input data-testid="unsupported-type" type="image" required />
<select data-testid="select" required></select>
<textarea data-testid="textarea" required></textarea>
<div data-testid="supported-role" role="tree" required></div>
<div data-testid="supported-role-aria" role="tree" aria-required="true"></div>
await expect.element(getByTestId('required-input')).toBeRequired();
await expect.element(getByTestId('aria-required-input')).toBeRequired();
await expect.element(getByTestId('conflicted-input')).toBeRequired();
await expect.element(getByTestId('aria-not-required-input')).not.toBeRequired();
await expect.element(getByTestId('optional-input')).not.toBeRequired();
await expect.element(getByTestId('unsupported-type')).not.toBeRequired();
await expect.element(getByTestId('select')).toBeRequired();
await expect.element(getByTestId('textarea')).toBeRequired();
await expect.element(getByTestId('supported-role')).not.toBeRequired();
await expect.element(getByTestId('supported-role-aria')).toBeRequired();
toBeValid
function toBeValid(): Promise<void>;
這允許您檢查元素的值目前是否處於有效狀態。
如果元素沒有 aria-invalid
屬性 或其屬性值為 "false",則該元素有效。如果該元素是表單元素,checkValidity()
的結果也必須為 true
。
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />
<form data-testid="valid-form">
<input />
</form>
<form data-testid="invalid-form">
<input required />
</form>
await expect.element(getByTestId('no-aria-invalid')).toBeValid();
await expect.element(getByTestId('aria-invalid')).not.toBeValid();
await expect.element(getByTestId('aria-invalid-value')).not.toBeValid();
await expect.element(getByTestId('aria-invalid-false')).toBeValid();
await expect.element(getByTestId('valid-form')).toBeValid();
await expect.element(getByTestId('invalid-form')).not.toBeValid();
toBeVisible
function toBeVisible(): Promise<void>;
這允許您檢查元素目前是否對使用者可見。
當元素具有非零尺寸的邊界框(bounding box)且沒有 visibility:hidden
計算樣式(computed style)時,該元素被視為可見。
請注意,根據此定義:
- 尺寸為零的元素不被視為可見。
- 具有
display:none
的元素不被視為可見。 - 具有
opacity:0
的元素被視為可見。
若要檢查列表中至少一個元素是否可見,請使用 locator.first()
。
// 檢查特定元素是否可見。
await expect.element(page.getByText('Welcome')).toBeVisible();
// 檢查列表中至少一個項目是否可見。
await expect.element(page.getByTestId('todo-item').first()).toBeVisible();
// 檢查兩個元素中至少一個是否可見,可能兩個都可見。
await expect
.element(
page
.getByRole('button', { name: 'Sign in' })
.or(page.getByRole('button', { name: 'Sign up' }))
.first()
)
.toBeVisible();
toContainElement
function toContainElement(
element: HTMLElement | SVGElement | null
): Promise<void>;
這允許您斷言一個元素是否包含另一個元素作為其後代。
<span data-testid="ancestor"><span data-testid="descendant"></span></span>
const ancestor = getByTestId('ancestor');
const descendant = getByTestId('descendant');
const nonExistantElement = getByTestId('does-not-exist');
await expect.element(ancestor).toContainElement(descendant);
await expect.element(descendant).not.toContainElement(ancestor);
await expect.element(ancestor).not.toContainElement(nonExistantElement);
toContainHTML
function toContainHTML(htmlText: string): Promise<void>;
斷言一個表示 HTML 元素的字串是否包含在另一個元素中。該字串應包含有效的 HTML,而非任何不完整的 HTML。
<span data-testid="parent"><span data-testid="child"></span></span>
// 這些是有效用法
await expect
.element(getByTestId('parent'))
.toContainHTML('<span data-testid="child"></span>');
await expect
.element(getByTestId('parent'))
.toContainHTML('<span data-testid="child" />');
await expect.element(getByTestId('parent')).not.toContainHTML('<br />');
// 這些將不起作用
await expect
.element(getByTestId('parent'))
.toContainHTML('data-testid="child"');
await expect.element(getByTestId('parent')).toContainHTML('data-testid');
await expect.element(getByTestId('parent')).toContainHTML('</span>');
WARNING
您可能不需要使用此匹配器。我們鼓勵從使用者在瀏覽器中如何感知應用程式的角度進行測試。這就是為什麼不推薦針對特定的 DOM 結構進行測試。
當被測試的程式碼渲染了從外部來源獲取的 HTML,並且您希望驗證該 HTML 程式碼是否按預期使用時,此匹配器可能很有用。
它不應被用於檢查您控制的 DOM 結構。請改用 toContainElement
。
toHaveAccessibleDescription
function toHaveAccessibleDescription(
description?: string | RegExp
): Promise<void>;
這允許您斷言元素是否具有預期的可存取描述。
您可以傳遞預期可存取描述的確切字串,也可以透過傳遞正規表示式(regular expression),或使用 expect.stringContaining
或 expect.stringMatching
進行部分匹配。
<a
data-testid="link"
href="/"
aria-label="Home page"
title="A link to start over"
>Start</a
>
<a data-testid="extra-link" href="/about" aria-label="About page">About</a>
<img src="avatar.jpg" data-testid="avatar" alt="User profile pic" />
<img
src="logo.jpg"
data-testid="logo"
alt="Company logo"
aria-describedby="t1"
/>
<span id="t1" role="presentation">The logo of Our Company</span>
<img
src="logo.jpg"
data-testid="logo2"
alt="Company logo"
aria-description="The logo of Our Company"
/>
await expect.element(getByTestId('link')).toHaveAccessibleDescription();
await expect
.element(getByTestId('link'))
.toHaveAccessibleDescription('A link to start over');
await expect
.element(getByTestId('link'))
.not.toHaveAccessibleDescription('Home page');
await expect
.element(getByTestId('extra-link'))
.not.toHaveAccessibleDescription();
await expect.element(getByTestId('avatar')).not.toHaveAccessibleDescription();
await expect
.element(getByTestId('logo'))
.not.toHaveAccessibleDescription('Company logo');
await expect
.element(getByTestId('logo'))
.toHaveAccessibleDescription('The logo of Our Company');
await expect
.element(getByTestId('logo2'))
.toHaveAccessibleDescription('The logo of Our Company');
toHaveAccessibleErrorMessage
function toHaveAccessibleErrorMessage(message?: string | RegExp): Promise<void>;
這允許您斷言元素是否具有預期的可存取錯誤訊息。
您可以傳遞預期可存取錯誤訊息的確切字串。 或者,您可以透過傳遞正規表示式或使用 expect.stringContaining
或 expect.stringMatching
來進行部分配。
<input
aria-label="Has Error"
aria-invalid="true"
aria-errormessage="error-message"
/>
<div id="error-message" role="alert">This field is invalid</div>
<input aria-label="No Error Attributes" />
<input
aria-label="Not Invalid"
aria-invalid="false"
aria-errormessage="error-message"
/>
// 帶有有效錯誤訊息的輸入框
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage();
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage('This field is invalid');
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage(/invalid/i);
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.not.toHaveAccessibleErrorMessage('This field is absolutely correct!');
// 不帶有效錯誤訊息的輸入框
await expect
.element(getByRole('textbox', { name: 'No Error Attributes' }))
.not.toHaveAccessibleErrorMessage();
await expect
.element(getByRole('textbox', { name: 'Not Invalid' }))
.not.toHaveAccessibleErrorMessage();
toHaveAccessibleName
function toHaveAccessibleName(name?: string | RegExp): Promise<void>;
這允許您斷言元素是否具有預期的可存取名稱。例如,這對於斷言表單元素和按鈕是否被正確標記很有用。
您可以傳遞預期可存取名稱的確切字串,也可以透過傳遞正規表示式,或使用 expect.stringContaining
或 expect.stringMatching
進行部分匹配。
<img data-testid="img-alt" src="" alt="Test alt" />
<img data-testid="img-empty-alt" src="" alt="" />
<svg data-testid="svg-title"><title>Test title</title></svg>
<button data-testid="button-img-alt"><img src="" alt="Test" /></button>
<p><img data-testid="img-paragraph" src="" alt="" /> Test content</p>
<button data-testid="svg-button"><svg><title>Test</title></svg></p>
<div><svg data-testid="svg-without-title"></svg></div>
<input data-testid="input-title" title="test" />
await expect.element(getByTestId('img-alt')).toHaveAccessibleName('Test alt');
await expect.element(getByTestId('img-empty-alt')).not.toHaveAccessibleName();
await expect
.element(getByTestId('svg-title'))
.toHaveAccessibleName('Test title');
await expect.element(getByTestId('button-img-alt')).toHaveAccessibleName();
await expect.element(getByTestId('img-paragraph')).not.toHaveAccessibleName();
await expect.element(getByTestId('svg-button')).toHaveAccessibleName();
await expect
.element(getByTestId('svg-without-title'))
.not.toHaveAccessibleName();
await expect.element(getByTestId('input-title')).toHaveAccessibleName();
toHaveAttribute
function toHaveAttribute(attribute: string, value?: unknown): Promise<void>;
這允許您檢查給定元素是否具有某個屬性。您還可以選擇檢查該屬性是否具有特定的預期值,或使用 expect.stringContaining
或 expect.stringMatching
進行部分匹配。
<button data-testid="ok-button" type="submit" disabled>ok</button>
const button = getByTestId('ok-button');
await expect.element(button).toHaveAttribute('disabled');
await expect.element(button).toHaveAttribute('type', 'submit');
await expect.element(button).not.toHaveAttribute('type', 'button');
await expect
.element(button)
.toHaveAttribute('type', expect.stringContaining('sub'));
await expect
.element(button)
.toHaveAttribute('type', expect.not.stringContaining('but'));
toHaveClass
function toHaveClass(
...classNames: string[],
options?: { exact: boolean }
): Promise<void>;
function toHaveClass(...classNames: (string | RegExp)[]): Promise<void>;
這允許您檢查給定元素在其 class
屬性中是否包含某些類別。您必須提供至少一個類別,除非您斷言該元素不包含任何類別。
類別名稱列表可以包含字串和正規表示式。正規表示式會針對目標元素中的每個單獨類別進行匹配,而不會針對其完整的 class
屬性值進行整體匹配。
WARNING
請注意,當僅提供正規表示式時,您不能使用 exact: true
選項。
<button data-testid="delete-button" class="btn extra btn-danger">
Delete item
</button>
<button data-testid="no-classes">No Classes</button>
const deleteButton = getByTestId('delete-button');
const noClasses = getByTestId('no-classes');
await expect.element(deleteButton).toHaveClass('extra');
await expect.element(deleteButton).toHaveClass('btn-danger btn');
await expect.element(deleteButton).toHaveClass(/danger/, 'btn');
await expect.element(deleteButton).toHaveClass('btn-danger', 'btn');
await expect.element(deleteButton).not.toHaveClass('btn-link');
await expect.element(deleteButton).not.toHaveClass(/link/);
// ⚠️ 正規表示式匹配的是單個類別,而非整個 classList
await expect.element(deleteButton).not.toHaveClass(/btn extra/);
// 元素**精確地**具有一組類別(任何順序)
await expect.element(deleteButton).toHaveClass('btn-danger extra btn', {
exact: true,
});
// 如果它擁有的類別數量超出預期,則會失敗
await expect.element(deleteButton).not.toHaveClass('btn-danger extra', {
exact: true,
});
await expect.element(noClasses).not.toHaveClass();
toHaveFocus
function toHaveFocus(): Promise<void>;
這允許您斷言元素是否處於焦點狀態。
<div><input type="text" data-testid="element-to-focus" /></div>
const input = page.getByTestId('element-to-focus');
input.element().focus();
await expect.element(input).toHaveFocus();
input.element().blur();
await expect.element(input).not.toHaveFocus();
toHaveFormValues
function toHaveFormValues(
expectedValues: Record<string, unknown>
): Promise<void>;
這允許您檢查表單或欄位集是否包含每個給定名稱的表單控制項,並具有指定的值。
TIP
需要強調的是,此匹配器只能在 form 或 fieldset 元素上呼叫。
這使得它能夠利用 form
和 fieldset
中的 .elements
屬性,以可靠地獲取其中的所有表單控制項。
這也避免了使用者提供包含多個 form
的容器,進而混淆不相關甚至可能相互衝突的表單控制項。
此匹配器抽象了根據表單控制項類型獲取其值的具體方式。例如,<input>
元素具有 value
屬性,但 <select>
元素沒有。以下是所有涵蓋的情況:
<input type="number">
元素會將值作為數字返回,而非字串。<input type="checkbox">
元素:- 如果只有一個具有給定
name
屬性的元素,則會將其視為布林值(boolean),如果核取方塊(checkbox)被選中則返回true
,如果未選中則返回false
。 - 如果有多個具有相同
name
屬性的核取方塊,則它們會被集體視為單個表單控制項,該控制項會將值作為**陣列(array)**返回,其中包含集合中所有選定核取方塊的值。
- 如果只有一個具有給定
<input type="radio">
元素會全部按name
屬性分組,且此類組會被視為單個表單控制項。此表單控制項會將值作為**字串(string)**返回,該字串對應於組中選定單選按鈕(radio button)的value
屬性。<input type="text">
元素會將值作為字串返回。這也適用於具有任何其他可能未在上述不同規則中明確涵蓋的type
屬性的<input>
元素(例如search
、email
、date
、password
、hidden
等)。- 不帶
multiple
屬性的<select>
元素會將值作為字串返回,該字串對應於選定option
的value
屬性,如果沒有選定選項則為undefined
。 <select multiple>
元素會將值作為陣列返回,其中包含所有 選定選項 的值。<textarea>
元素會將其值作為字串返回。該值對應於其節點內容。
上述規則使得,例如,從使用單個選擇控制項切換到使用一組單選按鈕變得容易。或者從多選控制項切換到使用一組核取方塊。此匹配器用於比較的最終表單值集將會是相同的。
<form data-testid="login-form">
<input type="text" name="username" value="jane.doe" />
<input type="password" name="password" value="12345678" />
<input type="checkbox" name="rememberMe" checked />
<button type="submit">Sign in</button>
</form>
await expect.element(getByTestId('login-form')).toHaveFormValues({
username: 'jane.doe',
rememberMe: true,
});
toHaveStyle
function toHaveStyle(css: string | Partial<CSSStyleDeclaration>): Promise<void>;
這允許您檢查特定元素是否應用了某些具有特定值的 CSS 屬性。它僅在元素應用了所有預期屬性時才匹配,而不僅僅是其中一些。
<button
data-testid="delete-button"
style="display: none; background-color: red"
>
Delete item
</button>
const button = getByTestId('delete-button');
await expect.element(button).toHaveStyle('display: none');
await expect.element(button).toHaveStyle({ display: 'none' });
await expect.element(button).toHaveStyle(`
background-color: red;
display: none;
`);
await expect.element(button).toHaveStyle({
backgroundColor: 'red',
display: 'none',
});
await expect.element(button).not.toHaveStyle(`
background-color: blue;
display: none;
`);
await expect.element(button).not.toHaveStyle({
backgroundColor: 'blue',
display: 'none',
});
這也適用於透過類別名稱應用於元素的規則,這些規則在文件中目前活動的樣式表中定義。CSS 優先級的常規規則適用。
toHaveTextContent
function toHaveTextContent(
text: string | RegExp,
options?: { normalizeWhitespace: boolean }
): Promise<void>;
這允許您檢查給定節點是否包含文字內容。這支援元素,也支援文字節點和片段。
當傳遞 string
參數時,它將對節點內容執行部分且區分大小寫的匹配。
若要執行不區分大小寫的匹配,您可以使用帶有 /i
修飾符的正規表示式(RegExp)。
如果您想匹配整個內容,您可以使用正規表示式來完成。
<span data-testid="text-content">Text Content</span>
const element = getByTestId('text-content');
await expect.element(element).toHaveTextContent('Content');
// 用於匹配整個內容
await expect.element(element).toHaveTextContent(/^Text Content$/);
// 用於不區分大小寫的匹配
await expect.element(element).toHaveTextContent(/content$/i);
await expect.element(element).not.toHaveTextContent('content');
toHaveValue
function toHaveValue(value: string | string[] | number | null): Promise<void>;
這允許您檢查給定的表單元素是否具有指定的值。 它接受 <input>
、<select>
和 <textarea>
元素,但 <input type="checkbox">
和 <input type="radio">
除外,它們只能使用 toBeChecked
或 toHaveFormValues
進行有效匹配。
它還接受角色為 meter
、progressbar
、slider
或 spinbutton
的元素,並檢查其 aria-valuenow
屬性(作為數字)。
對於所有其他表單元素,值會使用與 toHaveFormValues
相同的演算法進行匹配。
<input type="text" value="text" data-testid="input-text" />
<input type="number" value="5" data-testid="input-number" />
<input type="text" data-testid="input-empty" />
<select multiple data-testid="select-number">
<option value="first">First Value</option>
<option value="second" selected>Second Value</option>
<option value="third" selected>Third Value</option>
</select>
const textInput = getByTestId('input-text');
const numberInput = getByTestId('input-number');
const emptyInput = getByTestId('input-empty');
const selectInput = getByTestId('select-number');
await expect.element(textInput).toHaveValue('text');
await expect.element(numberInput).toHaveValue(5);
await expect.element(emptyInput).not.toHaveValue();
await expect.element(selectInput).toHaveValue(['second', 'third']);
toHaveDisplayValue
function toHaveDisplayValue(
value: string | RegExp | (string | RegExp)[]
): Promise<void>;
這允許您檢查給定的表單元素是否具有指定的顯示值(即終端使用者將看到的值)。它接受 <input>
、<select>
和 <textarea>
元素,但 <input type="checkbox">
和 <input type="radio">
除外,它們只能使用 toBeChecked
或 toHaveFormValues
進行有效匹配。
<label for="input-example">First name</label>
<input type="text" id="input-example" value="Luca" />
<label for="textarea-example">Description</label>
<textarea id="textarea-example">An example description here.</textarea>
<label for="single-select-example">Fruit</label>
<select id="single-select-example">
<option value="">Select a fruit...</option>
<option value="banana">Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado">Avocado</option>
</select>
<label for="multiple-select-example">Fruits</label>
<select id="multiple-select-example" multiple>
<option value="">Select a fruit...</option>
<option value="banana" selected>Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado" selected>Avocado</option>
</select>
const input = page.getByLabelText('First name');
const textarea = page.getByLabelText('Description');
const selectSingle = page.getByLabelText('Fruit');
const selectMultiple = page.getByLabelText('Fruits');
await expect.element(input).toHaveDisplayValue('Luca');
await expect.element(input).toHaveDisplayValue(/Luc/);
await expect
.element(textarea)
.toHaveDisplayValue('An example description here.');
await expect.element(textarea).toHaveDisplayValue(/example/);
await expect.element(selectSingle).toHaveDisplayValue('Select a fruit...');
await expect.element(selectSingle).toHaveDisplayValue(/Select/);
await expect.element(selectMultiple).toHaveDisplayValue([/Avocado/, 'Banana']);
toBeChecked
function toBeChecked(): Promise<void>;
這允許您檢查給定元素是否被選中。它接受類型為 checkbox
或 radio
的 input
元素,以及 role
為 checkbox
、radio
或 switch
且 aria-checked
屬性為 "true"
或 "false"
的元素。
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
role="checkbox"
aria-checked="false"
data-testid="aria-checkbox-unchecked"
/>
<input type="radio" checked value="foo" data-testid="input-radio-checked" />
<input type="radio" value="foo" data-testid="input-radio-unchecked" />
<div role="radio" aria-checked="true" data-testid="aria-radio-checked" />
<div role="radio" aria-checked="false" data-testid="aria-radio-unchecked" />
<div role="switch" aria-checked="true" data-testid="aria-switch-checked" />
<div role="switch" aria-checked="false" data-testid="aria-switch-unchecked" />
const inputCheckboxChecked = getByTestId('input-checkbox-checked');
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked');
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked');
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked');
await expect.element(inputCheckboxChecked).toBeChecked();
await expect.element(inputCheckboxUnchecked).not.toBeChecked();
await expect.element(ariaCheckboxChecked).toBeChecked();
await expect.element(ariaCheckboxUnchecked).not.toBeChecked();
const inputRadioChecked = getByTestId('input-radio-checked');
const inputRadioUnchecked = getByTestId('input-radio-unchecked');
const ariaRadioChecked = getByTestId('aria-radio-checked');
const ariaRadioUnchecked = getByTestId('aria-radio-unchecked');
await expect.element(inputRadioChecked).toBeChecked();
await expect.element(inputRadioUnchecked).not.toBeChecked();
await expect.element(ariaRadioChecked).toBeChecked();
await expect.element(ariaRadioUnchecked).not.toBeChecked();
const ariaSwitchChecked = getByTestId('aria-switch-checked');
const ariaSwitchUnchecked = getByTestId('aria-switch-unchecked');
await expect.element(ariaSwitchChecked).toBeChecked();
await expect.element(ariaSwitchUnchecked).not.toBeChecked();
toBePartiallyChecked
function toBePartiallyChecked(): Promise<void>;
這允許您檢查給定元素是否處於部分選中狀態。它接受類型為 checkbox
的 input
元素,以及 role
為 checkbox
且 aria-checked="mixed"
的元素,或者 indeterminate
設定為 true
的類型為 checkbox
的 input
元素。
<input type="checkbox" aria-checked="mixed" data-testid="aria-checkbox-mixed" />
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
role="checkbox"
aria-checked="false"
data-testid="aria-checkbox-unchecked"
/>
<input type="checkbox" data-testid="input-checkbox-indeterminate" />
const ariaCheckboxMixed = getByTestId('aria-checkbox-mixed');
const inputCheckboxChecked = getByTestId('input-checkbox-checked');
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked');
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked');
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked');
const inputCheckboxIndeterminate = getByTestId('input-checkbox-indeterminate');
await expect.element(ariaCheckboxMixed).toBePartiallyChecked();
await expect.element(inputCheckboxChecked).not.toBePartiallyChecked();
await expect.element(inputCheckboxUnchecked).not.toBePartiallyChecked();
await expect.element(ariaCheckboxChecked).not.toBePartiallyChecked();
await expect.element(ariaCheckboxUnchecked).not.toBePartiallyChecked();
inputCheckboxIndeterminate.element().indeterminate = true;
await expect.element(inputCheckboxIndeterminate).toBePartiallyChecked();
toHaveRole
function toHaveRole(role: ARIARole): Promise<void>;
這允許您斷言元素是否具有預期的 角色。
這在您已經透過角色本身以外的某些查詢存取元素,並希望對其可存取性進行額外斷言的情況下很有用。
該角色可以匹配顯式角色(透過 role
屬性),也可以透過 隱式 ARIA 語義 匹配隱式角色。
<button data-testid="button">Continue</button>
<div role="button" data-testid="button-explicit">Continue</button>
<button role="switch button" data-testid="button-explicit-multiple">Continue</button>
<a href="/about" data-testid="link">About</a>
<a data-testid="link-invalid">Invalid link<a/>
await expect.element(getByTestId('button')).toHaveRole('button');
await expect.element(getByTestId('button-explicit')).toHaveRole('button');
await expect
.element(getByTestId('button-explicit-multiple'))
.toHaveRole('button');
await expect
.element(getByTestId('button-explicit-multiple'))
.toHaveRole('switch');
await expect.element(getByTestId('link')).toHaveRole('link');
await expect.element(getByTestId('link-invalid')).not.toHaveRole('link');
await expect.element(getByTestId('link-invalid')).toHaveRole('generic');
WARNING
角色是透過字串相等進行字面匹配,不繼承 ARIA 角色層次結構。因此,查詢像 checkbox
這樣的父類別角色將不會包括像 switch
這樣的子類別角色元素。
另請注意,與 testing-library
不同,Vitest 會忽略所有自訂角色,只保留第一個有效角色,這遵循 Playwright 的行為:
<div data-testid="switch" role="switch alert"></div>;
await expect.element(getByTestId('switch')).toHaveRole('switch'); // ✅
await expect.element(getByTestId('switch')).toHaveRole('alert'); // ❌
toHaveSelection
function toHaveSelection(selection?: string): Promise<void>;
這允許斷言元素是否具有 文字選取範圍(selection)。
這對於檢查元素中是否有文字或部分文字被選取很有用。該元素可以是文字輸入欄位(text input)、文字區域(textarea),或任何其他包含文字的元素,例如段落(paragraph)、span 元素、div 元素等。
WARNING
預期的選取範圍是一個字串,它不允許檢查選取範圍的索引(index)。
<div>
<input type="text" value="text selected text" data-testid="text" />
<textarea data-testid="textarea">text selected text</textarea>
<p data-testid="prev">prev</p>
<p data-testid="parent">
text <span data-testid="child">selected</span> text
</p>
<p data-testid="next">next</p>
</div>
getByTestId('text').element().setSelectionRange(5, 13);
await expect.element(getByTestId('text')).toHaveSelection('selected');
getByTestId('textarea').element().setSelectionRange(0, 5);
await expect.element('textarea').toHaveSelection('text ');
const selection = document.getSelection();
const range = document.createRange();
selection.removeAllRanges();
selection.empty();
selection.addRange(range);
// 子元素的選取範圍也適用於父元素
range.selectNodeContents(getByTestId('child').element());
await expect.element(getByTestId('child')).toHaveSelection('selected');
await expect.element(getByTestId('parent')).toHaveSelection('selected');
// 選取範圍適用於 prev all、子元素之前的父元素文字以及子元素的部分內容。
range.setStart(getByTestId('prev').element(), 0);
range.setEnd(getByTestId('child').element().childNodes[0], 3);
await expect.element(queryByTestId('prev')).toHaveSelection('prev');
await expect.element(queryByTestId('child')).toHaveSelection('sel');
await expect.element(queryByTestId('parent')).toHaveSelection('text sel');
await expect.element(queryByTestId('next')).not.toHaveSelection();
// 選取範圍適用於子元素的部分內容、子元素之後的父元素文字以及 next 元素的部分內容。
range.setStart(getByTestId('child').element().childNodes[0], 3);
range.setEnd(getByTestId('next').element().childNodes[0], 2);
await expect.element(queryByTestId('child')).toHaveSelection('ected');
await expect.element(queryByTestId('parent')).toHaveSelection('ected text');
await expect.element(queryByTestId('prev')).not.toHaveSelection();
await expect.element(queryByTestId('next')).toHaveSelection('ne');