メインコンテンツへスキップ

ロケーター

はじめに

ロケーターは、Playwright の自動待機とリトライ機能の中核となるものです。一言で言えば、ロケーターは、任意の瞬間にページ上の要素を見つけるための方法を表します。

クイックガイド

これらは、推奨される組み込みロケーターです。

  • page.get_by_role():明示的および暗黙的なアクセシビリティ属性によって特定します。
  • page.get_by_text():テキストコンテンツによって特定します。
  • page.get_by_label():関連付けられたラベルのテキストによってフォームコントロールを特定します。
  • page.get_by_placeholder():プレースホルダーによって入力を特定します。
  • page.get_by_alt_text():要素(通常は画像)を代替テキストによって特定します。
  • page.get_by_title():要素をタイトル属性によって特定します。
  • page.get_by_test_id():要素を data-testid 属性に基づいて特定します(他の属性も設定可能です)。
page.get_by_label("User Name").fill("John")

page.get_by_label("Password").fill("secret-password")

page.get_by_role("button", name="Sign in").click()

expect(page.get_by_text("Welcome, John!")).to_be_visible()

要素の特定

Playwright には、複数の組み込みロケーターが付属しています。テストの耐性を高めるために、ユーザー向けの属性と、page.get_by_role() などの明示的なコントラクトを優先することをお勧めします。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
<button>Sign in</button>

ロールが button で名前が「サインイン」の要素を特定します。

page.get_by_role("button", name="Sign in").click()

コードジェネレーターを使用してロケーターを生成し、必要に応じて編集します。

ロケーターがアクションに使用されるたびに、最新の DOM 要素がページ内で特定されます。以下のスニペットでは、基になる DOM 要素は、各アクションの前に 2 回特定されます。これは、DOM が再レンダリングにより呼び出しの間に変更された場合、ロケーターに対応する新しい要素が使用されることを意味します。

locator = page.get_by_role("button", name="Sign in")

locator.hover()
locator.click()

page.get_by_label() などのロケーターを作成するすべてのメソッドは、ロケーターおよびFrameLocatorクラスでも利用できるため、それらをチェーンしてロケーターを反復的に絞り込むことができます。

locator = page.frame_locator("my-frame").get_by_role("button", name="Sign in")

locator.click()

ロールによる特定

page.get_by_role() ロケーターは、ユーザーと支援技術がページをどのように認識するかを反映しています。たとえば、要素がボタンであるかチェックボックスであるかなどです。ロールで特定する場合は、通常、アクセシブルな名前も渡して、ロケーターが正確な要素を特定するようにする必要があります。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000

サインアップ

<h3>Sign up</h3>
<label>
<input type="checkbox" /> Subscribe
</label>
<br/>
<button>Submit</button>

各要素を暗黙的なロールで特定できます

expect(page.get_by_role("heading", name="Sign up")).to_be_visible()

page.get_by_role("checkbox", name="Subscribe").check()

page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()

ロールロケーターには、ボタン、チェックボックス、見出し、リンク、リスト、テーブルなど多数が含まれており、ARIA ロールARIA 属性、およびアクセシブルな名前に関する W3C 仕様に従っています。<button> などの多くの HTML 要素には、ロールロケーターによって認識される暗黙的に定義されたロールがあることに注意してください。

ロールロケーターは、アクセシビリティ監査および適合性テストを置き換えるものではありませんが、ARIA ガイドラインに関する早期フィードバックを提供します。

ロールロケーターを使用する場合

要素を特定するには、ロールロケーターを優先することをお勧めします。これは、ユーザーと支援技術がページを認識する方法に最も近い方法だからです。

ラベルによる特定

ほとんどのフォームコントロールには、通常、フォームの操作に便利に使用できる専用のラベルがあります。この場合、page.get_by_label() を使用して、関連付けられたラベルでコントロールを特定できます。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
<label>Password <input type="password" /></label>

ラベルテキストで特定した後、入力を入力できます

page.get_by_label("Password").fill("secret")
ラベルロケーターを使用する場合

フォームフィールドを特定する場合は、このロケーターを使用します。

プレースホルダーによる特定

