ロケーター
ロケーターは、単一または複数の要素を表現するものです。すべてのロケーターは、セレクターと呼ばれる文字列によって定義されます。Vitest は、このセレクターを内部で生成する便利なメソッドを提供することで、抽象化しています。
ロケーター API は、Playwright のロケーターから派生した Ivya を使用しています。Vitest はこの API をすべてのプロバイダーに提供しており、Playwright にも対応しています。
TIP
このページでは API の使用方法を説明します。ロケーターとその利用法についてより深く理解するには、Playwright の「Locators」ドキュメントをご参照ください。
getByRole
function getByRole(
role: ARIARole | string,
options?: LocatorByRoleOptions
): Locator;
要素をその ARIA ロール、ARIA 属性、およびアクセシブル名で特定する方法を提供します。
TIP
getByText('The name')
で単一の要素のみをクエリする場合、多くの場合、getByRole(expectedRole, { name: 'The name' })
を使用する方が適切です。アクセシブル名によるクエリは、*ByAltText
や *ByTitle
などの他のクエリを置き換えるものではありません。アクセシブル名がこれらの属性と等しい場合でも、これらの属性の機能が置き換えられるわけではありません。
次の DOM 構造を例に説明します。
<h3>Sign up</h3>
<label>
Login
<input type="text" />
</label>
<label>
Password
<input type="password" />
</label>
<br />
<button>Submit</button>
各要素は、その暗黙のロールを使用して特定できます。
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
属性を使用して、セマンティクスを提供できます。
すでに暗黙のロールを持つ組み込み要素に、role
または aria-*
属性を介してロールを提供することは、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
無効な要素を含めるかどうか。デフォルトでは、フィルターは適用されません。他の属性とは異なり、無効状態は継承されることに注意してください。
詳細については、
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 }); // ❌
参照
getByAltText
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;
指定されたテキストに一致する alt
属性を持つ要素を見つけるロケーターを作成します。testing-library の実装とは異なり、Vitest は一致する alt
属性を持つすべての要素を照合します。
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;
page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌
オプション
exact: boolean
text
が完全に一致するかどうか: 大文字と小文字を区別し、文字列全体を照合します。デフォルトでは無効です。text
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
getByLabelText
function getByLabelText(
text: string | RegExp,
options?: LocatorOptions
): Locator;
関連付けられたラベルを持つ要素を見つけることができるロケーターを作成します。
page.getByLabelText('Username')
ロケーターは、以下の例のすべての入力を見つけられます。
// for/htmlFor 関係によるラベルとフォーム要素の ID の関連付け
<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
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
getByPlaceholder
function getByPlaceholder(
text: string | RegExp,
options?: LocatorOptions
): Locator;
指定された placeholder
属性を持つ要素を見つけることができるロケーターを作成します。Vitest は、input
要素だけでなく、一致する placeholder
属性を持つすべての要素を照合します。
<input placeholder="Username" />;
page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌
WARNING
一般的に、プレースホルダーよりもgetByLabelText
を使用してラベルに依存する方が推奨されます。
オプション
exact: boolean
text
が完全に一致するかどうか: 大文字と小文字を区別し、文字列全体を照合します。デフォルトでは無効です。text
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
getByText
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;
指定されたテキストを含む要素を見つけることができるロケーターを作成します。テキストは、TextNode の nodeValue
と照合されるか、タイプが button
または reset
の場合は入力の値と照合されます。テキストによる照合は、厳密な一致であっても常に空白の正規化が行われます。例えば、複数のスペースを 1 つに、改行をスペースに変換し、先頭と末尾の空白は無視されます。
<a href="/about">About ℹ️</a>;
page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌
TIP
このロケーターは、非インタラクティブ要素を特定するのに役立ちます。ボタンや入力などのインタラクティブ要素を特定する場合は、getByRole
の使用が推奨されます。
オプション
exact: boolean
text
が完全に一致するかどうか: 大文字と小文字を区別し、文字列全体を照合します。デフォルトでは無効です。text
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
getByTitle
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;
指定された title
属性を持つ要素を見つけることができるロケーターを作成します。testing-library の getByTitle
とは異なり、Vitest は SVG 内の title
要素を検出できません。
<span title="Delete" id="2"></span>;
page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌
オプション
exact: boolean
text
が完全に一致するかどうか: 大文字と小文字を区別し、文字列全体を照合します。デフォルトでは無効です。text
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
getByTestId
function getByTestId(text: string | RegExp): Locator;
指定されたテスト ID 属性に一致する要素を見つけることができるロケーターを作成します。属性名は browser.locators.testIdAttribute
で設定可能です。
<div data-testid="custom-element" />;
page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌
WARNING
これは、他のロケーターがユースケースに合わない場合にのみ使用することをお勧めします。data-testid
属性の使用は、実際のソフトウェアの使用方法とは異なるため、可能な限り避けるべきです。
オプション
exact: boolean
text
が完全に一致するかどうか: 大文字と小文字を区別し、文字列全体を照合します。デフォルトでは無効です。text
が正規表現の場合、このオプションは無視されます。厳密な一致でも空白はトリムされることに注意してください。
参照
nth
function nth(index: number): Locator;
このメソッドは、複数要素クエリ結果内の特定のインデックスのみに一致する新しいロケーターを返します。インデックスはゼロベースであり、nth(0)
は最初の要素を選択します。elements()[n]
とは異なり、nth
ロケーターは要素が見つかるまで再試行されます。
<div aria-label="one"><input /><input /><input /></div>
<div aria-label="two"><input /></div>
page.getByRole('textbox').nth(0); // ✅
page.getByRole('textbox').nth(4); // ❌
TIP
nth
を使用する前に、検索を絞り込むためにチェーンされたロケーターを使用すると便利です。 要素の位置以外に区別するより良い方法がない場合もあります。これは不安定性につながる可能性がありますが、何もないよりは優れています。
page.getByLabel('two').getByRole('input'); // ✅ page.getByRole('textbox').nth(3) のより良い代替案
page.getByLabel('one').getByRole('input'); // ❌ あいまいすぎる
page.getByLabel('one').getByRole('input').nth(1); // ✅ 実用的な妥協案
first
function first(): Locator;
このメソッドは、複数要素クエリ結果の最初のインデックスのみに一致する新しいロケーターを返します。 これは nth(0)
のシンタックスシュガーです。
<input /> <input /> <input />
page.getByRole('textbox').first(); // ✅
last
function last(): Locator;
このメソッドは、複数要素クエリ結果の最後のインデックスのみに一致する新しいロケーターを返します。 これは nth(-1)
のシンタックスシュガーです。
<input /> <input /> <input />
page.getByRole('textbox').last(); // ✅
and
function and(locator: Locator): Locator;
このメソッドは、親ロケーターと指定されたロケーターの両方に一致する新しいロケーターを作成します。次の例では、特定のタイトルを持つボタンを見つけます。
page.getByRole('button').and(page.getByTitle('Subscribe'));
or
function or(locator: Locator): Locator;
このメソッドは、いずれかまたは両方のロケーターに一致する新しいロケーターを作成します。
WARNING
ロケーターが複数の要素に一致する場合、単一の要素を期待する別のメソッドを呼び出すとエラーがスローされる可能性があることに注意してください。
<>
<button>Click me</button>
<a href="https://vitest.dev">Error happened!</a>
</>;
page.getByRole('button').or(page.getByRole('link')).click(); // ❌ 複数の要素に一致
filter
function filter(options: LocatorOptions): Locator;
このメソッドは、テキストによるフィルタリングなどのオプションに基づいてロケーターを絞り込みます。複数のフィルターを適用するためにチェーンできます。
has
- 型:
Locator
このオプションは、指定されたロケーターに一致する他の要素を含む要素にセレクターを絞り込みます。例えば、この HTML の場合:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
ロケーターを絞り込んで、内部に Vitest
テキストを持つ article
のみを見つけることができます。
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅
WARNING
指定されたロケーター(例: page.getByText('Vitest')
)は、親ロケーター(例: page.getByRole('article')
)に対して相対的である必要があります。ドキュメントルートからではなく、親ロケーターを起点としてクエリされます。
したがって、親ロケーターの外部にある要素をクエリするロケーターを渡すことはできません。
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌
この例は、article
要素が「Vitest」というテキストを持つ要素の外部にあるため失敗します。
TIP
このメソッドは、要素をさらに絞り込むためにチェーンして使用できます。
page
.getByRole('article')
.filter({ has: page.getByRole('button', { name: 'delete row' }) })
.filter({ has: page.getByText('Vitest') });
hasNot
- 型:
Locator
このオプションは、指定されたロケーターに一致する他の要素を含まない要素にセレクターを絞り込みます。例えば、この HTML の場合:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
ロケーターを絞り込んで、内部に Rolldown
を持たない article
のみを見つけることができます。
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌
WARNING
指定されたロケーターは、has
オプションと同様に、ドキュメントルートではなく親に対してクエリされる点に注意してください。
hasText
- 型:
string | RegExp
このオプションは、セレクターを、内部のどこかに指定されたテキストを含む要素のみに絞り込みます。文字列が渡された場合、照合は大文字と小文字を区別せず、部分文字列の検索が行われます。
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
検索が大文字と小文字を区別しないため、両方のロケーターは同じ要素を見つけられます。
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅
hasNotText
- 型:
string | RegExp
このオプションは、セレクターを、内部のどこかに指定されたテキストを含まない要素のみに絞り込みます。文字列が渡された場合、照合は大文字と小文字を区別せず、部分文字列の検索が行われます。
メソッド
すべてのメソッドは非同期であり、await
する必要があります。Vitest 3 以降、メソッドが await
されないとテストは失敗します。
click
function click(options?: UserEventClickOptions): Promise<void>;
要素をクリックします。オプションを使用してカーソル位置を設定可能です。
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).click();
dblClick
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;
要素に対してダブルクリックイベントをトリガーします。オプションを使用してカーソル位置を設定可能です。
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).dblClick();
tripleClick
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;
要素に対してトリプルクリックイベントをトリガーします。ブラウザ API に tripleclick
は存在しないため、このメソッドは 3 回連続でクリックイベントを発生させます。
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).tripleClick();
clear
function clear(options?: UserEventClearOptions): Promise<void>;
入力要素のコンテンツをクリアします。
import { page } from '@vitest/browser/context';
await page.getByRole('textbox', { name: 'Full Name' }).clear();
hover
function hover(options?: UserEventHoverOptions): Promise<void>;
カーソルを選択した要素に移動します。
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).hover();
unhover
function unhover(options?: UserEventHoverOptions): Promise<void>;
これは locator.hover
と同じように機能しますが、カーソルを document.body
要素に移動させます。
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).unhover();
fill
function fill(text: string, options?: UserEventFillOptions): Promise<void>;
現在の input
、textarea
、または contenteditable
要素の値を設定します。
import { page } from '@vitest/browser/context';
await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
dropTo
function dropTo(
target: Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
現在の要素をターゲットの位置へドラッグします。
import { page } from '@vitest/browser/context';
const paris = page.getByText('Paris');
const france = page.getByText('France');
await paris.dropTo(france);
selectOptions
function selectOptions(
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
<select>
要素から 1 つ以上の値を選択します。
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' }),
]);
screenshot
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
を指定すると、保存されたファイルパスとともにコンテンツが返されます。
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 - スクリーンショットへのフルパス
// bas64 - スクリーンショットの base64 エンコードされた文字列
警告 3.2.0+
save
が false
に設定されている場合、screenshot
は常に base64 文字列を返す点に注意してください。 その場合、path
も無視されます。
query
function query(): Element | null;
このメソッドは、ロケーターのセレクターに一致する単一の要素を返します。要素が見つからない場合は null
を返します。
複数の要素がセレクターに一致する場合、このメソッドはエラーをスローします。一致するすべての DOM 要素が必要な場合は .elements()
を、セレクターに一致するロケーターの配列が必要な場合は .all()
を使用してください。
次の DOM 構造を考えてみましょう。
<div>Hello <span>World</span></div>
<div>Hello</div>
これらのロケーターはエラーをスローしません。
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement
これらのロケーターはエラーをスローします。
// 複数の要素を返す
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌
element
function element(): Element;
このメソッドは、ロケーターのセレクターに一致する単一の要素を返します。
セレクターに一致する要素がない場合、エラーがスローされます。要素が存在するかどうかを確認するだけでよい場合は、.query()
の使用を検討してください。
セレクターに複数の要素が一致する場合、エラーがスローされます。一致するすべての DOM 要素が必要な場合は .elements()
を、セレクターに一致するロケーターの配列が必要な場合は .all()
を使用してください。
TIP
このメソッドは、外部ライブラリに渡す必要がある場合に便利です。アサーションが再試行されるたびに、ロケーターが expect.element
とともに使用されると自動的に呼び出されます。
await expect.element(page.getByRole('button')).toBeDisabled();
次の DOM 構造を考えてみましょう。
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>
これらのロケーターはエラーをスローしません。
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅
これらのロケーターはエラーをスローします。
// 複数の要素を返す
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌
// 要素を返さない
page.getByText('Hello USA').element(); // ❌
elements
function elements(): Element[];
このメソッドは、ロケーターのセレクターに一致する要素の配列を返します。
この関数はエラーをスローしません。セレクターに一致する要素がない場合、このメソッドは空の配列を返します。
次の DOM 構造を考えてみましょう。
<div>Hello <span>World</span></div>
<div>Hello</div>
これらのロケーターは常に成功します。
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
function all(): Locator[];
このメソッドは、セレクターに一致する新しいロケーターの配列を返します。
内部的には、このメソッドは .elements
を呼び出し、page.elementLocator
を使用してすべての要素をラップします。
プロパティ
selector
selector
は、ブラウザプロバイダーが要素を特定するために使用する文字列です。Playwright は playwright
ロケーター構文を使用し、preview
と webdriverio
は CSS を使用します。
DANGER
この文字列をテストコードで直接使用すべきではありません。selector
文字列は、コマンド API を操作する場合にのみ使用してください。
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();
};
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+ advanced
ロケーターファクトリのオブジェクトを定義することで、組み込みのロケーター API を拡張できます。これらのメソッドは、page
オブジェクトおよび作成されたすべてのロケーターのメソッドとして利用できます。
これらのロケーターは、組み込みのロケーターだけでは不十分な場合に役立ちます。例えば、UI にカスタムフレームワークを使用している場合などです。
ロケーターファクトリは、セレクター文字列またはロケーター自体を返す必要があります。
TIP
セレクター構文は Playwright ロケーターと同一です。それらを操作する方法をよりよく理解するには、公式ガイドをお読みください。
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
の値を持つすべての要素を見つけられます。ただし、メソッドがロケーターで呼び出された場合、そのロケーターの範囲内で適用されます。
<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>
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(); // ❌