【Playwright③】 効率的なDOM要素のアクセス方法(Locators)

Playwrightを使ったエンドツーエンド(E2E)テストでは、DOM要素へのアクセスが重要なステップとなる。Locatorsは、Playwrightが提供する強力なツールであり、これを使って正確かつ効率的にDOM要素を操作できる。本記事では、PlaywrightのLocatorsについて詳しく解説し、テストの信頼性と効率性を高める方法を学ぶ。

公式ドキュメント: https://playwright.dev/docs/locators

Locatorsとは?

Locatorsは、ページ上の要素を選択するための手段である。
Playwrightでは、page.locator()page.getByRole() など、いくつかの方法で要素を指定できる。
これにより、動的に変化するページや複雑な構造を持つページでも、確実に目的の要素を見つけることができる。

基本的なLocatorメソッド

ここでは、Playwrightでよく使われる基本的なLocatorメソッドを紹介する。
各メソッドごとに、HTML要素の例とそれに対応するテストコードを示す。
ちなみに、動作環境はNuxt3 TypeScript環境。

1. getByRole

getByRoleは、ボタンや見出しなどの要素を役割(Role)に基づいて選択する。

テストコード

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByRole</v-card-title>
  <v-card-text>
    <button type="submit" class="border-sm pa-2 rounded">Sign in</button>
    <h1>Playwright Locator Test</h1>
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByRole", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");
  // ボタンを探してクリック
  await page.getByRole("button", { name: "Sign in" }).click();
  // 見出しを探してテキストが表示されていることを確認
  await expect(page.getByRole("heading")).toHaveText("Playwright Locator Test");
});

2. getByLabel

getByLabelは、フォーム要素に関連付けられたラベルを基に要素を選択する。
これにより、フォームフィールドに正確にアクセスすることができる。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByLabel</v-card-title>
  <v-card-text>
    <div>
      <label for="username">User Name:</label>
      <input type="text" id="username" class="pa-2 ml-4 border-sm" />
    </div>
    <div class="mt-2">
      <label for="password">Password:</label>
      <input type="password" id="password" class="pa-2 ml-4 border-sm" />
    </div>
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByLabel", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");
  // ラベルを使ってユーザー名を入力
  await page.getByLabel("User Name").fill("JohnDoe");
  // ラベルを使ってパスワードを入力
  await page.getByLabel("Password").fill("secret-password");

  // 入力が正しく行われたか確認
  await expect(page.getByLabel("User Name")).toHaveValue("JohnDoe");
  await expect(page.getByLabel("Password")).toHaveValue("secret-password");
});

3. getByPlaceholder

getByPlaceholderは、プレースホルダーテキストを基に要素を選択する。
特に、ラベルがないフォーム要素に対して便利。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByPlaceholder</v-card-title>
  <v-card-text>
    <input type="text" placeholder="Enter your username" class="pa-2 border-sm" />
    <input type="password" placeholder="Enter your password" class="pa-2 ml-4 border-sm" />
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByPlaceholder", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");

  // プレースホルダーを使って入力を行う
  await page.getByPlaceholder("Enter your username").fill("JohnDoe");
  await page.getByPlaceholder("Enter your password").fill("secret-password");

  // 入力が正しく行われたか確認
  await expect(page.getByPlaceholder("Enter your username")).toHaveValue("JohnDoe");
  await expect(page.getByPlaceholder("Enter your password")).toHaveValue("secret-password");
});

4. getByText

getByTextは、要素のテキスト内容を基に要素を選択する。
これにより、表示されているテキストに基づいて要素を特定できる。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByText</v-card-title>
  <v-card-text>
    <p>Welcome, User!</p>
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByText", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");

  // テキストを基に要素を取得してアサーションを行う
  await expect(page.getByText("Welcome, User!")).toBeVisible();
});

注意点: 要素の重複

5. getByAltText

getByAltTextは、画像のaltテキストを基に要素を選択する。
画像要素のテストに有用。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByAltText</v-card-title>
  <v-card-text>
    <img src="/public/images/comming-soon.png" alt="comming soon image" />
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByAltText", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");

  // 画像のaltテキストを基に要素を取得してクリック
  await page.getByAltText("comming soon image").click();
});