入力には、ユーザーに入力すべき値をヒントするためのプレースホルダー属性がある場合があります。page.get_by_placeholder() を使用して、そのような入力を特定できます。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
<input type="email" placeholder="name@example.com" />

プレースホルダーテキストで特定した後、入力を入力できます

page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
プレースホルダーロケーターを使用する場合

ラベルはないがプレースホルダーテキストがあるフォーム要素を特定する場合は、このロケーターを使用します。

テキストによる特定

要素に含まれるテキストで要素を見つけます。page.get_by_text() を使用すると、部分文字列、完全一致文字列、または正規表現で一致させることができます。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
ようこそ、ジョン
<span>Welcome, John</span>

要素に含まれるテキストで要素を特定できます

expect(page.get_by_text("Welcome, John")).to_be_visible()

完全一致を設定する

expect(page.get_by_text("Welcome, John", exact=True)).to_be_visible()

正規表現で一致させる

expect(page.get_by_text(re.compile("welcome, john", re.IGNORECASE))).to_be_visible()

テキストによるマッチングは、完全一致であっても常に空白を正規化します。たとえば、複数のスペースを 1 つのスペースに変換したり、改行をスペースに変換したり、先頭と末尾の空白を無視したりします。

テキストロケーターを使用する場合

テキストロケーターは、divspanp などの非インタラクティブな要素を見つけるために使用することをお勧めします。buttonainput などのインタラクティブな要素の場合は、ロールロケーターを使用してください。

テキストでフィルタリングすることもできます。これは、リスト内の特定の項目を見つけようとする場合に役立ちます。

代替テキストによる特定

すべての画像には、画像を説明する alt 属性が必要です。page.get_by_alt_text() を使用して、代替テキストに基づいて画像を特定できます。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
playwright logo
<img alt="playwright logo" src="/img/playwright-logo.svg" width="100" />

代替テキストで特定した後、画像をクリックできます

page.get_by_alt_text("playwright logo").click()
代替ロケーターを使用する場合

img 要素や area 要素など、要素が代替テキストをサポートしている場合は、このロケーターを使用します。

タイトルによる特定

page.get_by_title() を使用して、一致するタイトル属性を持つ要素を特定します。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
25 件の問題
<span title='Issues count'>25 issues</span>

タイトルテキストで特定した後、問題の数を確認できます

expect(page.get_by_title("Issues count")).to_have_text("25 issues")
タイトルロケーターを使用する場合

要素に title 属性がある場合は、このロケーターを使用します。

テスト ID による特定

テスト ID によるテストは、最も耐性のあるテスト方法です。テキストや属性のロールが変更されても、テストは引き続き成功します。QA および開発者は、明示的なテスト ID を定義し、page.get_by_test_id() でクエリする必要があります。ただし、テスト ID によるテストはユーザー向けではありません。ロールまたはテキストの値が重要な場合は、ロールテキストロケーターなどのユーザー向けロケーターの使用を検討してください。

たとえば、次の DOM 構造を考えてみましょう。

http://localhost:3000
<button data-testid="directions">Itinéraire</button>

テスト ID で要素を特定できます

page.get_by_test_id("directions").click()
テスト ID ロケーターを使用する場合

テスト ID 手法を使用することを選択した場合、またはロールまたはテキストで特定できない場合にも、テスト ID を使用できます。

カスタムテスト ID 属性の設定

デフォルトでは、page.get_by_test_id()data-testid 属性に基づいて要素を特定しますが、テスト構成で設定するか、selectors.set_test_id_attribute() を呼び出すことで設定できます。

テストで使用するカスタムデータ属性にテスト ID を設定します。

playwright.selectors.set_test_id_attribute("data-pw")

HTML で、デフォルトの data-testid の代わりに data-pw をテスト ID として使用できるようになりました。

http://localhost:3000
<button data-pw="directions">Itinéraire</button>

そして、通常どおりに要素を特定します

page.get_by_test_id("directions").click()

CSS または XPath による特定

CSS ロケーターまたは XPath ロケーターをどうしても使用する必要がある場合は、page.locator() を使用して、ページ内の要素を見つける方法を記述するセレクターを受け取るロケーターを作成できます。Playwright は CSS セレクターと XPath セレクターをサポートしており、css= または xpath= プレフィックスを省略すると自動検出します。

