《最新出爐》系列初窺篇-Python+Playwright自動(dòng)化測(cè)試-6-元素定位大法-下篇

1.簡(jiǎn)介

上一篇主要是講解我們?nèi)粘9ぷ髦性谑褂肞laywright進(jìn)行元素定位的一些比較常用的定位方法的理論基礎(chǔ)知識(shí)以及在什么情況下推薦使用。今天這一篇講解和分享一下,在日常中很少用到或者很少見的定位,但是遇到了我們也要會(huì),俗話說(shuō):手里有糧心里不慌。

2.陰影定位-Shadow DOM

在做web自動(dòng)化的時(shí)候,一些元素在shadow-root的節(jié)點(diǎn)下,使得playwright中無(wú)法通過(guò)xpath來(lái)定位

上面所看到的shadow-root標(biāo)簽其實(shí)就是一個(gè)shadowDOM,那么什么是shadowDOM呢?

他是前端的一種頁(yè)面封裝技術(shù),可以將shadowDOM視為“DOM中的DOM”(可以看成一個(gè)隱藏的DOM)

他是一個(gè)獨(dú)立的DOM樹,具有自己的元素和樣式,與原始文檔DOM完全隔離。

shadowDOM必須附在一個(gè)HTML元素中,存放shadowDOM的元素,我們可以把它稱為宿主元素。在HTML5中有很多的標(biāo)簽樣式都是通過(guò)shadowDOM來(lái)實(shí)現(xiàn)的。

比如:日期選擇框,音頻播放標(biāo)簽,視頻播放標(biāo)簽都自帶了樣式;(這種封裝對(duì)于前端開發(fā)來(lái)說(shuō)雖好,但是我們測(cè)試人員在做web自動(dòng)給的時(shí)候就會(huì)遇到一些問(wèn)題,shadowDOM中的標(biāo)簽無(wú)法定位。)

默認(rèn)情況下,Playwright 中的所有定位器都使用 Shadow DOM 中的元素。例外情況是:

  • 通過(guò) XPath 定位不會(huì)刺穿陰影根部。
  • 不支持閉合模式影子根。

例如:以下示例和自定義 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>

您可以采用與影子根根本不存在相同的方式進(jìn)行定位。

要單擊 :<div>Details</div>

page.get_by_text("Details").click()

要單擊 :<x-details>

page.locator("x-details", has_text="Details" ).click()

要確保包含文本“詳細(xì)信息”,請(qǐng)執(zhí)行以下操作:<x-details>

expect(page.locator("x-details")).to_contain_text("Details")

3.過(guò)濾器定位-Filtering

例如以下 DOM 結(jié)構(gòu),我們要在其中單擊第二個(gè)產(chǎn)品卡的購(gòu)買按鈕。我們有幾個(gè)選項(xiàng)來(lái)過(guò)濾定位器以獲得正確的定位器。

3.1文本過(guò)濾

定位器可以使用 locator.filter()方法按文本進(jìn)行過(guò)濾。它將搜索元素內(nèi)某處的特定字符串,可能在后代元素中,不區(qū)分大小寫。您還可以傳遞正則表達(dá)式。

1.使用文本

page.get_by_role("listitem").filter(has_text="Product 2").get_by_role(
    "button", name="Add to cart"
).click()

2.使用正則表達(dá)式

page.get_by_role("listitem").filter(has_text=re.compile("Product 2")).get_by_role(
    "button", name="Add to cart"
).click()

3.通過(guò)沒(méi)有文本進(jìn)行篩選

# 5 in-stock items
expect(page.get_by_role("listitem").filter(has_not_text="Out of stock")).to_have_count(5)

3.2子項(xiàng)/后代過(guò)濾

定位器支持僅選擇具有或沒(méi)有與其他定位器匹配的后代的元素的選項(xiàng)。因此,您可以按任何其他定位器進(jìn)行過(guò)濾,例如 locator.get_by_role()、locator.get_by_test_id()、locator.get_by_text() 等。

1.使用子項(xiàng)

page.get_by_role("listitem").filter(
    has=page.get_by_role("heading", name="Product 2")
).get_by_role("button", name="Add to cart").click()

2.使用產(chǎn)品卡斷言,確保只有一個(gè)

expect(
    page.get_by_role("listitem").filter(
        has=page.get_by_role("heading", name="Product 2")
    )
).to_have_count(1)

3.通過(guò)內(nèi)部沒(méi)有匹配的元素進(jìn)行過(guò)濾

expect(
    page.get_by_role("listitem").filter(
        has_not=page.get_by_role("heading", name="Product 2")
    )
).to_have_count(1)

敲黑板!?。?!注意:內(nèi)部定位器從外部定位器開始匹配,而不是從文檔根目錄匹配。

3.3匹配其他定位進(jìn)行過(guò)濾

方法 locator.and_() 通過(guò)匹配其他定位器來(lái)縮小現(xiàn)有定位器的范圍。例如,您可以組合 page.get_by_role() 和 page.get_by_title() 以按角色和頭銜進(jìn)行匹配。

button = page.get_by_role("button").and_(page.getByTitle("Subscribe"))

4.鏈接定位器

您可以鏈接創(chuàng)建定位器的方法(如 page.get_by_text() 或 locator.get_by_role()),以將搜索范圍縮小到頁(yè)面的特定部分。

在此示例中,我們首先通過(guò)定位其角色:listitem 來(lái)創(chuàng)建一個(gè)名為 product 的定位器。然后我們按文本過(guò)濾。我們可以再次使用產(chǎn)品定位器按按鈕的角色獲取并單擊它,然后使用斷言來(lái)確保只有一個(gè)帶有文本“產(chǎn)品 2”的產(chǎn)品。

