Skip to content
Vitest 3
Main Navigation 指南 & API配置浏览器模式高级 API
3.2.0
2.1.9
1.6.1
0.34.6

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

主题

Sidebar Navigation

简介

为什么选择浏览器模式

浏览器模式

配置

浏览器配置

配置 Playwright

配置 WebdriverIO

API

Context API

交互 API

定位器

断言 API

命令 API

指南

多实例设置

配置参考

测试 API 参考

高级 API

页面导航

断言 API ​

Vitest 开箱即用地提供了大量 DOM 断言,这些断言源自 @testing-library/jest-dom 库,并增强了对定位器和内置重试功能的支持。

TypeScript 支持

如果你正在使用 TypeScript 或希望在 expect 中获得正确的类型提示,请确保你已在某处引用 @vitest/browser/context。如果你从未从那里导入,可以在 tsconfig.json 覆盖的任何文件中添加 reference 注释:

ts
/// <reference types="@vitest/browser/context" />

浏览器中的测试由于其异步特性,可能会出现不一致的失败。因此,即使条件因超时、网络请求或动画等原因延迟,也需要有方法确保断言能够成功。为此,Vitest 通过 expect.poll 和 expect.element API 开箱即用地提供了可重试的断言:

ts
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 接受第二个参数:

ts
interface ExpectPollOptions {
  // 断言重试的间隔,单位为毫秒。
  // 默认为 "expect.poll.interval" 配置选项。
  interval?: number;
  // 断言重试的超时时间,单位为毫秒。
  // 默认为 "expect.poll.timeout" 配置选项。
  timeout?: number;
  // 断言失败时打印的消息。
  message?: string;
}

TIP

expect.element 是 expect.poll(() => element) 的简写,工作方式完全相同。

toHaveTextContent 和所有其他断言仍然可以在常规 expect 上使用,但没有内置的重试机制:

ts
// 如果 .textContent 不等于 'Error!',则会立即失败。
expect(banner).toHaveTextContent('Error!');

toBeDisabled ​

ts
function toBeDisabled(): Promise<void>;

允许你检查元素在用户看来是否被禁用。

如果元素是表单控件,并且其上指定了 disabled 属性,或者元素是具有 disabled 属性的表单元素的后代,则匹配。

请注意,只有 HTML button、input、select、textarea、option、optgroup 等原生控件元素可以通过设置 disabled 属性来禁用。disabled 属性在其他元素上会被忽略,除非它是自定义元素。

html
<button data-testid="button" type="submit" disabled>submit</button>
ts
await expect.element(getByTestId('button')).toBeDisabled(); // ✅
await expect.element(getByTestId('button')).not.toBeDisabled(); // ❌

toBeEnabled ​

ts
function toBeEnabled(): Promise<void>;

允许你检查元素是否未从用户的角度被禁用。

功能类似于 not.toBeDisabled()。使用此匹配器可避免测试中的双重否定表达。

html
<button data-testid="button" type="submit" disabled>submit</button>
ts
await expect.element(getByTestId('button')).toBeEnabled(); // ✅
await expect.element(getByTestId('button')).not.toBeEnabled(); // ❌

toBeEmptyDOMElement ​

ts
function toBeEmptyDOMElement(): Promise<void>;

这允许你断言元素对用户来说没有可见内容。它会忽略注释,但若元素包含空格则会失败。

html
<span data-testid="not-empty"><span data-testid="empty"></span></span>
<span data-testid="with-whitespace"> </span>
<span data-testid="with-comment"><!-- comment --></span>
ts
await expect.element(getByTestId('empty')).toBeEmptyDOMElement();
await expect.element(getByTestId('not-empty')).not.toBeEmptyDOMElement();
await expect.element(getByTestId('with-whitespace')).not.toBeEmptyDOMElement();

toBeInTheDocument ​

ts
function toBeInTheDocument(): Promise<void>;

断言元素是否存在于文档中。

html
<svg data-testid="svg-element"></svg>
ts
await expect.element(getByTestId('svg-element')).toBeInTheDocument();
await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument();

WARNING

此匹配器不会查找分离的元素。元素必须添加到文档中才能被 toBeInTheDocument 找到。如果你希望在分离的元素中搜索,请使用 toContainElement。

toBeInvalid ​

ts
function toBeInvalid(): Promise<void>;

这允许你检查元素当前是否处于无效状态。

如果元素具有没有值或值为 "true" 的 aria-invalid 属性,或者 checkValidity() 的结果为 false,则该元素无效。