page.locator("css=button").click()
page.locator("xpath=//button").click()

page.locator("button").click()
page.locator("//button").click()

XPath セレクターと CSS セレクターは、DOM 構造または実装に結び付けることができます。これらのセレクターは、DOM 構造が変更されると壊れる可能性があります。以下の長い CSS チェーンまたは XPath チェーンは、不安定なテストにつながる悪い例です。

page.locator(
"#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input"
).click()

page.locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input').click()
これを使用する場合

DOM は頻繁に変更される可能性があるため、CSS と XPath は推奨されず、耐性のないテストにつながります。代わりに、ロールロケーターなど、ユーザーがページを認識する方法に近いロケーターを考案するか、テスト ID を使用して明示的なテストコントラクトを定義してみてください。

シャドウ DOM 内での特定

Playwright のすべてのロケーターは、デフォルトでシャドウ DOM 内の要素で動作します。例外は次のとおりです。

カスタム Web コンポーネントの次の例を考えてみましょう

<x-details role=button aria-expanded=true aria-controls=inner-details>
<div>Title</div>
#shadow-root
<div id=inner-details>Details</div>
</x-details>

シャドウルートが存在しない場合と同じように特定できます。

<div>Details</div> をクリックするには

page.get_by_text("Details").click()
<x-details role=button aria-expanded=true aria-controls=inner-details>
<div>Title</div>
#shadow-root
<div id=inner-details>Details</div>
</x-details>

<x-details> をクリックするには

page.locator("x-details", has_text="Details").click()
<x-details role=button aria-expanded=true aria-controls=inner-details>
<div>Title</div>
#shadow-root
<div id=inner-details>Details</div>
</x-details>

<x-details> にテキスト「Details」が含まれていることを確認するには

expect(page.locator("x-details")).to_contain_text("Details")

ロケーターのフィルタリング

2 番目の製品カードの「購入」ボタンをクリックしたい DOM 構造を考えてみましょう。適切なロケーターを取得するためにロケーターをフィルタリングするには、いくつかのオプションがあります。

http://localhost:3000
  • 製品 1

  • 製品 2

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

テキストでフィルタリング

ロケーターは、locator.filter() メソッドを使用してテキストでフィルタリングできます。要素内のどこか、おそらく子孫要素に特定の文字列を大文字と小文字を区別せずに検索します。正規表現を渡すこともできます。

page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
"button", name="Add to cart"
).click()

正規表現を使用する

page.get_by_role("listitem").filter(has_text=re.compile("Product 2")).get_by_role(
"button", name="Add to cart"
).click()

テキストがないことでフィルタリング

または、テキストを持たないことでフィルタリングします

# 5 in-stock items
expect(page.get_by_role("listitem").filter(has_not_text="Out of stock")).to_have_count(5)

子/子孫によるフィルタリング

ロケーターは、別のロケーターに一致する子孫を持つ要素または持たない要素のみを選択するオプションをサポートしています。したがって、locator.get_by_role()locator.get_by_test_id()locator.get_by_text() などの他のロケーターでフィルタリングできます。

http://localhost:3000
  • 製品 1

  • 製品 2

<ul>
<li>
<h3>Product 1</h3>
<button>Add to cart</button>
</li>
<li>
<h3>Product 2</h3>
<button>Add to cart</button>
</li>
</ul>
page.get_by_role("listitem").filter(
has=page.get_by_role("heading", name="Product 2")
).get_by_role("button", name="Add to cart").click()

製品カードをアサートして、製品カードが 1 つしかないことを確認することもできます

expect(
page.get_by_role("listitem").filter(
has=page.get_by_role("heading", name="Product 2")
)
).to_have_count(1)

フィルタリングロケーターは、元のロケーターに相対的である必要があり、ドキュメントルートではなく、元のロケーターの一致からクエリが開始されます。したがって、フィルタリングロケーターが元のロケーターによって一致した <li> リスト項目の外側にある <ul> リスト要素から一致を開始するため、以下は機能しません。

# ✖ WRONG
expect(
page.get_by_role("listitem").filter(
has=page.get_by_role("list").get_by_role("heading", name="Product 2")
)
).to_have_count(1)