6. getByTitle

getByTitleは、要素のtitle属性を基に要素を選択する。
特定のタイトルを持つ要素を取得する際に使用する。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByTitle</v-card-title>
  <v-card-text>
    <span title="Issues count">25 issues</span>
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByTitle", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");

  // title属性を基に要素を取得してアサーションを行う
  await expect(page.getByTitle("Issues count")).toHaveText("25 issues");
});

7. getByTestId

getByTestIdは、テストID属性を基に要素を選択する。
例えば、重複する要素がある場合に、特定の要素をターゲットにするために使用する。

テスト実装

アクセスしたい要素の表示:

HTML:

<v-card class="mt-10">
  <v-card-title>getByTestId</v-card-title>
  <v-card-text>
    <ul class="ml-6">
      <li data-testid="item-1">Item 1</li>
      <li data-testid="item-2">Item 2</li>
      <li data-testid="item-3">Item 3</li>
    </ul>
  </v-card-text>
</v-card>

テストコード:

import { test, expect } from "@playwright/test";

test("getByTestId", async ({ page }) => {
  await page.goto("http://localhost:3000/test/playwright");

  // test idを基に要素を取得してクリック
  await page.getByTestId("item-2").click();
  // 正しい要素がクリックされたか確認
  await expect(page.getByTestId("item-2")).toHaveText("Item 2");
});

おまけ: Locatorsの基本的な動作原理

1. 自動待機 (Auto-Waiting)

PlaywrightのLocatorsは、自動待機機能を持っている。
これは、指定した要素がDOMに存在し、表示され、操作可能になるまで待機する機能。
これにより、ページのロードや要素の動的な生成が完了するのを待ってから操作を開始するため、テストが安定する。

2. リトライ (Retry-ability)

Locatorsは、要素が一時的に見つからない場合や、操作が失敗した場合に、再試行を行う機能を備えている。
これにより、一時的なエラーやタイミングの問題でテストが失敗するリスクを軽減できる。

3. 最新のDOM要素の取得

Locatorsは、操作が実行される直前に常に最新のDOM要素を取得する。
つまり、Locatorが作成された時点ではなく、実際に操作が行われる時点でDOM要素が再評価される。
これにより、ページの再レンダリングや動的なコンテンツ変更に対応できる。

4. 要素のフィルタリング

Locatorsは、DOM内の特定の条件に一致する要素をフィルタリングする機能を持っている。
以下の例では、リスト項目の中から「Product 2」というテキストを含む要素をフィルタリングしてボタンをクリックする。

HTML:

<ul>
  <li>
    <h3>Product 1</h3>
    <button>Add to cart</button>
  </li>
  <li>
    <h3>Product 2</h3>
    <button>Add to cart</button>
  </li>
  <li>
    <h3>Product 3</h3>
    <button>Add to cart</button>
  </li>
</ul>

Playwrightテストコード:

import { test, expect } from '@playwright/test';

test('filter by text', async ({ page }) => {
  await page.goto('http://localhost:3000/test/playwright');

  // テキスト「Product 2」を含むリスト項目をフィルタリングし、ボタンをクリック
  await page
    .getByRole('listitem')
    .filter({ hasText: 'Product 2' })
    .getByRole('button', { name: 'Add to cart' })
    .click();

  // クリックしたボタンが正しいかどうかのアサーションを行う
  await expect(page.getByRole('listitem').filter({ hasText: 'Product 2' })).toBeVisible();
});

5. 仮想DOMのサポート

PlaywrightのLocatorsは、通常のDOM要素だけでなく、仮想DOM内の要素も自動的にサポートしている。
これにより、VueやReactなどのWebコンポーネントのテストも簡単に行うことができる。

まとめ

PlaywrightのLocatorsは、DOM要素に効率的にアクセスするための強力なツールだ。この記事で紹介した基本的なLocatorメソッドを活用し、あなたのプロジェクトにおけるテスト自動化をさらに強化していこう。次の記事では、「DOM操作」に焦点を当て、テストコードを通じて要素をクリックしたり、ドラッグしたり、入力したりする方法をについて解説する。

関連記事

コメント

この記事へのコメントはありません。