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

页面导航

定位器 ​

定位器用于表示单个或多个元素。每个定位器都由一个选择器字符串定义。Vitest 提供了便捷的方法在后台生成选择器,从而简化了这一过程。

定位器 API 使用 Playwright 的定位器 的一个分支,称为 Ivya。然而,Vitest 为每个 provider 提供此 API,而不仅限于 Playwright。

TIP

本页涵盖 API 用法。要更好地理解定位器及其用法,请阅读 Playwright 的“定位器”文档。

getByRole ​

ts
function getByRole(
  role: ARIARole | string,
  options?: LocatorByRoleOptions
): Locator;

通过元素的 ARIA 角色、ARIA 属性 和 可访问名称 来定位元素。

TIP

如果你只用 getByText('The name') 查询单个元素,通常建议使用 getByRole(expectedRole, { name: 'The name' })。可访问名称查询不能替代其他查询,例如 *ByAltText 或 *ByTitle。虽然可访问名称可能与这些属性的值相同,但它并不能取代这些属性的功能。

考虑以下 DOM 结构:

html
<h3>Sign up</h3>
<label>
  Login
  <input type="text" />
</label>
<label>
  Password
  <input type="password" />
</label>
<br />
<button>Submit</button>

你可以通过其隐式角色定位每个元素:

ts
await expect
  .element(page.getByRole('heading', { name: 'Sign up' }))
  .toBeVisible();

await page.getByRole('textbox', { name: 'Login' }).fill('admin');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');

await page.getByRole('button', { name: /submit/i }).click();

WARNING

角色通过字符串相等匹配,不遵循 ARIA 角色层次结构。因此,查询 checkbox 等超类角色将不包括 switch 等子类角色元素。

默认情况下,HTML 中的许多语义元素都具有角色;例如,<input type="radio"> 具有“radio”角色。HTML 中的非语义元素没有角色;未添加语义的 <div> 和 <span> 返回 null。role 属性可以提供语义。

ARIA 指南强烈不鼓励通过 role 或 aria-* 属性为本身已具有隐式角色的内置元素提供角色。

选项 ​
  • exact: boolean

    name 是否精确匹配:区分大小写且匹配整个字符串。默认禁用。如果 name 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

    tsx
    <button>Hello World</button>;
    
    page.getByRole('button', { name: 'hello world' }); // ✅
    page.getByRole('button', { name: 'hello world', exact: true }); // ❌
    page.getByRole('button', { name: 'Hello World', exact: true }); // ✅
  • checked: boolean

    是否应包含或不包含已选中元素(由 aria-checked 或 <input type="checkbox"/> 设置)。默认情况下,此筛选器不生效。

    有关更多信息,请参阅 aria-checked

    tsx
    <>
      <button role="checkbox" aria-checked="true" />
      <input type="checkbox" checked />
    </>;
    
    page.getByRole('checkbox', { checked: true }); // ✅
    page.getByRole('checkbox', { checked: false }); // ❌
  • disabled: boolean

    是否应包含或不包含禁用元素。默认情况下,不应用此筛选器。请注意,与其他属性不同,disabled 状态是可继承的。

    有关更多信息,请参阅 aria-disabled

    tsx
    <input type="text" disabled />;
    
    page.getByRole('textbox', { disabled: true }); // ✅
    page.getByRole('textbox', { disabled: false }); // ❌
  • expanded: boolean

    是否应包含或不包含展开元素。默认情况下,不应用此筛选器。

    有关更多信息,请参阅 aria-expanded

    tsx
    <a aria-expanded="true" href="example.com">
      Link
    </a>;
    
    page.getByRole('link', { expanded: true }); // ✅
    page.getByRole('link', { expanded: false }); // ❌
  • includeHidden: boolean

    是否应查询通常从可访问性树中排除的元素。默认情况下,只有非隐藏元素才与角色选择器匹配。

    请注意,角色 none 和 presentation 始终包含在内。

    tsx
    <button style="display: none" />;
    
    page.getByRole('button'); // ❌
    page.getByRole('button', { includeHidden: false }); // ❌
    page.getByRole('button', { includeHidden: true }); // ✅
  • level: number

    一个数字属性,通常用于 heading、listitem、row、treeitem 角色,<h1>-<h6> 元素具有默认值。默认情况下,此筛选器不生效。

    有关更多信息,请参阅 aria-level

    tsx
    <>
      <h1>Heading Level One</h1>
      <div role="heading" aria-level="1">
        Second Heading Level One
      </div>
    </>;
    
    page.getByRole('heading', { level: 1 }); // ✅
    page.getByRole('heading', { level: 2 }); // ❌
  • name: string | RegExp

    可访问名称。默认情况下,匹配不区分大小写并搜索子字符串。使用 exact 选项来控制此行为。

    tsx
    <button>Click Me!</button>;
    
    page.getByRole('button', { name: 'Click Me!' }); // ✅
    page.getByRole('button', { name: 'click me!' }); // ✅
    page.getByRole('button', { name: 'Click Me?' }); // ❌
  • pressed: boolean

    是否应包含或不包含按下元素。默认情况下,此筛选器不生效。

    有关更多信息,请参阅 aria-pressed

    tsx
    <button aria-pressed="true">👍</button>;
    
    page.getByRole('button', { pressed: true }); // ✅
    page.getByRole('button', { pressed: false }); // ❌
  • selected: boolean

    是否应包含或不包含选定元素。默认情况下,此筛选器不生效。

    有关更多信息,请参阅 aria-selected

    tsx
    <button role="tab" aria-selected="true">
      Vue
    </button>;
    
    page.getByRole('button', { selected: true }); // ✅
    page.getByRole('button', { selected: false }); // ❌