子/子孫を持たないことでフィルタリング

内部に一致する要素を持たないことでフィルタリングすることもできます。

expect(
page.get_by_role("listitem").filter(
has_not=page.get_by_role("heading", name="Product 2")
)
).to_have_count(1)

内部ロケーターは、ドキュメントルートからではなく、外部ロケーターから一致が開始されることに注意してください。

ロケーター演算子

ロケーター内でのマッチング

page.get_by_text()locator.get_by_role() などのロケーターを作成するメソッドをチェーンして、検索をページの特定の部分に絞り込むことができます。

この例では、最初にロールが listitem のロケーター product を作成します。次に、テキストでフィルタリングします。product ロケーターを再度使用して、ロールが button の要素を取得してクリックし、アサーションを使用してテキスト「製品 2」を持つ製品が 1 つしかないことを確認できます。

product = page.get_by_role("listitem").filter(has_text="Product 2")

product.get_by_role("button", name="Add to cart").click()

2 つのロケーターをチェーンすることもできます。たとえば、特定のダイアログ内の「保存」ボタンを見つける場合などです。

save_button = page.get_by_role("button", name="Save")
# ...
dialog = page.get_by_test_id("settings-dialog")
dialog.locator(save_button).click()

2 つのロケーターを同時にマッチング

locator.and_() メソッドは、追加のロケーターをマッチングすることで、既存のロケーターを絞り込みます。たとえば、page.get_by_role()page.get_by_title() を組み合わせて、ロールとタイトルの両方でマッチングできます。

button = page.get_by_role("button").and_(page.getByTitle("Subscribe"))

2 つの代替ロケーターのいずれかをマッチング

2 つ以上の要素のいずれかをターゲットにしたいが、どちらになるかわからない場合は、locator.or_() を使用して、いずれかまたは両方の代替に一致するロケーターを作成します。

たとえば、「新しいメール」ボタンをクリックしたいが、代わりにセキュリティ設定ダイアログが表示されるシナリオを考えてみましょう。この場合、「新しいメール」ボタンまたはダイアログのいずれかを待機し、それに応じて対応できます。

「新しいメール」ボタンとセキュリティダイアログの両方が画面に表示される場合、「or」ロケーターは両方に一致する可能性があり、「厳密モード違反」エラーが発生する可能性があります。この場合、locator.first を使用して、いずれか 1 つだけを一致させることができます。

new_email = page.get_by_role("button", name="New")
dialog = page.get_by_text("Confirm security settings")
expect(new_email.or_(dialog).first).to_be_visible()
if (dialog.is_visible()):
page.get_by_role("button", name="Dismiss").click()
new_email.click()

可視要素のみをマッチング

可視性を確認する代わりに、要素を一意に識別するより信頼性の高い方法を見つける方が通常は優れています。

2 つのボタンがあるページを考えてみましょう。1 つ目は非表示で、2 つ目は表示されています。

<button style='display: none'>Invisible</button>
<button>Visible</button>
  • これは両方のボタンを見つけ、厳密性違反エラーをスローします

    page.locator("button").click()
  • これは、2 番目のボタンのみを見つけてクリックします。なぜなら、2 番目のボタンは表示されているからです。

    page.locator("button").filter(visible=True).click()

リスト

リスト内の項目数を数える

リスト内の項目数を数えるためにロケーターをアサートできます。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • りんご
  • バナナ
  • オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>

リストに 3 つの項目があることを確認するには、カウントアサーションを使用します。

expect(page.get_by_role("listitem")).to_have_count(3)

リスト内のすべてのテキストをアサートする

リスト内のすべてのテキストを見つけるためにロケーターをアサートできます。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • りんご
  • バナナ
  • オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>

expect(locator).to_have_text() を使用して、リストにテキスト「りんご」、「バナナ」、「オレンジ」があることを確認します。

expect(page.get_by_role("listitem")).to_have_text(["apple", "banana", "orange"])

特定の項目を取得する

リスト内の特定の項目を取得する方法はたくさんあります。

テキストで取得

page.get_by_text() メソッドを使用して、リスト内の要素をテキストコンテンツで特定し、クリックします。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • りんご
  • バナナ
  • オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>