html
<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>
ts
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 ​

ts
function toBeRequired(): Promise<void>;

这允许你检查表单元素当前是否为必填。

如果元素具有 required 或 aria-required="true" 属性,则为必填。

html
<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>
ts
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 ​

ts
function toBeValid(): Promise<void>;

这允许你检查元素的值当前是否处于有效状态。

如果元素没有 aria-invalid 属性 或属性值为 "false",则该元素有效。如果它是表单元素,checkValidity() 的结果也必须是 true。

html
<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>
ts
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 ​

ts
function toBeVisible(): Promise<void>;

这允许你检查元素当前是否对用户可见。

当元素具有非空边界框且没有 visibility:hidden 计算样式时,它被视为可见。

注意,根据此定义:

  • 零大小的元素不被视为可见。
  • 具有 display:none 的元素不被视为可见。
  • 具有 opacity:0 的元素被视为可见。

要检查列表中至少有一个元素是可见的,请使用 locator.first()。

ts
// 特定元素可见。
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 ​

ts
function toContainElement(
  element: HTMLElement | SVGElement | null
): Promise<void>;

这允许你断言元素是否包含另一个元素作为其子孙元素。

html
<span data-testid="ancestor"><span data-testid="descendant"></span></span>
ts
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 ​

ts
function toContainHTML(htmlText: string): Promise<void>;

断言一个表示 HTML 元素的字符串是否包含在另一个元素中。字符串应包含完整有效的 HTML,而不是任何不完整的 HTML。

html
<span data-testid="parent"><span data-testid="child"></span></span>
ts
// 这些是有效用法
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 ​

ts
function toHaveAccessibleDescription(
  description?: string | RegExp
): Promise<void>;

这允许你断言元素拥有预期的可访问描述。

你可以传入预期可访问描述的精确字符串,也可以通过传入正则表达式,或使用 expect.stringContaining 或 expect.stringMatching 来进行部分匹配。

html
<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"
/>
ts
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 ​

ts
function toHaveAccessibleErrorMessage(message?: string | RegExp): Promise<void>;

这允许你断言元素拥有预期的可访问错误消息。

你可以传入预期可访问错误消息的精确字符串。 或者,你可以通过传入正则表达式,或使用 expect.stringContaining 或 expect.stringMatching 来执行部分匹配。

html
<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"
/>
ts
// 具有有效错误消息的输入
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 ​

ts
function toHaveAccessibleName(name?: string | RegExp): Promise<void>;

这允许你断言元素拥有预期的可访问名称。例如,这对于断言表单元素和按钮是否正确标记很有用。

你可以传入预期可访问名称的精确字符串,也可以通过传入正则表达式,或使用expect.stringContaining 或 expect.stringMatching 来进行部分匹配。

html
<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" />
javascript
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 ​

ts
function toHaveAttribute(attribute: string, value?: unknown): Promise<void>;

这允许你检查给定元素是否具有某个属性。你还可以选择检查该属性是否具有特定的预期值,或使用 expect.stringContaining 或 expect.stringMatching 来进行部分匹配。

html
<button data-testid="ok-button" type="submit" disabled>ok</button>
ts
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 ​

ts
function toHaveClass(
  ...classNames: string[],
  options?: { exact: boolean }
): Promise<void>;
function toHaveClass(...classNames: (string | RegExp)[]): Promise<void>;

这允许你检查给定元素在其 class 属性中是否具有某些类。你必须至少提供一个类,除非你断言元素不包含任何类。

类名列表可以包含字符串和正则表达式。正则表达式会针对目标元素中的每个单独类进行匹配,而不是针对其完整的 class 属性值进行整体匹配。

WARNING

请注意,当只提供正则表达式时,不能使用 exact: true 选项。

html
<button data-testid="delete-button" class="btn extra btn-danger">
  Delete item
</button>
<button data-testid="no-classes">No Classes</button>
ts
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 ​

ts
function toHaveFocus(): Promise<void>;

这允许你断言元素是否拥有焦点。

html
<div><input type="text" data-testid="element-to-focus" /></div>
ts
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 ​