另请参阅 ​
  • MDN 上的 ARIA 角色列表
  • w3.org 上的 ARIA 角色列表
  • testing-library 的 ByRole

getByAltText ​

ts
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;

创建一个定位器,能够找到 alt 属性与文本匹配的元素。与 testing-library 的实现不同,Vitest 将匹配任何具有相应 alt 属性的元素。

tsx
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;

page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByAltText

getByLabelText ​

ts
function getByLabelText(
  text: string | RegExp,
  options?: LocatorOptions
): Locator;

创建一个定位器,能够找到具有关联标签的元素。

page.getByLabelText('Username') 定位器将找到以下示例中的所有输入:

html
// `label` 标签和表单元素 `id` 之间的 `for`/`htmlFor` 关系
<label for="username-input">Username</label>
<input id="username-input" />

// 带有表单元素的 `aria-labelledby` 属性
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />

// 包装标签
<label>Username <input /></label>

// 包装标签,其中标签文本位于另一个子元素中
<label>
  <span>Username</span>
  <input />
</label>

// `aria-label` 属性
// 请注意,这不是用户可以在页面上看到的标签,因此您的输入的目的必须对视觉用户显而易见。
<input aria-label="Username" />

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByLabelText

getByPlaceholder ​

ts
function getByPlaceholder(
  text: string | RegExp,
  options?: LocatorOptions
): Locator;

创建一个定位器,能够找到具有指定 placeholder 属性的元素。Vitest 将匹配任何具有匹配 placeholder 属性的元素,而不仅仅是 input。

tsx
<input placeholder="Username" />;

page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌

WARNING

通常,最好依赖使用 getByLabelText 的标签,而不是仅依赖占位符。

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByPlaceholderText

getByText ​

ts
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;

创建一个定位器,能够找到包含指定文本的元素。文本将与 TextNode 的 nodeValue 或输入的值(如果类型是 button 或 reset)进行匹配。通过文本匹配总是会规范化空格,即使是精确匹配也是如此。例如,它会将多个空格转换为一个,将换行符转换为空格,并忽略前导和尾随空格。

tsx
<a href="/about">About ℹ️</a>;

page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌

TIP

此定位器对于定位非交互式元素很有用。如果需要定位交互式元素,例如按钮或输入,请优先使用 getByRole。

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByText

getByTitle ​

ts
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;

创建一个定位器,能够找到具有指定 title 属性的元素。与 testing-library 的 getByTitle 不同,Vitest 无法在 SVG 中找到 title 元素。

tsx
<span title="Delete" id="2"></span>;

page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByTitle

getByTestId ​

ts
function getByTestId(text: string | RegExp): Locator;

创建一个定位器,能够找到与指定测试 ID 属性匹配的元素。你可以使用 browser.locators.testIdAttribute 配置属性名称。

tsx
<div data-testid="custom-element" />;

page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌

WARNING

建议仅在其他定位器不适用于你的用例时才使用此方法。使用 data-testid 属性不符合你的软件使用方式,应尽可能避免。

选项 ​

  • exact: boolean

    text 是否精确匹配:区分大小写和整个字符串。默认禁用。如果 text 是正则表达式,则此选项将被忽略。请注意,精确匹配时仍会去除空格。

另请参阅 ​

  • testing-library 的 ByTestId

nth ​

ts
function nth(index: number): Locator;

此方法返回一个新的定位器,该定位器仅匹配多元素查询结果中的特定索引。它是零基的,nth(0) 选择第一个元素。与 elements()[n] 不同,nth 定位器将重试直到元素出现。