テキストコンテンツで項目を特定してクリックします。

page.get_by_text("orange").click()

テキストでフィルタリング

locator.filter() を使用して、リスト内の特定の項目を特定します。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • りんご
  • バナナ
  • オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>

「listitem」のロールで項目を特定し、「オレンジ」のテキストでフィルタリングしてクリックします。

page.get_by_role("listitem").filter(has_text="orange").click()

テスト ID で取得

page.get_by_test_id() メソッドを使用して、リスト内の要素を特定します。テスト ID がまだない場合は、HTML を変更してテスト ID を追加する必要がある場合があります。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • りんご
  • バナナ
  • オレンジ
<ul>
<li data-testid='apple'>apple</li>
<li data-testid='banana'>banana</li>
<li data-testid='orange'>orange</li>
</ul>

「オレンジ」のテスト ID で項目を特定してクリックします。

page.get_by_test_id("orange").click()

n 番目の項目で取得

同一の要素のリストがあり、それらを区別する唯一の方法が順序である場合は、リストから特定の要素を locator.firstlocator.last、または locator.nth() で選択できます。

banana = page.get_by_role("listitem").nth(1)

ただし、このメソッドは注意して使用してください。多くの場合、ページが変更され、ロケーターが意図した要素とはまったく異なる要素を指す可能性があります。代わりに、厳密性基準に合格する一意のロケーターを考案してみてください。

フィルターのチェーン

さまざまな類似点を持つ要素がある場合は、locator.filter() メソッドを使用して適切な要素を選択できます。複数のフィルターをチェーンして選択範囲を絞り込むこともできます。

たとえば、次の DOM 構造を考えてみましょう

http://localhost:3000
  • ジョン
  • メアリー
  • ジョン
  • メアリー
<ul>
<li>
<div>John</div>
<div><button>Say hello</button></div>
</li>
<li>
<div>Mary</div>
<div><button>Say hello</button></div>
</li>
<li>
<div>John</div>
<div><button>Say goodbye</button></div>
</li>
<li>
<div>Mary</div>
<div><button>Say goodbye</button></div>
</li>
</ul>

「メアリー」と「さようならと言う」の行のスクリーンショットを撮るには

row_locator = page.get_by_role("listitem")

row_locator.filter(has_text="Mary").filter(
has=page.get_by_role("button", name="Say goodbye")
).screenshot(path="screenshot.png")

これで、プロジェクトのルートディレクトリに「screenshot.png」ファイルが作成されたはずです。

まれなユースケース

リスト内の各要素で何かを行う

要素を反復処理する

for row in page.get_by_role("listitem").all():
print(row.text_content())

通常の for ループを使用して反復処理する

rows = page.get_by_role("listitem")
count = rows.count()
for i in range(count):
print(rows.nth(i).text_content())

ページ内で評価する

locator.evaluate_all() 内のコードはページ内で実行され、そこで任意の DOM API を呼び出すことができます。

rows = page.get_by_role("listitem")
texts = rows.evaluate_all("list => list.map(element => element.textContent)")

厳密性

ロケーターは厳密です。これは、ターゲット DOM 要素を意味するロケーターに対するすべての操作は、複数の要素が一致した場合に例外をスローすることを意味します。たとえば、次の呼び出しは、DOM に複数のボタンがある場合にスローされます。

複数あるとエラーをスローする

page.get_by_role("button").click()

一方、Playwright は、複数要素操作を実行する場合を理解しているため、ロケーターが複数の要素に解決される場合、次の呼び出しは完全に正常に機能します。

複数の要素で正常に機能する

page.get_by_role("button").count()

locator.firstlocator.last、および locator.nth() を使用して、複数の要素が一致した場合に使用する要素を Playwright に指示することで、厳密性チェックから明示的にオプトアウトできます。これらのメソッドは、ページが変更されたときに、Playwright が意図していない要素をクリックする可能性があるため、推奨されません。代わりに、上記のベストプラクティスに従って、ターゲット要素を一意に識別するロケーターを作成してください。

その他のロケーター

あまり一般的でないロケーターについては、その他のロケーターガイドをご覧ください。