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

その他のロケーター

はじめに

最も一般的で推奨されるロケーターについては、メインのロケーターガイドを参照してください。

page.get_by_role()page.get_by_text()のような推奨されるロケーターに加えて、Playwrightはこのガイドで説明されている様々な他のロケーターをサポートしています。

CSSロケーター

実装に依存し、ページ変更時に壊れる可能性があるCSSを使用する代わりに、テキストやアクセシブルなロールのようなユーザーに見えるロケーターを優先することをお勧めします。

PlaywrightはCSSセレクターで要素を特定できます。

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()
  • #nav-bar :text("Home") - :text()疑似クラスは、指定されたテキストを含む最小の要素にマッチします。マッチングでは大文字と小文字を区別せず、空白をトリムし、部分文字列を検索します。

    例えば、これは#nav-bar要素のどこかに"Home"というテキストを持つ要素を見つけます。

    page.locator("#nav-bar :text('Home')").click()
  • #nav-bar :text-is("Home") - :text-is()疑似クラスは、正確なテキストを持つ最小の要素にマッチします。正確なマッチングでは大文字と小文字を区別し、空白をトリムし、完全な文字列を検索します。

    例えば、:text-is("Log")<button>Log in</button>にはマッチしません。なぜなら、<button>には"Log"とは等しくない単一のテキストノード"Log in"が含まれているからです。しかし、: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番目のボタンが可視の、2つのボタンがあるページを考えてみましょう。

<button style='display: none'>Invisible</button>
<button>Visible</button>
  • これにより両方のボタンが見つかり、厳密性違反エラーがスローされます。

    page.locator("button").click()
  • これは2番目のボタンのみを見つけ、それが可視であるためクリックします。

    page.locator("button:visible").click()

CSS: 他の要素を含む要素

:has()疑似クラスは、実験的なCSS疑似クラスです。これは、指定された要素の:scopeに対してパラメータとして渡されたセレクターのいずれかが少なくとも1つの要素にマッチする場合に要素を返します。

以下のスニペットは、内部に<div class=promo>を持つ<article>要素のテキストコンテンツを返します。

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()

: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()

すべてのレイアウト疑似クラスは、最後の引数としてオプションの最大ピクセル距離をサポートしています。例えば、button:near(:text("Username"), 120)は、"Username"というテキストを持つ要素から最大120 CSSピクセル離れたボタンにマッチします。

CSS: クエリ結果からn番目のマッチを選択

通常、要素を何らかの属性やテキストコンテンツで区別することは可能であり、これはページ変更に対してより堅牢です。

ページに類似した要素が多数含まれており、特定の1つを選択するのが難しい場合があります。例えば、

<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()

:nth-match()は、locator.wait_for()を使用して、指定された数の要素が表示されるまで待機するのにも役立ちます。

# Wait until all three buttons are visible
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()

親要素ロケーター

他の要素の親要素をターゲットにする必要がある場合、ほとんどの場合、子ロケーターによって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)

あるいは、親要素に適したロケーターが見つからない場合は、xpath=..を使用します。この方法はDOM構造の変更によってテストが壊れる可能性があるため、信頼性は低いことに注意してください。可能な限りlocator.filter()を優先してください。

parent = page.get_by_text("Hello").locator('xpath=..')

Reactロケーター

Reactロケーターは実験的なもので、_がプレフィックスとして付いています。機能は将来変更される可能性があります。

Reactロケーターを使用すると、コンポーネント名とプロパティ値で要素を見つけることができます。構文はCSS属性セレクターと非常によく似ており、すべてのCSS属性セレクター演算子をサポートしています。

Reactロケーターでは、コンポーネント名はCamelCaseで表記されます。

page.locator("_react=BookItem").click()

その他の例

  • コンポーネントによるマッチング: _react=BookItem
  • コンポーネントと正確なプロパティ値によるマッチング (大文字小文字を区別): _react=BookItem[author = "Steven King"]
  • プロパティ値のみによるマッチング (大文字小文字を区別しない): _react=[author = "steven king" i]
  • コンポーネントと真値プロパティ値によるマッチング: _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ロケーターでは、コンポーネント名はkebab-caseで表記されます。

page.locator("_vue=book-item").click()

その他の例

  • コンポーネントによるマッチング: _vue=book-item
  • コンポーネントと正確なプロパティ値によるマッチング (大文字小文字を区別): _vue=book-item[author = "Steven King"]
  • プロパティ値のみによるマッチング (大文字小文字を区別しない): _vue=[author = "steven king" i]
  • コンポーネントと真値プロパティ値によるマッチング: _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()

//または..で始まるセレクター文字列は、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()

ラベルからフォームコントロールへのリターゲット

警告

ラベルからコントロールへのリターゲットに頼るのではなく、ラベルテキストによる特定をお勧めします。

Playwrightのターゲット入力アクションは、ラベルとコントロールを自動的に区別するため、関連するコントロールに対してアクションを実行するためにラベルをターゲットにすることができます。

例えば、以下のDOM構造を考えてみましょう: <label for="password">Password:</label><input id="password" type="password">。このラベルはpage.get_by_text()を使用して"Password"テキストでターゲットにできます。ただし、以下の操作はラベルではなく入力フィールドに対して実行されます。

# Fill the input by targeting the label.
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")

レガシーテキストロケーター

警告

代わりに、モダンなテキストロケーターをお勧めします。

レガシーテキストロケーターは、渡されたテキストを含む要素にマッチします。

page.locator("text=Log in").click()

レガシーテキストロケーターにはいくつかのバリエーションがあります。

  • text=Log in - デフォルトのマッチングでは大文字と小文字を区別せず、空白をトリムし、部分文字列を検索します。例えば、text=Log<button>Log in</button>にマッチします。

    page.locator("text=Log in").click()
  • text="Log in" - テキスト本体は、空白をトリムした後の正確なコンテンツを持つテキストノードを検索するために、シングルクォーテーションまたはダブルクォーテーションでエスケープできます。

    例えば、text="Log"<button>Log in</button>にはマッチしません。なぜなら、<button>には"Log"とは等しくない単一のテキストノード"Log in"が含まれているからです。しかし、text="Log"<button> Log <span>in</span></button>にマッチします。なぜなら、<button>にはテキストノード" Log "が含まれているからです。この厳密なモードでは大文字と小文字を区別するマッチングが暗示されるため、text="Download"<button>download</button>にはマッチしません。

    引用された本体は通常のエスケープルールに従います。例えば、ダブルクォーテーションで囲まれた文字列内でダブルクォーテーションをエスケープするには\"を使用します: text="foo\"bar"

    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()

クォーテーション ("または') で始まり終わる文字列セレクターは、レガシーテキストロケーターとみなされます。例えば、"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は特定の属性を使用して要素を選択するための省略形をサポートしています。現在、以下の属性のみがサポートされています。

  • id
  • data-testid
  • data-test-id
  • data-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()

属性セレクターは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要素をキャプチャします。