html
<div aria-label="one"><input /><input /><input /></div>
<div aria-label="two"><input /></div>
tsx
page.getByRole('textbox').nth(0); // ✅
page.getByRole('textbox').nth(4); // ❌

TIP

在使用 nth 之前,你可能会发现使用链式定位器来缩小搜索范围很有用。 有时,除了元素位置之外,没有更好的区分方法;尽管这可能导致不稳定,但聊胜于无。

tsx
page.getByLabel('two').getByRole('input'); // ✅ 优于 page.getByRole('textbox').nth(3)
page.getByLabel('one').getByRole('input'); // ❌ 太模糊
page.getByLabel('one').getByRole('input').nth(1); // ✅ 务实的折衷

first ​

ts
function first(): Locator;

此方法返回一个新的定位器,该定位器仅匹配多元素查询结果的第一个索引。 它是 nth(0) 的语法糖。

html
<input /> <input /> <input />
tsx
page.getByRole('textbox').first(); // ✅

last ​

ts
function last(): Locator;

此方法返回一个新的定位器,该定位器仅匹配多元素查询结果的最后一个索引。 它是 nth(-1) 的语法糖。

html
<input /> <input /> <input />
tsx
page.getByRole('textbox').last(); // ✅

and ​

ts
function and(locator: Locator): Locator;

此方法创建一个新的定位器,该定位器同时匹配父定位器和提供的定位器。以下示例查找具有特定标题的按钮:

ts
page.getByRole('button').and(page.getByTitle('Subscribe'));

or ​

ts
function or(locator: Locator): Locator;

此方法创建一个新的定位器,该定位器匹配其中一个或两个定位器。

WARNING

请注意,如果定位器匹配多个元素,则调用某些方法可能会抛出错误,尤其当该方法期望单个元素时:

tsx
<>
  <button>Click me</button>
  <a href="https://vitest.dev">Error happened!</a>
</>;

page.getByRole('button').or(page.getByRole('link')).click(); // ❌ 匹配多个元素

filter ​

ts
function filter(options: LocatorOptions): Locator;

此方法根据选项缩小定位器范围,例如按文本筛选。它可以通过链式调用来应用多个筛选器。

has ​

  • 类型: Locator

此选项缩小选择器范围,以匹配包含与提供的定位器匹配的其他元素的元素。例如,对于此 HTML:

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

我们可以缩小定位器范围,只查找内部包含 Vitest 文本的 article:

ts
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅

WARNING

提供的定位器(示例中的 page.getByText('Vitest'))必须相对于父定位器(示例中的 page.getByRole('article'))。它将从父定位器开始查询,而不是从文档根开始。

这意味着,你不能传入查询父定位器范围之外元素的定位器:

ts
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌

此示例将失败,因为 article 元素位于带有 Vitest 文本的元素之外。

TIP

此方法可以链式调用以进一步缩小元素范围:

ts
page
  .getByRole('article')
  .filter({ has: page.getByRole('button', { name: 'delete row' }) })
  .filter({ has: page.getByText('Vitest') });

hasNot ​

  • 类型: Locator

此选项缩小选择器范围,以匹配不包含其他与提供的定位器匹配的元素的元素。例如,对于此 HTML:

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

我们可以缩小定位器范围,只查找内部不包含 Rolldown 的 article。

ts
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌

WARNING

请注意,提供的定位器是针对父级查询的,而不是针对文档根的,就像 has 选项一样。

hasText ​

  • 类型: string | RegExp

此选项缩小选择器范围,以仅匹配内部包含指定文本的元素。当传入 string 时,匹配不区分大小写并搜索子字符串。

html
<article>
  <div>Vitest</div>
</article>
<article>
  <div>Rolldown</div>
</article>

两个定位器都将找到相同的元素,因为搜索不区分大小写:

ts
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅

hasNotText ​

  • 类型: string | RegExp

此选项缩小选择器范围,以仅匹配内部不包含指定文本的元素。当传入 string 时,匹配不区分大小写并搜索子字符串。

方法 ​

所有方法都是异步的,必须被等待。从 Vitest 3 开始,如果方法未被等待,测试将失败。

click ​

ts
function click(options?: UserEventClickOptions): Promise<void>;

点击一个元素。你可以使用选项设置光标位置。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).click();
  • 更多信息请参阅 userEvent.click

dblClick ​

ts
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;

触发元素的双击事件。你可以使用选项设置光标位置。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).dblClick();
  • 更多信息请参阅 userEvent.dblClick

tripleClick ​

ts
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;

触发元素的三击事件。由于浏览器 API 中没有 tripleclick,此方法将连续触发三次点击事件。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).tripleClick();
  • 更多信息请参阅 userEvent.tripleClick

