Playwright で locator が要素を特定できない(strict mode violation)
strict mode violation は locator が 2 つ以上の要素に一致したときのエラー。
getByRole で属性まで指定する、filter() で絞り込む、要素に test id を付与するのが基本の解決策。
first() での回避は最終手段。
#playwright#locator#strict-mode#selector#e2e
公開:
要約
Error: strict mode violation: locator('button') resolved to 3 elements は、locator が複数の要素に一致した ことを示すエラー。
Playwright の locator は strict mode がデフォルトで、操作対象は 1 要素に特定されている必要がある。
セレクタを曖昧なまま first() で逃げるのではなく、一意に特定できる locator に書き換える のが正攻法。
よくある原因
- セレクタが汎用的:
buttonや.itemのようなセレクタがページ全体で複数一致する - 繰り返し要素: 一覧やテーブルで同じテキストのボタン(「編集」「削除」など)が行ごとに描画される
- 重複 DOM: レスポンシブ対応でモバイル用・デスクトップ用に同じ要素が 2 セット存在する
- コンポーネント再利用: 同一構造のカードやフォームが複数描画される
解決策
1. ロールと名前で一意化する
// NG: strict mode violation になりやすい
await page.locator("button").click();
// OK: ロール + アクセシブルネームで特定
await page.getByRole("button", { name: "保存" }).click();推奨される locator の選び方は 公式ドキュメントの Locators にまとまっている。
2. filter で絞り込む
// 「Tokyo」を含む行の中の「編集」ボタン
await page
.getByRole("row")
.filter({ hasText: "Tokyo" })
.getByRole("button", { name: "編集" })
.click();繰り返し要素は「どの行・どのカードの中か」という文脈ごと指定すると、データの増減に強いテストになる。
3. test id を付与する
<button data-testid="submit-order">注文する</button>await page.getByTestId("submit-order").click();アクセシブルな属性で特定しづらい要素には data-testid を付与する。
4. nth / first は意図がある場合のみ
await page.getByRole("listitem").first().click();「先頭の項目を選ぶ」ことが仕様として正しい場合のみ使う。
一意化を諦めるための first() は、DOM の並び替えで別要素を操作する flaky テストにつながる。