其他定位器
簡介
請查看主要的定位器指南,以瞭解最常見和建議的定位器。
除了建議的定位器,如 page.get_by_role() 和 page.get_by_text() 之外,Playwright 還支援本指南中描述的各種其他定位器。
CSS 定位器
我們建議優先使用使用者可見的定位器,例如文字或可存取角色,而不是使用與實作相關聯的 CSS,因為當頁面變更時,CSS 可能會中斷。
Playwright 可以依 CSS 選擇器定位元素。
- 同步
- 非同步
page.locator("css=button").click()
await page.locator("css=button").click()
Playwright 在兩個方面擴增了標準 CSS 選擇器
- CSS 選擇器會穿透封閉的 Shadow 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 的 regex 的最小元素。例如,
:text-matches("Log\s*in", "i")
會比對<button>Login</button>
和<button>log IN</button>
。
文字比對一律會正規化空白字元。例如,它會將多個空格變成一個空格,將換行符號變成空格,並忽略開頭和結尾的空白字元。
類型為 button
和 submit
的輸入元素會依其 value
而非文字內容比對。例如,:text("Log in")
會比對 <input type=button value="Log in">
。
CSS:僅比對可見元素
Playwright 在 CSS 選擇器中支援 :visible
虛擬類別。例如,css=button
會比對頁面上的所有按鈕,而 css=button:visible
只會比對可見的按鈕。這對於區分非常相似但可見性不同的元素很有用。
考量一個具有兩個按鈕的頁面,第一個按鈕不可見,第二個按鈕可見。
<button style='display: none'>Invisible</button>
<button>Visible</button>
-
這會找到兩個按鈕並擲回嚴格性違規錯誤
- 同步
- 非同步
page.locator("button").click()
await page.locator("button").click()
-
這只會找到第二個按鈕,因為它是可見的,然後按一下它。
- 同步
- 非同步
page.locator("button:visible").click()
await page.locator("button:visible").click()
CSS:包含其他元素的元素
:has()
虛擬類別是一個實驗性 CSS 虛擬類別。如果作為參數傳遞的任何選擇器(相對於給定元素的 :scope
)至少比對一個元素,則它會傳回元素。
以下程式碼片段會傳回 <article>
元素的文字內容,該元素內部具有 <div class=promo>
。
- 同步
- 非同步
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:依版面配置比對元素
依版面配置比對可能會產生非預期的結果。例如,當版面配置變更一個像素時,可能會比對到不同的元素。
有時,當目標元素缺少獨特的功能時,很難提出良好的選擇器。在這種情況下,使用 Playwright 版面配置 CSS 虛擬類別可能會有所幫助。這些可以與常規 CSS 結合使用,以精確找出多個選項之一。
例如,input:right-of(:text("Password"))
比對文字 "Password" 右側的輸入欄位 - 當頁面具有多個難以區分的輸入時很有用。
請注意,版面配置虛擬類別除了其他項目(例如 input
)之外也很有用。如果您單獨使用版面配置虛擬類別,例如 :right-of(:text("Password"))
,則很可能您不會得到您要尋找的輸入,而是在文字和目標輸入之間的一些空白元素。
版面配置虛擬類別使用邊界用戶端矩形來計算元素的距離和相對位置。
: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)
會從上面的程式碼片段中選取第三個按鈕。請注意,索引是以 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()
不同,元素不一定是同層級元素,它們可以位於頁面上的任何位置。在上面的程式碼片段中,所有三個按鈕都比對 :text("Buy")
選擇器,而 :nth-match()
會選取第三個按鈕。
第 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 定位器中,元件名稱會以 CamelCase 轉錄。
- 同步
- 非同步
page.locator("_react=BookItem").click()
await 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"]
- 依元件和 key 比對:
_react=BookItem[key = '2']
- 依屬性值 regex 比對:
_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()
await 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"]
- 依屬性值 regex 比對:
_vue=[author = /Steven(\\s+King)?/i]
若要在樹狀結構中尋找 Vue 元素名稱,請使用 Vue DevTools。
Vue 定位器支援 Vue2 及更高版本。
Vue 定位器以及 Vue DevTools 僅適用於未縮小的應用程式組建。
XPath 定位器
我們建議優先使用使用者可見的定位器,例如文字或可存取角色,而不是使用與實作相關聯的 XPath,因為當頁面變更時,XPath 很容易中斷。
XPath 定位器相當於呼叫 Document.evaluate
。
- 同步
- 非同步
page.locator("xpath=//button").click()
await page.locator("xpath=//button").click()
任何以 //
或 ..
開頭的選擇器字串都會被視為 xpath 選擇器。例如,Playwright 會將 '//html/body'
轉換為 'xpath=//html/body'
。
XPath 不會穿透 Shadow Root。
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">密碼:</label><input id="password" type="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 的 regex,以/
符號括住。例如,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"
。
比對一律會正規化空白字元。例如,它會將多個空格變成一個空格,將換行符號變成空格,並忽略開頭和結尾的空白字元。
類型為 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()
# 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 選擇器,因此不支援任何 CSS 特定的項目,例如 :enabled
。如需更多功能,請使用正確的 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
元素。