clear ​

ts
function clear(options?: UserEventClearOptions): Promise<void>;

清除输入元素内容。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('textbox', { name: 'Full Name' }).clear();
  • 更多信息请参阅 userEvent.clear

hover ​

ts
function hover(options?: UserEventHoverOptions): Promise<void>;

将光标位置移动到选定的元素。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).hover();
  • 更多信息请参阅 userEvent.hover

unhover ​

ts
function unhover(options?: UserEventHoverOptions): Promise<void>;

这与 locator.hover 的工作方式相同,但将光标移动到 document.body 元素上。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('img', { name: 'Rose' }).unhover();
  • 更多信息请参阅 userEvent.unhover

fill ​

ts
function fill(text: string, options?: UserEventFillOptions): Promise<void>;

设置当前 input、textarea 或 contenteditable 元素的值。

ts
import { page } from '@vitest/browser/context';

await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
  • 更多信息请参阅 userEvent.fill

dropTo ​

ts
function dropTo(
  target: Locator,
  options?: UserEventDragAndDropOptions
): Promise<void>;

将当前元素拖动到目标位置。

ts
import { page } from '@vitest/browser/context';

const paris = page.getByText('Paris');
const france = page.getByText('France');

await paris.dropTo(france);
  • 更多信息请参阅 userEvent.dragAndDrop

selectOptions ​

ts
function selectOptions(
  values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
  options?: UserEventSelectOptions
): Promise<void>;

从 <select> 元素中选择一个或多个值。

ts
import { page } from '@vitest/browser/context';

const languages = page.getByRole('select', { name: 'Languages' });

await languages.selectOptions('EN');
await languages.selectOptions(['ES', 'FR']);
await languages.selectOptions([
  languages.getByRole('option', { name: 'Spanish' }),
  languages.getByRole('option', { name: 'French' }),
]);
  • 更多信息请参阅 userEvent.selectOptions

screenshot ​

ts
function screenshot(
  options: LocatorScreenshotOptions & { save: false }
): Promise<string>;
function screenshot(
  options: LocatorScreenshotOptions & { base64: true }
): Promise<{
  path: string;
  base64: string;
}>;
function screenshot(
  options?: LocatorScreenshotOptions & { base64?: false }
): Promise<string>;

创建与定位器选择器匹配的元素的屏幕截图。

你可以使用 path 选项指定屏幕截图的保存位置,该位置是相对于当前测试文件的。如果未设置 path 选项,Vitest 将默认使用 browser.screenshotDirectory(默认为 __screenshot__),以及文件和测试的名称来确定屏幕截图的文件路径。

如果你还需要屏幕截图的内容,可以指定 base64: true 以将其与屏幕截图保存的文件路径一并返回。

ts
import { page } from '@vitest/browser/context';

const button = page.getByRole('button', { name: 'Click Me!' });

const path = await button.screenshot();

const { path, base64 } = await button.screenshot({
  path: './button-click-me.png',
  base64: true, // 也返回 base64 字符串
});
// path - 屏幕截图的完整路径
// base64 - 屏幕截图的 base64 编码字符串

警告 3.2.0+

请注意,如果 save 设置为 false,screenshot 将始终返回 base64 字符串。 在这种情况下,path 也将被忽略。

query ​

ts
function query(): Element | null;

此方法返回与定位器选择器匹配的单个元素,如果未找到元素则返回 null。

如果多个元素匹配选择器,此方法将抛出错误。当你需要所有匹配的 DOM 元素时,请使用 .elements();当你需要匹配该选择器的定位器数组时,请使用 .all()。

考虑以下 DOM 结构:

html
<div>Hello <span>World</span></div>
<div>Hello</div>

这些定位器不会抛出错误:

ts
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement

这些定位器将抛出错误:

ts
// 返回多个元素
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌

element ​

ts
function element(): Element;

此方法返回与定位器选择器匹配的单个元素。

如果没有元素匹配选择器,则抛出错误。当你只需要检查元素是否存在时,请考虑使用 .query()。

如果多个元素匹配选择器,则抛出错误。当你需要所有匹配的 DOM 元素时,请使用 .elements();当你需要匹配该选择器的定位器数组时,请使用 .all()。

TIP

如果你需要将其传递给外部库,此方法会很有用。当定位器与 expect.element 一起使用时,每次断言重试时都会自动调用此方法:

ts
await expect.element(page.getByRole('button')).toBeDisabled();

考虑以下 DOM 结构:

html
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>

这些定位器不会抛出错误:

ts
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅

这些定位器将抛出错误:

