
E2Eテストを実装すると、テスト業務が楽になるというイメージがあると思います。
でも、実はE2Eテストを導入できた先に、これまでに無い業務も発生します。
それは、テスト項目が陳腐化していないかという見直し運用と、修正の際の再構築作業です。
ページ内のDOM構造が少し変わるだけで、テストを大幅に作り直すことになる場合があります。
実際に開発を行う現場のモジュール担保性と同じ領域で、テストの担保も行う必要があるんですね。
ということで、実務で壊れないE2Eを書くためのポイントを学習していきましょう。
Page / Locator を強化する目的
PageとLocatorを強化すると、次のようなメリットがあります。
・テストが壊れにくくなる
・UI変更に強くなる
・自動待機により安定性が上がる
・コードが読みやすくなる
・テスト工数が大幅に減る
このPageとLocatorという2つを理解できれば、Playwrightの本質を理解したと思っても大丈夫でしょう。
Page(ページ操作)の強化ポイント
Page は「ユーザーの操作」を完全に再現するための API 集合です。
すべての操作は async / await で順序が保証されるのがポイントです。
page.goto()
・遷移を待つ機構が自動でつく。
・waitForNavigation が不要なケースが多い。
page.click()
・押せる状態になるまで自動待機。
・短絡的な待機処理が不要。
page.fill()
・入力可能になるまで自動待機。
page.getByRole()
・「UI が利用者にどう見えるか」で取得できて壊れにくい。
・壊れにくく、テスト設計が安定する。
サンプルコード
import { test, expect } from "@playwright/test";
test("page API の基本操作まとめ", async ({ page }) => {
// --- ① page.goto():ページ遷移が完了するまで自動待機 ---
await page.goto("https://example.com");
// → DOMロード + ネットワークがアイドル状態になるまで待つ
// --- ② page.click():押せる状態になるまで自動待機 ---
await page.click('button#login');
// → ボタンが見えて、押せて、安定するまで勝手に待つ
// --- ③ page.fill():入力可能になるまで自動待機 ---
await page.fill('input[name="username"]', "koji");
await page.fill('input[name="password"]', "secret");
// → input がアクティブで編集できる状態になるまで待つ
// --- ④ page.getByRole():UI の意味で要素を取得 ---
await page.getByRole("button", { name: "送信" }).click();
// → 画面上で「ユーザが見る名前」ベースなので壊れにくい
// --- ⑤ 出力確認 ---
await expect(page.getByRole("heading", { name: "ログイン完了" })).toBeVisible();
});
よく使う操作一覧
ページ操作
page.goto(url)
page.reload()
page.goBack()
page.goForward()
全体の待機
page.waitForTimeout(ms)
page.waitForLoadState()
JavaScript の実行
page.evaluate(() => {...})
スクリーンショット
page.screenshot()
フレーム操作
page.frame()
ページ全体の検索
page.getByRole()
page.getByText()
page.locator()
※ locator を生成する役割
Locator(要素取得)の強化ポイント
Locator は“常に最新のDOMを監視する”スマートオブジェクトです。
CSSセレクタを使わずに要素取得するのがポイントです。
サンプルコード
import { test, expect } from "@playwright/test";
test("Locator API の基本操作まとめ", async ({ page }) => {
// --- ページ遷移 ---
await page.goto("https://example.com");
// --- ① Locator で要素を定義(遅延評価される) ---
const loginButton = page.locator('button#login');
const username = page.locator('input[name="username"]');
const password = page.locator('input[name="password"]');
const submitButton = page.getByRole("button", { name: "送信" });
// --- ② click():要素が押せるようになるまで待機 ---
await loginButton.click();
// --- ③ fill():入力可能になるまで待機してから入力 ---
awa
信頼度の高い Locator
locator.click()
毎回 DOM を再検索して自動待機付き。
locator.fill()
入力状態を自動チェック。
getByRole()
アクセシビリティに基づく安定セレクタ。
getByLabel()
フォーム系に強い。
getByTestId()
サービス側に data-testid を付けると安定する。
getByText()
曖昧さ回避のための精度調整。
getByText()
(曖昧回避に注意)
locator.nth(n)
リストを扱うときの定番。
locator.first() / locator.last()
リスト系DOM の変化に強い。
ポイント
・Selenium のような「stale element」系のエラーは起きない。
・Locator をページ内の変化に強くするには role, label, testId が最強。
・CSSセレクタを極力使わない
・CSS だけで書かれた E2E は維持不能になる。
よく使う操作一覧
要素の取得
locator = page.locator('css')
locator = page.getByRole('button', { name: '送信' })
要素の操作(=自動待機が走る)
locator.click()
locator.fill()
locator.check()
locator.selectOption()
locator.hover()
要素のテキスト/属性取得
locator.textContent()
locator.innerText()
locator.getAttribute()
要素の数や状態確認
expect(locator).toBeVisible()
expect(locator).toHaveCount(n)
expect(locator).toHaveText()
要素の絞り込み(柔軟)
locator.nth(index)
locator.first()
locator.last()
locator.filter({ hasText })
locator.locator('child-selector')(子孫へのアクセス)
locator.and()
locator.or()
Page と Locator の組み合わせ
フォーム入力
await page.getByLabel("メール").fill("test@example.com")
ボタン押下
await page.getByRole("button", { name: "登録" }).click()
モーダル要素
const modal = page.getByRole("dialog")
複数要素の処理
await page.getByRole("listitem").nth(2).click()
ドロップダウン
await page.getByRole("combobox").selectOption("A")
必要に応じて locator.filter() で絞り込むみ、
画面遷移チェックは await expect(page).toHaveURL("/dashboard")みたいにすると良いでしょう。
安定性を高めるコツ
1. 「ボタン」は role+name で必ず特定する。
2. 「文言に依存する UI 」は exact: true を使って誤取得を防ぐ。
3. 「テスト専用の data-testid 」を導入すると万全。
4. SPAの「非同期部分」は page.waitForResponse() を併用。
5. Locatorの取得は「人間から見て一意」かを意識する。
Page / Locator でよくある失敗と回避方法
getByTextが別要素に一致して誤クリック
role or testId を使う。
CSSセレクタがDOMを編集(変更)されて即死
role に逃がす。
awaitを忘れてテストが暴走
VSCodeのPlaywright 拡張を使って検出。
遷移待ちを手動で入れてしまう
ほぼ不要なので削除する(auto-wait がある)
サーバー応答待ちが必要なケース
API を待つ場合は page.waitForResponse() で安定化する。
page.click() と locator.click() の違いは?
page.click('selector')
selector をその場で評価し、1回だけ使う。
locator.click()
locator が常に最新DOMを参照するため、UI変動に強い。
基本的に locator.click() を使う方が安定
セレクタを多用する場合は?
page.locator() で Locator をまず作り、その Locator を複数回使う。
あとがき
今回は、Playwrightの本質が学習できたかと思います。
安定的にテストをするという思考は、その後の不具合を生むか生まないかの大きな分かれ道になるでしょう。
だって、テストコード内で不具合が発生すると、そのサービスが正常かどうか以前に、テストコードの検証からしないと行けなくなるから、
テストのためのテスト・・・みたいな意味のわからないカオス状態に陥りますからね。
もちろん、100%安定的なテストなんて、世の中には余程の小さなシステムじゃないとあり得ません。
それらも含めて、忍耐強く且つ、安定性を求める姿勢が重要ですね。
0 件のコメント:
コメントを投稿