ロケーター
はじめに
ロケーターは、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() は、要素をその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()
await page.get_by_label("User Name").fill("John")
await page.get_by_label("Password").fill("secret-password")
await page.get_by_role("button", name="Sign in").click()
await expect(page.get_by_text("Welcome, John!")).to_be_visible()
要素の特定
Playwrightには複数の組み込みロケーターが用意されています。テストの回復力を高めるために、page.get_by_role()のようなユーザーが操作する属性や明示的な契約を優先することをお勧めします。
例えば、以下のDOM構造を考えてみましょう。
<button>Sign in</button>
「Sign in」という名前のbutton
ロールを持つ要素を特定します。
- 同期
- 非同期
page.get_by_role("button", name="Sign in").click()
await 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()
locator = page.get_by_role("button", name="Sign in")
await locator.hover()
await locator.click()
page.get_by_label()のようなロケーターを作成するすべてのメソッドは、LocatorクラスとFrameLocatorクラスでも利用できるため、それらを連結してロケーターを段階的に絞り込むことができます。
- 同期
- 非同期
locator = page.frame_locator("my-frame").get_by_role("button", name="Sign in")
locator.click()
locator = page.frame_locator("#my-frame").get_by_role("button", name="Sign in")
await locator.click()
ロールによる特定
page.get_by_role()ロケーターは、ユーザーや支援技術がページをどのように認識するかを反映しています。例えば、ある要素がボタンなのかチェックボックスなのかなどです。ロールで特定する場合、通常はアクセシブルネームも渡して、ロケーターが正確な要素を特定できるようにする必要があります。
例えば、以下のDOM構造を考えてみましょう。
サインアップ
<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()
await expect(page.get_by_role("heading", name="Sign up")).to_be_visible()
await page.get_by_role("checkbox", name="Subscribe").check()
await page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()
ロールロケーターには、ボタン、チェックボックス、見出し、リンク、リスト、テーブルなどが含まれ、ARIAロール、ARIA属性、アクセシブルネームに関するW3Cの仕様に準拠しています。<button>
のような多くのHTML要素には、暗黙的に定義されたロールがあり、ロールロケーターによって認識されることに注意してください。
ロールロケーターはアクセシビリティ監査や適合性テストを**置き換えるものではない**ことに注意してください。むしろ、ARIAガイドラインに関する初期のフィードバックを提供します。
要素を特定するには、ロールロケーターを優先することをお勧めします。これは、ユーザーや支援技術がページを認識する方法に最も近いからです。
ラベルによる特定
ほとんどのフォームコントロールには通常、フォームとの対話に便利に使用できる専用のラベルがあります。この場合、page.get_by_label()を使用して、関連付けられたラベルによってコントロールを特定できます。
例えば、以下のDOM構造を考えてみましょう。
<label>Password <input type="password" /></label>
ラベルテキストで入力要素を特定した後、その内容を入力できます
- 同期
- 非同期
page.get_by_label("Password").fill("secret")
await page.get_by_label("Password").fill("secret")
フォームフィールドを特定する際にこのロケーターを使用します。
プレースホルダーによる特定
入力要素には、ユーザーに入力すべき値のヒントを与えるプレースホルダー属性がある場合があります。このような入力要素は、page.get_by_placeholder()を使用して特定できます。
例えば、以下のDOM構造を考えてみましょう。
<input type="email" placeholder="name@example.com" />
プレースホルダーテキストで入力要素を特定した後、その内容を入力できます
- 同期
- 非同期
page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
await page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
ラベルはないがプレースホルダーテキストがあるフォーム要素を特定する際に、このロケーターを使用します。
テキストによる特定
要素が含むテキストで要素を見つけます。page.get_by_text()を使用する場合、部分文字列、完全一致文字列、または正規表現で一致させることができます。
例えば、以下のDOM構造を考えてみましょう。
<span>Welcome, John</span>
要素が含むテキストで特定できます
- 同期
- 非同期
expect(page.get_by_text("Welcome, John")).to_be_visible()
await expect(page.get_by_text("Welcome, John")).to_be_visible()
完全一致を設定
- 同期
- 非同期
expect(page.get_by_text("Welcome, John", exact=True)).to_be_visible()
await 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()
await expect(
page.get_by_text(re.compile("welcome, john", re.IGNORECASE))
).to_be_visible()
テキストによる一致は、完全一致であっても常に空白を正規化します。例えば、複数のスペースを1つに、改行をスペースに変換し、先頭と末尾の空白を無視します。
div
、span
、p
などの非インタラクティブ要素を見つけるには、テキストロケーターを使用することをお勧めします。button
、a
、input
などのインタラクティブ要素には、ロールロケーターを使用してください。
リスト内の特定の項目を見つけようとする際に便利なテキストによるフィルタリングも可能です。
altテキストによる特定
すべての画像には、画像を説明するalt
属性が必要です。page.get_by_alt_text()を使用して、代替テキストに基づいて画像を特定できます。
例えば、以下のDOM構造を考えてみましょう。
<img alt="playwright logo" src="/img/playwright-logo.svg" width="100" />
代替テキストで画像を特定した後、その画像をクリックできます
- 同期
- 非同期
page.get_by_alt_text("playwright logo").click()
await page.get_by_alt_text("playwright logo").click()
img
やarea
要素のように、altテキストをサポートする要素を特定する際にこのロケーターを使用します。
titleによる特定
page.get_by_title()を使用して、一致するtitle属性を持つ要素を特定します。
例えば、以下のDOM構造を考えてみましょう。
<span title='Issues count'>25 issues</span>
titleテキストで特定した後、issueの数をチェックできます
- 同期
- 非同期
expect(page.get_by_title("Issues count")).to_have_text("25 issues")
await expect(page.get_by_title("Issues count")).to_have_text("25 issues")
要素にtitle
属性がある場合にこのロケーターを使用します。
テストIDによる特定
テストIDによるテストは、属性のテキストやロールが変更されてもテストがパスするため、最も回復力のあるテスト方法です。QAと開発者は、明示的なテストIDを定義し、page.get_by_test_id()でそれらをクエリすべきです。ただし、テストIDによるテストはユーザーには見えません。ロールやテキストロケーターが重要な場合は、ユーザーが操作するロケーターの使用を検討してください。
例えば、以下のDOM構造を考えてみましょう。
<button data-testid="directions">Itinéraire</button>
テストIDで要素を特定できます
- 同期
- 非同期
page.get_by_test_id("directions").click()
await page.get_by_test_id("directions").click()
カスタムテストID属性の設定
デフォルトでは、page.get_by_test_id()はdata-testid
属性に基づいて要素を特定しますが、テスト設定で構成するか、selectors.set_test_id_attribute()を呼び出すことで設定できます。
テストIDを設定して、テスト用のカスタムデータ属性を使用します。
- 同期
- 非同期
playwright.selectors.set_test_id_attribute("data-pw")
playwright.selectors.set_test_id_attribute("data-pw")
これでHTMLで、デフォルトのdata-testid
の代わりにdata-pw
をテストIDとして使用できるようになります。
<button data-pw="directions">Itinéraire</button>
そして通常通り要素を特定します
- 同期
- 非同期
page.get_by_test_id("directions").click()
await 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()
await page.locator("css=button").click()
await page.locator("xpath=//button").click()
await page.locator("button").click()
await 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()
await page.locator(
"#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input"
).click()
await page.locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input').click()
DOMは頻繁に変更される可能性があり、テストの回復力を低下させるため、CSSとXPathは推奨されません。代わりに、ロールロケーターやテストIDを使用した明示的なテスト契約の定義など、ユーザーがページを認識する方法に近いロケーターを考案するようにしてください。
Shadow DOMでの特定
Playwrightのすべてのロケーターは、**デフォルトで**Shadow DOM内の要素と連携します。例外は以下の通りです。
- XPathによる特定はシャドウルートを透過しません。
- クローズドモードのシャドウルートはサポートされていません。
カスタム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()
await 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()
await 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")
await expect(page.locator("x-details")).to_contain_text("Details")
ロケーターのフィルタリング
2番目の製品カードの購入ボタンをクリックしたい以下のDOM構造を考えてみましょう。適切なロケーターを取得するために、いくつかのフィルタリングオプションがあります。
製品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()
await 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()
await 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)
# 5 in-stock items
await 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()などの他のロケーターでフィルタリングできます。
製品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()
await 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)
await 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)
# ✖ WRONG
await 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)
await 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ロケーターを再度使用して、ボタンのロールで取得しクリックし、その後、アサーションを使用して「Product 2」というテキストを持つ製品が1つだけであることを確認します。
- 同期
- 非同期
product = page.get_by_role("listitem").filter(has_text="Product 2")
product.get_by_role("button", name="Add to cart").click()
product = page.get_by_role("listitem").filter(has_text="Product 2")
await 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()
save_button = page.get_by_role("button", name="Save")
# ...
dialog = page.get_by_test_id("settings-dialog")
await 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"))
button = page.get_by_role("button").and_(page.getByTitle("Subscribe"))
2つの代替ロケーターのいずれかに一致
2つ以上の要素のいずれかをターゲットにしたいが、どれになるかわからない場合、locator.or_()を使用して、いずれか一方または両方の代替要素に一致するロケーターを作成します。
例えば、「新規メール」ボタンをクリックしたいが、代わりにセキュリティ設定ダイアログが表示されることがあるシナリオを考えてみましょう。この場合、「新規メール」ボタンかダイアログのいずれかを待機し、それに応じて対処できます。
「新規メール」ボタンとセキュリティダイアログの両方が画面に表示された場合、「or」ロケーターは両方に一致し、場合によっては「厳密モード違反」エラーをスローする可能性があります。この場合、locator.firstを使用してどちらか一方のみに一致させることができます。
- 同期
- 非同期
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()
new_email = page.get_by_role("button", name="New")
dialog = page.get_by_text("Confirm security settings")
await expect(new_email.or_(dialog).first).to_be_visible()
if (await dialog.is_visible()):
await page.get_by_role("button", name="Dismiss").click()
await new_email.click()
可視要素のみの一致
可視性をチェックする代わりに、要素を一意に識別するためのより信頼性の高い方法を見つける方が通常は優れています。
最初のボタンは非表示で、2番目のボタンが表示されている2つのボタンがあるページを考えてみましょう。
<button style='display: none'>Invisible</button>
<button>Visible</button>
-
これは両方のボタンを見つけ、厳密性違反エラーをスローします
- 同期
- 非同期
page.locator("button").click()
await page.locator("button").click()
-
これは2番目のボタンのみを見つけ、それが表示されているため、クリックします。
- 同期
- 非同期
page.locator("button").filter(visible=True).click()
await page.locator("button").filter(visible=True).click()
リスト
リスト内の項目のカウント
ロケーターをアサートして、リスト内の項目をカウントできます。
例えば、以下のDOM構造を考えてみましょう
- りんご
- バナナ
- オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>
カウントアサーションを使用して、リストに3つの項目があることを確認します。
- 同期
- 非同期
expect(page.get_by_role("listitem")).to_have_count(3)
await expect(page.get_by_role("listitem")).to_have_count(3)
リスト内のすべてのテキストをアサート
ロケーターをアサートして、リスト内のすべてのテキストを見つけることができます。
例えば、以下のDOM構造を考えてみましょう
- りんご
- バナナ
- オレンジ
<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"])
await expect(page.get_by_role("listitem")).to_have_text(["apple", "banana", "orange"])
特定の項目を取得
リスト内の特定の項目を取得する方法は多数あります。
テキストで取得
page.get_by_text()メソッドを使用して、リスト内の要素をそのテキストコンテンツで特定し、クリックします。
例えば、以下のDOM構造を考えてみましょう
- りんご
- バナナ
- オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>
項目のテキストコンテンツで特定し、クリックします。
- 同期
- 非同期
page.get_by_text("orange").click()
await page.get_by_text("orange").click()
テキストによるフィルタリング
locator.filter()を使用して、リスト内の特定の項目を特定します。
例えば、以下のDOM構造を考えてみましょう
- りんご
- バナナ
- オレンジ
<ul>
<li>apple</li>
<li>banana</li>
<li>orange</li>
</ul>
「listitem」のロールで項目を特定し、次に「orange」のテキストでフィルタリングし、クリックします。
- 同期
- 非同期
page.get_by_role("listitem").filter(has_text="orange").click()
await page.get_by_role("listitem").filter(has_text="orange").click()
テストIDで取得
page.get_by_test_id()メソッドを使用して、リスト内の要素を特定します。テストIDがまだない場合は、HTMLを変更してテストIDを追加する必要がある場合があります。
例えば、以下のDOM構造を考えてみましょう
- りんご
- バナナ
- オレンジ
<ul>
<li data-testid='apple'>apple</li>
<li data-testid='banana'>banana</li>
<li data-testid='orange'>orange</li>
</ul>
テストIDが「orange」の項目を特定し、クリックします。
- 同期
- 非同期
page.get_by_test_id("orange").click()
await page.get_by_test_id("orange").click()
N番目の項目で取得
同一の要素のリストがあり、それらを区別する唯一の方法が順序である場合、locator.first、locator.last、またはlocator.nth()を使用してリストから特定の要素を選択できます。
- 同期
- 非同期
banana = page.get_by_role("listitem").nth(1)
banana = await page.get_by_role("listitem").nth(1)
ただし、この方法の使用には注意してください。ページが変更されることが多く、ロケーターが予期していたものとはまったく異なる要素を指す可能性があります。代わりに、厳密性基準を満たす一意のロケーターを考案するようにしてください。
フィルターの連結
様々な類似性を持つ要素がある場合、locator.filter()メソッドを使用して適切な要素を選択できます。複数のフィルターを連結して、選択範囲を絞り込むこともできます。
例えば、以下のDOM構造を考えてみましょう
- ジョン
- メアリー
- ジョン
- メアリー
<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")
row_locator = page.get_by_role("listitem")
await 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 row in await page.get_by_role("listitem").all():
print(await row.text_content())
通常のforループを使用してイテレート
- 同期
- 非同期
rows = page.get_by_role("listitem")
count = rows.count()
for i in range(count):
print(rows.nth(i).text_content())
rows = page.get_by_role("listitem")
count = await rows.count()
for i in range(count):
print(await 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)")
rows = page.get_by_role("listitem")
texts = await rows.evaluate_all("list => list.map(element => element.textContent)")
厳密性
ロケーターは厳密です。これは、何らかのターゲットDOM要素を意味するロケーターに対するすべての操作が、複数の要素に一致する場合に例外をスローすることを意味します。例えば、DOMに複数のボタンがある場合、以下の呼び出しは例外をスローします。
複数ある場合にエラーをスロー
- 同期
- 非同期
page.get_by_role("button").click()
await page.get_by_role("button").click()
一方、Playwrightは複数の要素に対する操作を実行する際にそれを認識するため、ロケーターが複数の要素に解決される場合、以下の呼び出しは完全に機能します。
複数の要素でも問題なく動作
- 同期
- 非同期
page.get_by_role("button").count()
await page.get_by_role("button").count()
locator.first、locator.last、およびlocator.nth()を使用して、複数の要素が一致する場合にどの要素を使用するかをPlaywrightに指示することで、厳密性チェックを明示的に無効にすることができます。これらのメソッドは、ページが変更された場合にPlaywrightが意図しない要素をクリックする可能性があるため、**推奨されません**。代わりに、上記のベストプラクティスに従って、ターゲット要素を一意に識別するロケーターを作成してください。
その他のロケーター
あまり一般的ではないロケーターについては、その他のロケーターガイドを参照してください。