ts
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 属性的复选框,则将其视为布尔值:如果复选框被选中,则返回 true;如果未选中,则返回 false。
    • 如果有多个具有相同 name 属性的复选框,则它们都被集体视为单个表单控件,该控件将值作为数组返回,其中包含集合中所有选定复选框的值。
  • <input type="radio"> 元素都按 name 属性分组,并且此类组被视为单个表单控件。此表单控件将值作为字符串返回,对应于组中选定单选按钮的 value 属性。
  • <input type="text"> 元素将值作为字符串返回。这也适用于具有任何其他可能未在上述不同规则中明确涵盖的 type 属性的 <input> 元素(例如 search、email、date、password、hidden 等)。
  • 不带 multiple 属性的 <select> 元素将值作为字符串返回,对应于选定 option 的 value 属性,如果没有选定选项,则返回 undefined。
  • <select multiple> 元素将值作为数组返回,其中包含所有 选定选项 的值。
  • <textarea> 元素将其值作为字符串返回。该值对应于它们的节点内容。

上述规则使得,例如,从使用单个选择控件切换到使用一组单选按钮变得容易。或者从多选控件切换到使用一组复选框。此匹配器用于比较的最终表单值集将是相同的。

html
<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>
ts
await expect.element(getByTestId('login-form')).toHaveFormValues({
  username: 'jane.doe',
  rememberMe: true,
});

toHaveStyle ​

ts
function toHaveStyle(css: string | Partial<CSSStyleDeclaration>): Promise<void>;

这允许你检查某个元素是否设置了某些特定的 CSS 属性和特定值。它仅在元素设置了所有预期属性时才匹配,而不仅仅是其中一些。

html
<button
  data-testid="delete-button"
  style="display: none; background-color: red"
>
  Delete item
</button>
ts
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 ​

ts
function toHaveTextContent(
  text: string | RegExp,
  options?: { normalizeWhitespace: boolean }
): Promise<void>;

这允许你检查给定节点是否拥有文本内容。这支持元素,也支持文本节点和片段。

当传入 string 参数时,它将对节点内容进行部分区分大小写的匹配。

要进行不区分大小写的匹配,你可以使用带有 /i 修饰符的 RegExp。

如果你想匹配整个内容,你可以使用 RegExp 实现。

html
<span data-testid="text-content">Text Content</span>
ts
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 ​

ts
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 相同的算法匹配。

html
<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>
ts
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 ​

typescript
function toHaveDisplayValue(
  value: string | RegExp | (string | RegExp)[]
): Promise<void>;

这允许你检查给定表单元素是否拥有指定的显示值(最终用户将看到的值)。它接受 <input>、<select> 和 <textarea> 元素,但 <input type="checkbox"> 和 <input type="radio"> 除外,它们只能使用 toBeChecked 或 toHaveFormValues 进行有意义的匹配。

html
<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>
ts
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 ​

ts
function toBeChecked(): Promise<void>;

这允许你检查给定元素是否处于选中状态。它接受类型为 checkbox 或 radio 的 input 元素,以及 role 为 checkbox、radio 或 switch 且 aria-checked 属性为 "true" 或 "false" 的元素。

html
<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" />
ts
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 ​

typescript
function toBePartiallyChecked(): Promise<void>;

这允许你检查给定元素是否处于部分选中状态。它接受类型为 checkbox 的 input 元素和 role 为 checkbox 且 aria-checked="mixed" 的元素,或者 indeterminate 设置为 true 的类型为 checkbox 的 input 元素。

html
<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" />
ts
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 ​

ts
function toHaveRole(role: ARIARole): Promise<void>;

这允许你断言元素拥有预期的 角色。

这在已通过角色之外的其他查询访问元素时,并且想要对其可访问性进行额外断言的情况下很有用。

该角色可以与显式角色(通过 role 属性)匹配,也可以通过 隐式 ARIA 语义 匹配隐式角色。

html
<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/>
ts
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 的行为:

jsx
<div data-testid="switch" role="switch alert"></div>;

await expect.element(getByTestId('switch')).toHaveRole('switch'); // ✅
await expect.element(getByTestId('switch')).toHaveRole('alert'); // ❌

toHaveSelection ​

ts
function toHaveSelection(selection?: string): Promise<void>;

这允许断言元素拥有 文本选择。

这对于检查元素中是否存在选中的文本或部分文本很有用。该元素可以是文本类型的输入框、文本区域,或任何其他包含文本的元素,例如段落、span、div 等。

WARNING

预期选择是字符串形式,不支持检查选择范围索引。

html
<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>
ts
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 开始,涵盖父元素中子元素之前的文本,以及子元素的一部分。
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');
Pager
上一页定位器
下一页命令 API

基于 MIT 许可证 发布。

版权所有 (c) 2021-Present Vitest Team

https://vitest.dev/guide/browser/assertion-api

基于 MIT 许可证 发布。

版权所有 (c) 2021-Present Vitest Team