ハンドル
はじめに
Playwrightは、ページのDOM要素やページ内のその他のオブジェクトへのハンドルを作成できます。これらのハンドルはPlaywrightプロセス内に存在しますが、実際のオブジェクトはブラウザ内に存在します。ハンドルには2種類あります。
- ページ内の任意のJavaScriptオブジェクトを参照するためのJSHandle
- ページ内のDOM要素を参照するためのElementHandle。要素に対するアクションの実行やプロパティのアサートを可能にする追加のメソッドがあります。
ページ内のすべてのDOM要素はJavaScriptオブジェクトでもあるため、すべてのElementHandleはJSHandleでもあります。
ハンドルは、ページ内のそれらの実際のオブジェクトに対して操作を実行するために使用されます。ハンドル上で評価したり、ハンドルプロパティを取得したり、ハンドルを評価パラメータとして渡したり、ページオブジェクトをJSONにシリアライズしたりできます。これらのメソッドについては、JSHandleクラスのAPIを参照してください。
APIリファレンス
JSHandleを取得する最も簡単な方法を以下に示します。
- 同期
- 非同期
js_handle = page.evaluate_handle('window')
# Use jsHandle for evaluations.
js_handle = await page.evaluate_handle('window')
# Use jsHandle for evaluations.
要素のハンドル
ElementHandleの使用は非推奨です。代わりにLocatorオブジェクトとウェブファーストのアサーションを使用してください。
ElementHandleが必要な場合は、page.wait_for_selector()またはframe.wait_for_selector()メソッドで取得することをお勧めします。これらのAPIは、要素がアタッチされ、表示されるまで待機します。
- 同期
- 非同期
# Get the element handle
element_handle = page.wait_for_selector('#box')
# Assert bounding box for the element
bounding_box = element_handle.bounding_box()
assert bounding_box.width == 100
# Assert attribute for the element
class_names = element_handle.get_attribute('class')
assert 'highlighted' in class_names
# Get the element handle
element_handle = page.wait_for_selector('#box')
# Assert bounding box for the element
bounding_box = await element_handle.bounding_box()
assert bounding_box.width == 100
# Assert attribute for the element
class_names = await element_handle.get_attribute('class')
assert 'highlighted' in class_names
パラメータとしてのハンドル
ハンドルは、page.evaluate()や類似のメソッドに渡すことができます。以下のスニペットは、ページ内に新しい配列を作成し、データで初期化して、この配列へのハンドルをPlaywrightに返します。その後、そのハンドルは後続の評価で使用されます。
- 同期
- 非同期
# Create new array in page.
my_array_handle = page.evaluate_handle("""() => {
window.myArray = [1];
return myArray;
}""")
# Get current length of the array.
length = page.evaluate("a => a.length", my_array_handle)
# Add one more element to the array using the handle
page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
'myArray': my_array_handle,
'newElement': 2
})
# Release the object when it's no longer needed.
my_array_handle.dispose()
# Create new array in page.
my_array_handle = await page.evaluate_handle("""() => {
window.myArray = [1];
return myArray;
}""")
# Get current length of the array.
length = await page.evaluate("a => a.length", my_array_handle)
# Add one more element to the array using the handle
await page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
'myArray': my_array_handle,
'newElement': 2
})
# Release the object when it's no longer needed.
await my_array_handle.dispose()
ハンドルのライフサイクル
ハンドルは、page.evaluate_handle()、page.query_selector()、page.query_selector_all()などのページメソッド、またはそれに対応するフレームメソッドframe.evaluate_handle()、frame.query_selector()、frame.query_selector_all()を使用して取得できます。作成されたハンドルは、ページがナビゲートされるか、js_handle.dispose()メソッドを介して手動で破棄されない限り、ガベージコレクションからオブジェクトを保持します。
APIリファレンス
- JSHandle
- ElementHandle
- element_handle.bounding_box()
- element_handle.get_attribute()
- element_handle.inner_text()
- element_handle.inner_html()
- element_handle.text_content()
- js_handle.evaluate()
- page.evaluate_handle()
- page.query_selector()
- page.query_selector_all()
LocatorとElementHandleの比較
静的なページで大規模なDOM走査を実行する必要がある稀なケースでのみ、ElementHandleを使用することをお勧めします。すべてのユーザーアクションとアサーションには、代わりにロケーターを使用してください。
LocatorとElementHandleの違いは、後者が特定の要素を指すのに対し、Locatorはその要素を取得するロジックをカプセル化している点です。
以下の例では、ハンドルはページの特定のDOM要素を指しています。その要素のテキストが変更されたり、Reactによってまったく異なるコンポーネントがレンダリングされたりしても、ハンドルはその古いDOM要素を指し続けます。これにより、予期しない動作が発生する可能性があります。
- 同期
- 非同期
handle = page.query_selector("text=Submit")
handle.hover()
handle.click()
handle = await page.query_selector("text=Submit")
await handle.hover()
await handle.click()
ロケーターを使用すると、ロケーターが使用されるたびに、セレクターを使用してページ内の最新のDOM要素が特定されます。したがって、以下のスニペットでは、基になるDOM要素が2回特定されることになります。
- 同期
- 非同期
locator = page.get_by_text("Submit")
locator.hover()
locator.click()
locator = page.get_by_text("Submit")
await locator.hover()
await locator.click()