跳到主要內容

其他定位器

簡介

注意

查看主要的定位器指南,以了解最常用和建議的定位器。

除了建議的定位器(例如 Page.GetByRole()Page.GetByText())之外,Playwright 還支援本指南中描述的各種其他定位器。

CSS 定位器

注意

我們建議優先使用使用者可見的定位器,例如文字或可存取角色,而不是使用與實作相關聯的 CSS,這可能會在頁面變更時中斷。

Playwright 可以透過 CSS 選取器定位元素。

await page.Locator("css=button").ClickAsync();

Playwright 以兩種方式擴充標準 CSS 選取器

  • 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>
    await page.Locator(":has-text(\"Playwright\")").ClickAsync();
    // Correct, only matches the <article> element
    await page.Locator("article:has-text(\"Playwright\")").ClickAsync();
  • #nav-bar :text("Home") - :text() 虛擬類別比對包含指定文字的最小元素。比對不區分大小寫、修剪空白字元並搜尋子字串。

    例如,這會在 #nav-bar 元素內部的某個位置尋找文字為「Home」的元素

    await page.Locator("#nav-bar :text('Home')").ClickAsync();
  • #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>

注意

文字比對一律會正規化空白字元。例如,它會將多個空格變成一個空格,將換行符號變成空格,並忽略開頭和結尾的空白字元。

注意

類型為 buttonsubmit 的輸入元素會依其 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>
  • 這會尋找兩個按鈕並擲回嚴格性違規錯誤

    await page.Locator("button").ClickAsync();
  • 這只會尋找第二個按鈕,因為它是可見的,然後按一下它。

    await page.Locator("button:visible").ClickAsync();

CSS:包含其他元素的元素

:has() 虛擬類別是實驗性 CSS 虛擬類別。如果作為參數傳遞的任何選取器相對於給定元素的 :scope 比對至少一個元素,則它會傳回元素。

下列程式碼片段會傳回具有內部 <div class=promo><article> 元素的文字內容。

await page.Locator("article:has(div.promo)").TextContentAsync();

CSS:比對其中一個條件的元素

逗號分隔的 CSS 選取器清單將比對可以由該清單中其中一個選取器選取的所有元素。

// 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\")").ClickAsync();

: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".
await page.Locator("input:right-of(:text(\"Username\"))").FillAsync("value");

// Click a button near the promo card.
await page.Locator("button:near(.promo-card)").ClickAsync();

// Click the radio input in the list closest to the "Label 3".
await page.Locator("[type=radio]:left-of(:text(\"Label 3\"))").First.ClickAsync();

所有版面配置虛擬類別都支援選用的最大像素距離作為最後一個引數。例如,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
await page.Locator(":nth-match(:text('Buy'), 3)").ClickAsync();

:nth-match() 也可用於等待指定數量的元素出現,方法是使用Locator.WaitForAsync()

// Wait until all three buttons are visible
await page.Locator(":nth-match(:text('Buy'), 3)").WaitForAsync();
注意

:nth-child()不同,元素不必是同層級元素,它們可以位於頁面上的任何位置。在上面的程式碼片段中,所有三個按鈕都比對 :text("Buy") 選取器,而 :nth-match() 選取第三個按鈕。

第 N 個元素定位器

您可以使用 nth= 定位器傳遞以零為基礎的索引,將查詢縮小到第 n 個比對。

// Click first button
await page.Locator("button").Locator("nth=0").ClickAsync();

// Click last button
await page.Locator("button").Locator("nth=-1").ClickAsync();

父元素定位器

當您需要以其他元素的父元素為目標時,大多數時候您應該依子定位器Locator.Filter()。例如,考量下列 DOM 結構

<li><label>Hello</label></li>
<li><label>World</label></li>

如果您想要以文字為 "Hello" 的標籤的父 <li> 為目標,則使用Locator.Filter()效果最佳

var child = page.GetByText("Hello");
var parent = page.GetByRole(AriaRole.Listitem).Filter(new () { Has = child });

或者,如果您找不到父元素的合適定位器,請使用 xpath=..。請注意,此方法不如可靠,因為對 DOM 結構的任何變更都會中斷您的測試。如果可能,請優先使用Locator.Filter()

var parent = page.GetByText("Hello").Locator("xpath=..");

React 定位器

注意

React 定位器是實驗性的,並以 _ 為前綴。此功能未來可能會變更。

React 定位器允許依其元件名稱和屬性值尋找元素。語法與CSS 屬性選取器非常相似,並支援所有 CSS 屬性選取器運算子。

在 React 定位器中,元件名稱以駝峰式大小寫轉錄。

await page.Locator("_react=BookItem").ClickAsync();

更多範例

  • 元件比對:_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 轉錄。

await page.Locator("_vue=book-item").ClickAsync();

更多範例

  • 元件比對:_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 定位器相當於呼叫 Document.evaluate

await page.Locator("xpath=//button").ClickAsync();
注意

任何以 //.. 開頭的選取器字串都假定為 xpath 選取器。例如,Playwright 會將 '//html/body' 轉換為 'xpath=//html/body'

注意

XPath 不會穿透陰影根目錄。

XPath 聯集

管線運算子 (|) 可用於在 XPath 中指定多個選取器。它會比對可以由該清單中其中一個選取器選取的所有元素。

// Waits for either confirmation dialog or load spinner.
await page.Locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").WaitForAsync();

標籤到表單控制項重新定向

警告

我們建議依標籤文字定位,而不是依賴標籤到控制項的重新定向。

Playwright 中的目標輸入動作會自動區分標籤和控制項,因此您可以以標籤為目標,以對相關聯的控制項執行動作。

例如,考量下列 DOM 結構:<label for="password">密碼:</label><input id="password" type="password">。您可以使用 Page.GetByText(),依其「密碼」文字以標籤為目標。但是,下列動作會在輸入上執行,而不是在標籤上執行

// Fill the input by targeting the label.
await page.GetByText("Password").FillAsync("secret");

但是,其他方法會以標籤本身為目標,例如 Expect(Locator).ToHaveTextAsync() 將判斷提示標籤的文字內容,而不是輸入欄位。

// Fill the input by targeting the label.
await Expect(Page.Locator("label")).ToHaveTextAsync("Password");

舊版文字定位器

警告

我們建議使用新式文字定位器

舊版文字定位器比對包含傳遞文字的元素。

await page.Locator("text=Log in").ClickAsync();

舊版文字定位器有幾個變體

  • text=Log in - 預設比對不區分大小寫、修剪空白字元並搜尋子字串。例如,text=Log 比對 <button>Log in</button>

    await page.Locator("text=Log in").ClickAsync();
  • 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"

    await page.Locator("text='Log in'").ClickAsync();
  • /Log\s*in/i - 主體可以是包裝在 / 符號中的類似 JavaScript 的 regex。例如,text=/Log\s*in/i 比對 <button>Login</button><button>log IN</button>

    await page.Locator("text=/Log\\s*in/i").ClickAsync();
注意

以引號("')開頭和結尾的字串選取器假定為舊版文字定位器。例如,"Log in" 會在內部轉換為 text="Log in"

注意

比對一律會正規化空白字元。例如,它會將多個空格變成一個空格,將換行符號變成空格,並忽略開頭和結尾的空白字元。

注意

類型為 buttonsubmit 的輸入元素會依其 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"
await page.Locator("id=username").FillAsync("value");

// Click an element with data-test-id "submit"
await page.Locator("data-test-id=submit").ClickAsync();
注意

屬性選取器不是 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 元素。