ts
// 返回多个元素
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌

// 不返回任何元素
page.getByText('Hello USA').element(); // ❌

elements ​

ts
function elements(): Element[];

此方法返回与定位器选择器匹配的元素数组。

该方法不会抛出错误。如果没有元素匹配选择器,此方法将返回空数组。

考虑以下 DOM 结构:

html
<div>Hello <span>World</span></div>
<div>Hello</div>

这些定位器将始终成功:

ts
page.getByText('Hello World').elements(); // ✅ [HTMLElement]
page.getByText('World').elements(); // ✅ [HTMLElement]
page.getByText('Hello', { exact: true }).elements(); // ✅ [HTMLElement]
page.getByText('Hello').element(); // ✅ [HTMLElement, HTMLElement]
page.getByText('Hello USA').elements(); // ✅ []

all ​

ts
function all(): Locator[];

此方法返回与选择器匹配的新定位器数组。

在内部,此方法调用 .elements 并使用 page.elementLocator 包装每个元素。

  • 请参阅 locator.elements()

属性 ​

selector ​

selector 是一个字符串,浏览器提供程序将使用它来定位元素。Playwright 将使用 playwright 定位器语法,而 preview 和 webdriverio 将使用 CSS 选择器。

DANGER

你不应该在测试代码中直接使用此字符串。selector 字符串只应在处理命令 API 时使用:

ts
import type { BrowserCommand } from 'vitest/node';

const test: BrowserCommand<string> = function test(context, selector) {
  // playwright
  await context.iframe.locator(selector).click();
  // webdriverio
  await context.browser.$(selector).click();
};
ts
import { test } from 'vitest';
import { commands, page } from '@vitest/browser/context';

test('works correctly', async () => {
  await commands.test(page.getByText('Hello').selector); // ✅
  // vitest 会自动将其解包为字符串
  await commands.test(page.getByText('Hello')); // ✅
});

自定义定位器 3.2.0+ 高级 ​

你可以通过定义定位器工厂对象来扩展内置定位器 API。这些方法将作为 page 对象和任何已创建的定位器上的方法存在。

如果内置定位器不够用,这些定位器会很有用。例如,当你为 UI 使用自定义框架时尤其如此。

定位器工厂需要返回一个选择器字符串或一个定位器本身。

TIP

选择器语法与 Playwright 定位器相同。请阅读他们的指南以更好地理解如何使用它们。

ts
import { locators } from '@vitest/browser/context';

locators.extend({
  getByArticleTitle(title) {
    return `[data-title="${title}"]`;
  },
  getByArticleCommentsCount(count) {
    return `.comments :text("${count} comments")`;
  },
  async previewComments() {
    // 你可以通过“this”访问当前定位器
    // 请注意,如果该方法是在 `page` 上调用的,则 `this` 将是 `page`,
    // 而不是当前定位器!
    if (this !== page) {
      await this.click();
    }
    // ...
  },
});

// 如果你正在使用 TypeScript,你可以扩展 LocatorSelectors 接口
// 以便在 locators.extend、page.* 和 locator.* 方法中获得自动补全
declare module '@vitest/browser/context' {
  interface LocatorSelectors {
    // 如果自定义方法返回字符串,它将被转换为定位器
    // 如果它返回其他任何内容,则将按原样返回
    getByArticleTitle(title: string): Locator;
    getByArticleCommentsCount(count: number): Locator;

    // Vitest 将返回一个 Promise,并且不会尝试将其转换为定位器
    previewComments(this: Locator): Promise<void>;
  }
}

如果该方法在全局 page 对象上调用,则选择器将应用于整个页面。在下面的示例中,getByArticleTitle 将找到所有具有 data-title 属性且值为 title 的元素。但是,如果该方法在定位器上调用,则它将限定在该定位器范围内。

html
<article data-title="Hello, World!">
  Hello, World!
  <button id="comments">2 comments</button>
</article>

<article data-title="Hello, Vitest!">
  Hello, Vitest!
  <button id="comments">0 comments</button>
</article>
ts
const articles = page.getByRole('article');
const worldArticle = page.getByArticleTitle('Hello, World!'); // ✅
const commentsElement = worldArticle.getByArticleCommentsCount(2); // ✅
const wrongCommentsElement = worldArticle.getByArticleCommentsCount(0); // ❌
const wrongElement = page.getByArticleTitle('No Article!'); // ❌

await commentsElement.previewComments(); // ✅
await wrongCommentsElement.previewComments(); // ❌
Pager
上一页交互 API
下一页断言 API

基于 MIT 许可证 发布。

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

https://vitest.dev/guide/browser/locators

基于 MIT 许可证 发布。

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