その他のロケーター
はじめに
最も一般的で推奨されるロケーターについては、メインのロケーターガイドをご覧ください。
page.get_by_role() や page.get_by_text() のような推奨ロケーターに加えて、Playwright はこのガイドで説明されている様々な他のロケーターをサポートしています。
CSS ロケーター
実装に依存し、ページが変更されたときに壊れる可能性がある CSS を使用する代わりに、テキストやアクセシブルなロールのようなユーザーに表示されるロケーターを優先することをお勧めします。
Playwright は CSS セレクターで要素を特定できます。
- 同期
- 非同期
page.locator("css=button").click()
await page.locator("css=button").click()
Playwright は標準的な CSS セレクターを 2 つの方法で拡張します。
- CSS セレクターは開いているシャドウ DOM を貫通します。
- Playwright は、
:visible、:has-text()、:has()、:is()、:nth-match()などのカスタム疑似クラスを追加します。
CSS: テキストによるマッチング
Playwright には、テキストコンテンツで要素をマッチングするための多くの CSS 疑似クラスが含まれています。
-
article:has-text("Playwright")-:has-text()は、指定されたテキストがどこかに含まれている要素(子要素や子孫要素内である可能性もあります)にマッチします。マッチングでは大文字と小文字を区別せず、空白をトリムし、部分文字列を検索します。例えば、
article:has-text("Playwright")は<article><div>Playwright</div></article>にマッチします。:has-text()は他の CSS 指定子と組み合わせて使用する必要があります。そうしないと、<body>を含む、指定されたテキストを含むすべての要素にマッチすることに注意してください。- 同期
- 非同期
# Wrong, will match many elements including <body>
page.locator(':has-text("Playwright")').click()
# Correct, only matches the <article> element
page.locator('article:has-text("All products")').click()# Wrong, will match many elements including <body>
await page.locator(':has-text("Playwright")').click()
# Correct, only matches the <article> element
await page.locator('article:has-text("Playwright")').click() -
#nav-bar :text("Home")-:text()疑似クラスは、指定されたテキストを含む最小の要素にマッチします。マッチングでは大文字と小文字を区別せず、空白をトリムし、部分文字列を検索します。例えば、これは
#nav-bar要素内のどこかに「Home」というテキストを持つ要素を見つけます。- 同期
- 非同期
page.locator("#nav-bar :text('Home')").click()await page.locator("#nav-bar :text('Home')").click() -
#nav-bar :text-is("Home")-:text-is()疑似クラスは、正確なテキストを持つ最小の要素にマッチします。厳密なマッチングでは大文字と小文字を区別し、空白をトリムし、完全な文字列を検索します。例えば、
:text-is("Log")は<button>Log in</button>にマッチしません。なぜなら、<button>には"Log in"という単一のテキストノードが含まれており、それが"Log"と等しくないからです。しかし、:text-is("Log")は<button> Log <span>in</span></button>にマッチします。なぜなら、<button>には" Log "というテキストノードが含まれているからです。同様に、
:text-is("Download")は<button>download</button>にマッチしません。大文字と小文字を区別するからです。
-
#nav-bar :text-matches("reg?ex", "i")-:text-matches()疑似クラスは、JavaScript のような正規表現にマッチするテキストコンテンツを持つ最小の要素にマッチします。例えば、
:text-matches("Log\s*in", "i")は<button>Login</button>と<button>log IN</button>にマッチします。
テキストマッチングは常に空白を正規化します。例えば、複数のスペースを1つにまとめ、改行をスペースに変換し、前後の空白を無視します。
button および submit 型の入力要素は、テキストコンテンツではなく value でマッチングされます。例えば、:text("Log in") は <input type=button value="Log in"> にマッチします。
CSS: 表示されている要素のみをマッチングする
Playwright は CSS セレクターで :visible 疑似クラスをサポートしています。例えば、css=button はページのすべてのボタンにマッチしますが、css=button:visible は表示されているボタンのみにマッチします。これは、非常に似ているが表示が異なる要素を区別するのに役立ちます。
ページに2つのボタンがあり、1つ目は非表示、2つ目は表示されている場合を考えます。
<button style='display: none'>Invisible</button>
<button>Visible</button>
-
これにより両方のボタンが見つかり、厳密性違反エラーがスローされます。
- 同期
- 非同期
page.locator("button").click()await page.locator("button").click() -
これにより、2番目のボタンのみが見つかり、クリックされます。なぜなら、それが表示されているからです。
- 同期
- 非同期
page.locator("button:visible").click()await page.locator("button:visible").click()
CSS: 他の要素を含む要素
:has() 疑似クラスは実験的な CSS 疑似クラスです。これは、与えられた要素の :scope に相対的に、パラメータとして渡されたセレクターのいずれかが少なくとも1つの要素にマッチする場合に、その要素を返します。
次のスニペットは、内部に <div class=promo> を持つ <article> 要素のテキストコンテンツを返します。
- 同期
- 非同期
page.locator("article:has(div.promo)").text_content()
await page.locator("article:has(div.promo)").text_content()
CSS: いずれかの条件にマッチする要素
CSS セレクターをコンマで区切ったリストは、そのリスト内のいずれかのセレクターで選択できるすべての要素にマッチします。
- 同期
- 非同期
# Clicks a <button> that has either a "Log in" or "Sign in" text.
page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()
# Clicks a <button> that has either a "Log in" or "Sign in" text.
await page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()
:is() 疑似クラスは、要素に追加の条件のリストを指定するのに役立つ可能性のある実験的な CSS 疑似クラスです。
CSS: レイアウトに基づいた要素のマッチング
レイアウトに基づいたマッチングは、予期しない結果を生成する可能性があります。例えば、レイアウトが1ピクセル変更されただけで、別の要素がマッチする可能性があります。
特徴的な機能が不足している場合、目的の要素に対して適切なセレクターを考案するのは難しい場合があります。この場合、Playwright のレイアウト CSS 疑似クラスが役立つことがあります。これらは通常の CSS と組み合わせて、複数の選択肢の中から1つを特定することができます。
例えば、input:right-of(:text("Password")) は、「Password」というテキストの右側にある入力フィールドにマッチします。これは、ページに互いに区別しにくい複数の入力がある場合に役立ちます。
レイアウト疑似クラスは、input のような他のものと組み合わせて使用すると役立ちます。レイアウト疑似クラスを単独で使用すると、:right-of(:text("Password")) のように、探している入力ではなく、テキストと目的の入力の間にある空の要素や、スクロールアウトされて現在表示されていない要素など、たまたま最も近い別の要素が見つかる可能性が高いです。
レイアウト疑似クラスは、要素の距離と相対位置を計算するためにbounding client rectを使用します。
:right-of(div > button)- 内側のセレクターにマッチする任意の要素の右側にある要素に、任意の垂直位置でマッチします。:left-of(div > button)- 内側のセレクターにマッチする任意の要素の左側にある要素に、任意の垂直位置でマッチします。:above(div > button)- 内側のセレクターにマッチする任意の要素の上側にある要素に、任意の水平位置でマッチします。:below(div > button)- 内側のセレクターにマッチする任意の要素の下側にある要素に、任意の水平位置でマッチします。:near(div > button)- 内側のセレクターにマッチする任意の要素の近く(50 CSS ピクセル以内)にある要素にマッチします。
結果としてマッチした要素はアンカー要素からの距離でソートされるため、最も近い要素を選択するにはlocator.firstを使用できます。これは、似たような要素のリストがあり、最も近いものが明らかに正しい場合にのみ役立ちます。しかし、他のケースでlocator.firstを使用すると、期待通りに機能しない可能性が高いです。探している要素ではなく、ランダムな空の<div>や、スクロールアウトされて現在表示されていない要素など、たまたま最も近い別の要素がターゲットになります。
- 同期
- 非同期
# Fill an input to the right of "Username".
page.locator("input:right-of(:text(\"Username\"))").fill("value")
# Click a button near the promo card.
page.locator("button:near(.promo-card)").click()
# Click the radio input in the list closest to the "Label 3".
page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first.click()
# Fill an input to the right of "Username".
await page.locator("input:right-of(:text(\"Username\"))").fill("value")
# Click a button near the promo card.
await page.locator("button:near(.promo-card)").click()
# Click the radio input in the list closest to the "Label 3".
await page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first.click()
すべてのレイアウト疑似クラスは、最後の引数としてオプションの最大ピクセル距離をサポートしています。例えば、button:near(:text("Username"), 120) は、「Username」というテキストを持つ要素から最大120 CSS ピクセル離れたボタンにマッチします。
CSS: クエリ結果から n 番目のマッチを選択する
通常、要素はページ変更に対してより堅牢な、いくつかの属性やテキストコンテンツによって区別することができます。
ページには多数の類似した要素が含まれていることがあり、特定の要素を選択するのが難しい場合があります。例えば
<section> <button>Buy</button> </section>
<article><div> <button>Buy</button> </div></article>
<div><div> <button>Buy</button> </div></div>
この場合、:nth-match(:text("Buy"), 3) は上記のスニペットから3番目のボタンを選択します。インデックスは1ベースであることに注意してください。
- 同期
- 非同期
# Click the third "Buy" button
page.locator(":nth-match(:text('Buy'), 3)").click()
# Click the third "Buy" button
await page.locator(":nth-match(:text('Buy'), 3)").click()
:nth-match() は、locator.wait_for() を使用して、指定された数の要素が出現するまで待機するのにも役立ちます。
- 同期
- 非同期
# Wait until all three buttons are visible
page.locator(":nth-match(:text('Buy'), 3)").wait_for()
# Wait until all three buttons are visible
await page.locator(":nth-match(:text('Buy'), 3)").wait_for()
:nth-child() とは異なり、要素は兄弟である必要はなく、ページ上のどこにでも存在できます。上記のスニペットでは、3つのボタンすべてが :text("Buy") セレクターにマッチし、:nth-match() は3番目のボタンを選択します。
N 番目の要素ロケーター
ゼロベースのインデックスを渡す nth= ロケーターを使用して、クエリを n 番目のマッチに絞り込むことができます。
- 同期
- 非同期
# Click first button
page.locator("button").locator("nth=0").click()
# Click last button
page.locator("button").locator("nth=-1").click()
# Click first button
await page.locator("button").locator("nth=0").click()
# Click last button
await page.locator("button").locator("nth=-1").click()
親要素ロケーター
他の要素の親要素をターゲットにする必要がある場合、ほとんどの場合、子ロケーターでlocator.filter()を使用する必要があります。例えば、次の DOM 構造を考えてみましょう。
<li><label>Hello</label></li>
<li><label>World</label></li>
「Hello」というテキストを持つラベルの親 <li> をターゲットにしたい場合、locator.filter() を使用するのが最適です。
- 同期
- 非同期
child = page.get_by_text("Hello")
parent = page.get_by_role("listitem").filter(has=child)
child = page.get_by_text("Hello")
parent = page.get_by_role("listitem").filter(has=child)
または、親要素の適切なロケーターが見つからない場合は、xpath=.. を使用してください。ただし、この方法は DOM 構造の変更によってテストが壊れる可能性があるため、信頼性が低いことに注意してください。可能な場合はlocator.filter()を優先してください。
- 同期
- 非同期
parent = page.get_by_text("Hello").locator('xpath=..')
parent = page.get_by_text("Hello").locator('xpath=..')
React ロケーター
React ロケーターは実験的であり、_ をプレフィックスとしています。機能は将来変更される可能性があります。
React ロケーターは、コンポーネント名とプロパティ値で要素を見つけることができます。構文はCSS 属性セレクターと非常に似ており、すべての CSS 属性セレクター演算子をサポートしています。
React ロケーターでは、コンポーネント名は**キャメルケース**で表記されます。
- 同期
- 非同期
page.locator("_react=BookItem").click()
await page.locator("_react=BookItem").click()
その他の例
- **コンポーネント**でマッチング:
_react=BookItem - コンポーネントと**正確なプロパティ値**(大文字と小文字を区別)でマッチング:
_react=BookItem[author = "Steven King"] - プロパティ値のみでマッチング、**大文字と小文字を区別しない**:
_react=[author = "steven king" i] - コンポーネントと**truthy プロパティ値**でマッチング:
_react=MyButton[enabled] - コンポーネントと**真偽値**でマッチング:
_react=MyButton[enabled = false] - プロパティ**値の部分文字列**でマッチング:
_react=[author *= "King"] - コンポーネントと**複数のプロパティ**でマッチング:
_react=BookItem[author *= "king" i][year = 1990] - **ネストされた**プロパティ値でマッチング:
_react=[some.nested.value = 12] - コンポーネントとプロパティ値の**プレフィックス**でマッチング:
_react=BookItem[author ^= "Steven"] - コンポーネントとプロパティ値の**サフィックス**でマッチング:
_react=BookItem[author $= "Steven"] - コンポーネントと**キー**でマッチング:
_react=BookItem[key = '2'] - プロパティ値の**正規表現**でマッチング:
_react=[author = /Steven(\\s+King)?/i]
ツリー内の React 要素名を見つけるには、React DevTools を使用してください。
React ロケーターは React 15 以降をサポートしています。
React ロケーターは、React DevTools と同様に、**ミニファイされていない**アプリケーションビルドに対してのみ機能します。
Vue ロケーター
Vue ロケーターは実験的であり、_ をプレフィックスとしています。機能は将来変更される可能性があります。
Vue ロケーターは、コンポーネント名とプロパティ値で要素を見つけることができます。構文はCSS 属性セレクターと非常に似ており、すべての CSS 属性セレクター演算子をサポートしています。
Vue ロケーターでは、コンポーネント名は**ケバブケース**で表記されます。
- 同期
- 非同期
page.locator("_vue=book-item").click()
await page.locator("_vue=book-item").click()
その他の例
- **コンポーネント**でマッチング:
_vue=book-item - コンポーネントと**正確なプロパティ値**(大文字と小文字を区別)でマッチング:
_vue=book-item[author = "Steven King"] - プロパティ値のみでマッチング、**大文字と小文字を区別しない**:
_vue=[author = "steven king" i] - コンポーネントと**truthy プロパティ値**でマッチング:
_vue=my-button[enabled] - コンポーネントと**真偽値**でマッチング:
_vue=my-button[enabled = false] - プロパティ**値の部分文字列**でマッチング:
_vue=[author *= "King"] - コンポーネントと**複数のプロパティ**でマッチング:
_vue=book-item[author *= "king" i][year = 1990] - **ネストされた**プロパティ値でマッチング:
_vue=[some.nested.value = 12] - コンポーネントとプロパティ値の**プレフィックス**でマッチング:
_vue=book-item[author ^= "Steven"] - コンポーネントとプロパティ値の**サフィックス**でマッチング:
_vue=book-item[author $= "Steven"] - プロパティ値の**正規表現**でマッチング:
_vue=[author = /Steven(\\s+King)?/i]
ツリー内の Vue 要素名を見つけるには、Vue DevTools を使用してください。
Vue ロケーターは Vue2 以降をサポートしています。
Vue ロケーターは、Vue DevTools と同様に、**ミニファイされていない**アプリケーションビルドに対してのみ機能します。
XPath ロケーター
実装に依存し、ページが変更されたときに簡単に壊れる可能性がある XPath を使用する代わりに、テキストやアクセシブルなロールのようなユーザーに表示されるロケーターを優先することをお勧めします。
XPath ロケーターは Document.evaluate の呼び出しと同等です。
- 同期
- 非同期
page.locator("xpath=//button").click()
await page.locator("xpath=//button").click()
// または .. で始まるセレクター文字列はすべて xpath セレクターであると見なされます。例えば、Playwright は '//html/body' を 'xpath=//html/body' に変換します。
XPath はシャドウルートを貫通しません。
XPath ユニオン
パイプ演算子 (|) を使用して XPath で複数のセレクターを指定できます。これは、そのリスト内のいずれかのセレクターで選択できるすべての要素にマッチします。
- 同期
- 非同期
# Waits for either confirmation dialog or load spinner.
page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").wait_for()
# Waits for either confirmation dialog or load spinner.
await page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").wait_for()
ラベルからフォームコントロールへの再ターゲット
ラベルからコントロールへの再ターゲットに依存するのではなく、ラベルテキストによる特定を推奨します。
Playwright のターゲット入力アクションは、ラベルとコントロールを自動的に区別するため、関連するコントロールに対してアクションを実行するためにラベルをターゲットにすることができます。
例えば、次の DOM 構造を考えてみましょう: <label for="password">Password:</label><input id="password" type="password">。「Password」というテキストを使用してpage.get_by_text()でラベルをターゲットにすることができます。ただし、次のアクションはラベルではなく入力に対して実行されます。
- locator.click() はラベルをクリックし、自動的に入力フィールドにフォーカスを合わせます。
- locator.fill() は入力フィールドに入力します。
- locator.input_value() は入力フィールドの値を返します。
- locator.select_text() は入力フィールドのテキストを選択します。
- locator.set_input_files() は
type=fileの入力フィールドにファイルをセットします。 - locator.select_option() はセレクトボックスからオプションを選択します。
- 同期
- 非同期
# Fill the input by targeting the label.
page.get_by_text("Password").fill("secret")
# Fill the input by targeting the label.
await page.get_by_text("Password").fill("secret")
ただし、その他のメソッドはラベル自体をターゲットにします。例えば、expect(locator).to_have_text() は、入力フィールドではなくラベルのテキストコンテンツをアサートします。
- 同期
- 非同期
# Fill the input by targeting the label.
expect(page.locator("label")).to_have_text("Password")
# Fill the input by targeting the label.
await expect(page.locator("label")).to_have_text("Password")
レガシーテキストロケーター
代わりに、最新のテキストロケーターを推奨します。
レガシーテキストロケーターは、渡されたテキストを含む要素にマッチします。
- 同期
- 非同期
page.locator("text=Log in").click()
await page.locator("text=Log in").click()
レガシーテキストロケーターにはいくつかのバリエーションがあります。
-
text=Log in- デフォルトのマッチングでは大文字と小文字を区別せず、空白をトリムし、部分文字列を検索します。例えば、text=Logは<button>Log in</button>にマッチします。- 同期
- 非同期
page.locator("text=Log in").click()await page.locator("text=Log in").click() -
text="Log in"- テキスト本体は、空白をトリムした後の正確なコンテンツを持つテキストノードを検索するために、シングルクォートまたはダブルクォートでエスケープできます。例えば、
text="Log"は<button>Log in</button>にマッチしません。なぜなら、<button>には"Log in"という単一のテキストノードが含まれており、それが"Log"と等しくないからです。しかし、text="Log"は<button> Log <span>in</span></button>にマッチします。なぜなら、<button>には" Log "というテキストノードが含まれているからです。この厳密なモードは大文字と小文字を区別するマッチングを意味するため、text="Download"は<button>download</button>にマッチしません。引用符で囲まれた本体は通常のエスケープルールに従います。例えば、ダブルクォート文字列内のダブルクォートをエスケープするには
\"を使用します:text="foo\"bar"。- 同期
- 非同期
page.locator("text='Log in'").click()await page.locator("text='Log in'").click() -
/Log\s*in/i- 本体は/記号で囲まれたJavaScript のような正規表現にできます。例えば、text=/Log\s*in/iは<button>Login</button>と<button>log IN</button>にマッチします。- 同期
- 非同期
page.locator("text=/Log\s*in/i").click()await page.locator("text=/Log\s*in/i").click()
引用符(" または ')で始まり終わる文字列セレクターは、レガシーテキストロケーターであると見なされます。例えば、"Log in" は内部的に text="Log in" に変換されます。
マッチングは常に空白を正規化します。例えば、複数のスペースを1つにまとめ、改行をスペースに変換し、前後の空白を無視します。
button および submit 型の入力要素は、テキストコンテンツではなく value でマッチングされます。例えば、text=Log in は <input type=button value="Log in"> にマッチします。
id、data-testid、data-test-id、data-test セレクター
代わりにテスト ID による特定を推奨します。
Playwright は、特定の属性を使用して要素を選択するための短縮形をサポートしています。現在、以下の属性のみがサポートされています。
iddata-testiddata-test-iddata-test
- 同期
- 非同期
# Fill an input with the id "username"
page.locator('id=username').fill('value')
# Click an element with data-test-id "submit"
page.locator('data-test-id=submit').click()
# Fill an input with the id "username"
await page.locator('id=username').fill('value')
# Click an element with data-test-id "submit"
await page.locator('data-test-id=submit').click()
属性セレクターは CSS セレクターではないため、:enabled のような CSS 固有のものはサポートされていません。より多くの機能については、適切なCSSセレクターを使用してください。例: css=[data-test="login"]:enabled。
セレクターの連結
代わりにロケーターの連結を推奨します。
engine=body または短縮形式で定義されたセレクターは、>> トークンと組み合わせることができます。例: selector1 >> selector2 >> selectors3。セレクターが連結されている場合、次のセレクターは前のセレクターの結果に対してクエリされます。
例えば、
css=article >> css=.bar > .baz >> css=span[attr=value]
は以下と同等です
document
.querySelector('article')
.querySelector('.bar > .baz')
.querySelector('span[attr=value]');
セレクターが本体に >> を含める必要がある場合は、連結セパレーターと混同されないように文字列内でエスケープする必要があります。例: text="some >> text"。
中間マッチ
他の要素を含む要素を特定するには、別のロケーターでフィルタリングすることを推奨します。
デフォルトでは、連結されたセレクターは最後のセレクターによってクエリされた要素に解決されます。セレクターに * をプレフィックスとして追加することで、中間セレクターによってクエリされた要素をキャプチャできます。
例えば、css=article >> text=Hello はテキスト Hello を持つ要素をキャプチャし、*css=article >> text=Hello (* に注目) はテキスト Hello を持つ要素を含む article 要素をキャプチャします。