product = page.get_by_role("listitem").filter(has_text="Product 2")

product.get_by_role("button", name="Add to cart").click()

您還可以將兩個(gè)定位器鏈接在一起,例如在特定對(duì)話框中查找“保存”按鈕:

save_button = page.get_by_role("button", name="Save")
# ...
dialog = page.get_by_test_id("settings-dialog")
dialog.locator(save_button).click()

5.列表

5.1對(duì)列表中的項(xiàng)目進(jìn)行計(jì)數(shù)

可以斷言定位器以對(duì)列表中的項(xiàng)目進(jìn)行計(jì)數(shù)。例如:一下DOM結(jié)構(gòu)

使用計(jì)數(shù)斷言確保列表包含 3 個(gè)項(xiàng)目。

expect(page.get_by_role("listitem")).to_have_count(3)

5.2斷言列表中所有文本

可以斷言定位器以查找列表中的所有文本。使用 expect(定位器).to_have_text() 確保列表包含文本“蘋果”、“香蕉”和“橙色”。

expect(page.get_by_role("listitem")).to_have_text(["apple", "banana", "orange"])

5.3定位特定項(xiàng)目

有許多方法可以在列表中定位特定項(xiàng)目。

5.3.1通過(guò)文本定位

使用 page.get_by_text() 方法通過(guò)文本內(nèi)容在列表中查找元素,然后單擊它。

通過(guò)文本內(nèi)容找到項(xiàng)目并單擊它。

page.get_by_text("orange").click()

5.3.2通過(guò)文本過(guò)濾定位

使用 locator.filter() 在列表中查找特定項(xiàng)目。按“列表項(xiàng)”的角色找到一個(gè)項(xiàng)目,然后按“橙色”的文本進(jìn)行篩選,然后單擊它。

page.get_by_role("listitem").filter(has_text="orange").click()

5.3.3通過(guò)測(cè)試id定位

使用 page.get_by_test_id() 方法在列表中查找元素。如果您還沒(méi)有測(cè)試 ID,則可能需要修改 html 并添加測(cè)試 ID。

通過(guò)測(cè)試ID“橙色”找到項(xiàng)目,然后單擊它。

page.get_by_test_id("orange").click()

5.3.4通過(guò)第n項(xiàng)定位

如果你有一個(gè)相同元素的列表,并且區(qū)分它們的唯一方法是順序,你可以從帶有 locator.first、locator.last 或 locator.nth() 的列表中選擇一個(gè)特定的元素。

banana = page.get_by_role("listitem").nth(1)

但是,請(qǐng)謹(jǐn)慎使用此方法。通常,頁(yè)面可能會(huì)更改,并且定位器將指向與預(yù)期完全不同的元素。相反,嘗試提出一個(gè)通過(guò)嚴(yán)格標(biāo)準(zhǔn)的獨(dú)特定位器。

5.4鏈接過(guò)濾器

當(dāng)您有各種相似性的元素時(shí),可以使用 locator.filter()方法選擇正確的元素。您還可以鏈接多個(gè)篩選器以縮小選擇范圍。

要截取帶有“Mary”和“Say goodbye”的行的屏幕截圖:

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

5.5罕見例子

5.5.1對(duì)列表中每個(gè)元素執(zhí)行操作

迭代元素

for row in page.get_by_role("listitem").all():
    print(row.text_content())

使用常規(guī) for 循環(huán)進(jìn)行迭代:

rows = page.get_by_role("listitem")
count = rows.count()
for i in range(count):
    print(rows.nth(i).text_content())

5.5.2在頁(yè)面中評(píng)估

locator.evaluate_all()中的代碼在頁(yè)面中運(yùn)行,您可以在那里調(diào)用任何 DOM API。

rows = page.get_by_role("listitem")
texts = rows.evaluate_all("list => list.map(element => element.textContent)")

6.小結(jié)

定位器是非常嚴(yán)格。這意味著,如果多個(gè)元素匹配,則對(duì)定位器執(zhí)行暗示某些目標(biāo) DOM 元素的所有操作都將引發(fā)異常。例如,如果 DOM 中有多個(gè)按鈕,則會(huì)引發(fā)以下調(diào)用:

6.1如果有多個(gè)button,則引發(fā)錯(cuò)誤

page.get_by_role("button").click()

另一方面,Playwright 了解何時(shí)執(zhí)行多元素操作,因此當(dāng)定位器解析為多個(gè)元素時(shí),以下調(diào)用工作正常。

6.2適用于多個(gè)元素

page.get_by_role("button").count()

您可以通過(guò) locator.first、locator.last 和 locator.nth() 告訴 Playwright 在多個(gè)元素匹配時(shí)使用哪個(gè)元素來(lái)明確選擇退出嚴(yán)格性檢查。不建議使用這些方法,因?yàn)楫?dāng)您的頁(yè)面更改時(shí),Playwright 可能會(huì)單擊您不想要的元素。相反,請(qǐng)按照上述最佳實(shí)踐創(chuàng)建唯一標(biāo)識(shí)目標(biāo)元素的定位器。

6.3其他定位器

對(duì)于不太常用的定位器,請(qǐng)查看官網(wǎng)的其他定位器指南。由于時(shí)間關(guān)系,宏哥就不在這里對(duì)其進(jìn)行展開介紹和講解了。好了時(shí)間不早了,關(guān)于元素定位大法今天就分享到這里!??!僅供大家學(xué)習(xí)參考,感謝您耐心的閱讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容