跳至主要內容

選擇器

WebDriver 協定提供了多種選擇器策略來查詢元素。WebdriverIO 簡化了它們,以保持選擇元素的簡單性。請注意,即使查詢元素的命令稱為 $$$,它們也與 jQuery 或 Sizzle 選擇器引擎無關。

雖然有這麼多不同的選擇器可用,但只有少數能提供一種彈性的方式來找到正確的元素。例如,給定以下按鈕

<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-testid="submit"
>
Submit
</button>

我們建議不建議以下選擇器

選擇器建議註解
$('button')🚨 絕對不要最糟 - 太過通用,沒有上下文。
$('.btn.btn-large')🚨 絕對不要差。與樣式耦合。極易變更。
$('#main')⚠️ 謹慎使用較佳。但仍與樣式或 JS 事件監聽器耦合。
$(() => document.queryElement('button'))⚠️ 謹慎使用有效的查詢,但撰寫複雜。
$('button[name="submission"]')⚠️ 謹慎使用與具有 HTML 語義的 name 屬性耦合。
$('button[data-testid="submit"]')✅ 良好需要額外的屬性,與 a11y 沒有關聯。
$('aria/Submit')$('button=Submit')✅ 總是最佳。類似於使用者與頁面互動的方式。建議使用前端的翻譯檔案,這樣當翻譯更新時,您的測試永遠不會失敗

CSS 查詢選擇器

如果沒有另外指示,WebdriverIO 將使用 CSS 選擇器模式查詢元素,例如

selectors/example.js
loading...

若要取得其中具有特定文字的錨點元素,請查詢以等號 (=) 符號開頭的文字。

例如

selectors/example.html
loading...

您可以使用以下方式查詢此元素

selectors/example.js
loading...

若要尋找其可見文字部分符合您搜尋值的錨點元素,請在查詢字串前面使用 *= 來查詢 (例如,*=driver)。

您也可以使用以下方式查詢以上範例中的元素

selectors/example.js
loading...

注意:您無法在一個選擇器中混合多個選擇器策略。使用多個鏈接的元素查詢來達到相同的目標,例如

const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('*=driver')

具有特定文字的元素

相同的技術也可以應用於元素。此外,也可以在查詢中使用 .=.*= 進行不區分大小寫的匹配。

例如,以下是查詢標題為「歡迎來到我的頁面」的 1 級標題

selectors/example.html
loading...

您可以使用以下方式查詢此元素

selectors/example.js
loading...

或使用查詢部分文字

selectors/example.js
loading...

對於 idclass 名稱也是如此

selectors/example.html
loading...

您可以使用以下方式查詢此元素

selectors/example.js
loading...

注意:您無法在一個選擇器中混合多個選擇器策略。使用多個鏈接的元素查詢來達到相同的目標,例如

const elem = await $('header h1*=Welcome') // doesn't work!!!
// use instead
const elem = await $('header').$('h1*=Welcome')

標籤名稱

若要查詢具有特定標籤名稱的元素,請使用 <tag><tag />

selectors/example.html
loading...

您可以使用以下方式查詢此元素

selectors/example.js
loading...

名稱屬性

若要查詢具有特定名稱屬性的元素,您可以使用一般的 CSS3 選擇器,或透過將類似 [name="some-name"] 作為選擇器參數傳遞,來使用來自 JSONWireProtocol 的提供的名稱策略

selectors/example.html
loading...
selectors/example.js
loading...

注意:此選擇器策略已棄用,僅在由 JSONWireProtocol 協定執行的舊瀏覽器或使用 Appium 時才有效。

xPath

也可以透過特定的 xPath 來查詢元素。

xPath 選擇器的格式類似 //body/div[6]/div[1]/span[1]

selectors/xpath.html
loading...

您可以使用以下方式查詢第二個段落

selectors/example.js
loading...

您可以使用 xPath 來上下遍歷 DOM 樹

selectors/example.js
loading...

協助工具名稱選擇器

依其可存取名稱查詢元素。可存取名稱是當該元素獲得焦點時螢幕閱讀器所宣告的內容。可存取名稱的值可以是視覺內容或隱藏的文字替代方案。

資訊

您可以在我們的發佈部落格文章中閱讀更多關於此選擇器的資訊

aria-label 擷取

selectors/aria.html
loading...
selectors/example.js
loading...

aria-labelledby 擷取

selectors/aria.html
loading...
selectors/example.js
loading...

依內容擷取

selectors/aria.html
loading...
selectors/example.js
loading...

依標題擷取

selectors/aria.html
loading...
selectors/example.js
loading...

alt 屬性擷取

selectors/aria.html
loading...
selectors/example.js
loading...

ARIA - 角色屬性

若要根據 ARIA 角色查詢元素,您可以直接將元素的角色指定為選擇器參數,例如 [role=button]

selectors/aria.html
loading...
selectors/example.js
loading...

ID 屬性

WebDriver 協定不支援定位器策略「id」,應使用 CSS 或 xPath 選擇器策略來尋找使用 ID 的元素。

但是,某些驅動程式 (例如 Appium You.i Engine Driver) 可能仍然支援此選擇器。

目前支援的 ID 選擇器語法為

//css locator
const button = await $('#someid')
//xpath locator
const button = await $('//*[@id="someid"]')
//id strategy
// Note: works only in Appium or similar frameworks which supports locator strategy "ID"
const button = await $('id=resource-id/iosname')

JS 函數

您也可以使用 JavaScript 函數,透過 Web 原生 API 來擷取元素。當然,您只能在 Web 環境中執行此操作 (例如,browser 或行動裝置中的 Web 環境)。

給定以下 HTML 結構

selectors/js.html
loading...

您可以使用以下方式查詢 #elem 的兄弟元素

selectors/example.js
loading...

深層選擇器

警告

從 WebdriverIO 的 v9 版本開始,不再需要這個特殊的選擇器,因為 WebdriverIO 會自動穿透 Shadow DOM。建議移除前面的 >>> 來遷移這個選擇器。

許多前端應用程式大量依賴具有Shadow DOM的元素。在沒有任何變通方法的情況下,技術上不可能查詢 Shadow DOM 內的元素。shadow$shadow$$ 就是這樣的變通方法,但有其限制。有了深層選擇器,您現在可以使用常見的查詢命令查詢任何 Shadow DOM 內的所有元素。

假設我們有一個應用程式,其結構如下

Chrome Example

使用此選擇器,您可以查詢巢狀於另一個 Shadow DOM 內的 <button /> 元素,例如:

selectors/example.js
loading...

行動裝置選擇器

對於混合式行動裝置測試,在執行命令之前,自動化伺服器必須處於正確的情境中。為了自動化手勢,驅動程式最好設定為原生情境。但是,要從 DOM 選擇元素,驅動程式需要設定為平台的 Webview 情境。只有在那之後才能使用上述方法。

對於原生行動裝置測試,不需要在情境之間切換,因為您必須使用行動裝置策略並直接使用底層裝置自動化技術。當測試需要對尋找元素進行一些精細的控制時,這特別有用。

Android UiAutomator

Android 的 UI Automator 架構提供了多種尋找元素的方法。您可以使用 UI Automator API,尤其是 UiSelector 類別來定位元素。在 Appium 中,您將 Java 程式碼以字串形式傳送至伺服器,伺服器會在應用程式的環境中執行它,並傳回元素或多個元素。

const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()

Android DataMatcher 和 ViewMatcher(僅限 Espresso)

Android 的 DataMatcher 策略提供了一種透過 Data Matcher 來尋找元素的方法

const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"]
})
await menuItem.click()

類似地,View Matcher

const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"],
"class": "androidx.test.espresso.matcher.ViewMatchers"
})
await menuItem.click()

Android View Tag(僅限 Espresso)

View tag 策略提供了一種方便的方法,可以透過其標籤來尋找元素。

const elem = await $('-android viewtag:tag_identifier')
await elem.click()

iOS UIAutomation

當自動化 iOS 應用程式時,可以使用 Apple 的 UI Automation 架構來尋找元素。

這個 JavaScript API 具有存取視圖及其所有內容的方法。

const selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
const button = await $(`ios=${selector}`)
await button.click()

您也可以在 Appium 的 iOS UI Automation 中使用述詞搜尋來進一步精確元素選擇。有關詳細資訊,請參閱此處

iOS XCUITest 述詞字串和類別鏈

對於 iOS 10 及更高版本(使用 XCUITest 驅動程式),您可以使用述詞字串

const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()

以及類別鏈

const selector = '**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton'
const button = await $(`-ios class chain:${selector}`)
await button.click()

輔助功能 ID

輔助功能 ID 定位器策略旨在讀取 UI 元素的唯一識別碼。這有不會在本地化或任何其他可能更改文字的過程中變更的好處。此外,如果功能相同的元素具有相同的輔助功能 ID,則有助於建立跨平台測試。

  • 對於 iOS,這是 Apple 佈局的 accessibility identifier 此處
  • 對於 Android,輔助功能 ID 會對應到元素的 content-description,如 此處所述。

對於這兩個平台,通常最好透過其 輔助功能 ID 取得元素(或多個元素)。它也是優先於已棄用的 name 策略的方法。

const elem = await $('~my_accessibility_identifier')
await elem.click()

類別名稱

類別名稱策略是一個 字串,代表目前檢視上的 UI 元素。

  • 對於 iOS,它是UIAutomation 類別的完整名稱,並將以 UIA- 開頭,例如文字欄位的 UIATextField。完整的參考資料可以在此處找到。
  • 對於 Android,它是 UI Automator 類別的完整限定名稱,例如文字欄位的 android.widget.EditText。完整的參考資料可以在此處找到。
  • 對於 Youi.tv,它是 Youi.tv 類別的完整名稱,並將以 CYI- 開頭,例如按鈕元素的 CYIPushButtonView。完整的參考資料可以在 You.i Engine Driver 的 GitHub 頁面找到。
// iOS example
await $('UIATextField').click()
// Android example
await $('android.widget.DatePicker').click()
// Youi.tv example
await $('CYIPushButtonView').click()

鏈式選擇器

如果您想在查詢中更精確,您可以鏈接選擇器,直到找到正確的元素。如果您在實際命令之前呼叫 element,WebdriverIO 會從該元素開始查詢。

例如,如果您有類似以下的 DOM 結構

<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>

而且您想將產品 B 新增至購物車,僅使用 CSS 選擇器會很困難。

使用選擇器鏈接,會更容易。只需逐步縮小所需的元素範圍

await $('.row .entry:nth-child(2)').$('button*=Add').click()

Appium 影像選擇器

使用 -image 定位器策略,可以將 Appium 傳送一個代表您要存取之元素的影像檔案。

支援的檔案格式 jpg、png、gif、bmp、svg

完整的參考資料可以在此處找到

const elem = await $('./file/path/of/image/test.jpg')
await elem.click()

注意:Appium 使用此選擇器的方式是它會在內部製作一個(應用程式)螢幕快照,並使用提供的影像選擇器來驗證是否可以在該(應用程式)螢幕快照中找到該元素。

請注意,Appium 可能會調整擷取的(應用程式)螢幕快照大小,使其與您的(應用程式)螢幕的 CSS 大小相符(這將發生在 iPhone 上,以及具有 Retina 顯示器的 Mac 電腦上,因為 DPR 大於 1)。這會導致找不到相符項目,因為提供的影像選擇器可能是從原始螢幕快照中擷取的。您可以透過更新 Appium Server 設定來修正此問題,請參閱 Appium 文件以取得設定,以及 此評論以取得詳細說明。

React 選擇器

WebdriverIO 提供了一種基於元件名稱選擇 React 元件的方法。為此,您可以選擇兩個命令:react$react$$

這些命令允許您從 React VirtualDOM 選擇元件,並傳回單個 WebdriverIO 元素或元素陣列(取決於使用的函式)。

注意:命令 react$react$$ 在功能上類似,只是 react$$ 會傳回所有相符的實例作為 WebdriverIO 元素的陣列,而 react$ 會傳回找到的第一個實例。

基本範例

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent() {
return (
<div>
MyComponent
</div>
)
}

function App() {
return (<MyComponent />)
}

ReactDOM.render(<App />, document.querySelector('#root'))

在上面的程式碼中,應用程式內部有一個簡單的 MyComponent 實例,React 會將其呈現在 id="root" 的 HTML 元素內。

使用 browser.react$ 命令,您可以選擇 MyComponent 的實例

const myCmp = await browser.react$('MyComponent')

現在,您已將 WebdriverIO 元素儲存在 myCmp 變數中,您可以對其執行元素命令。

篩選元件

WebdriverIO 在內部使用的程式庫允許您依據元件的 props 和/或狀態篩選您的選擇。若要執行此操作,您需要為 props 傳遞第二個引數,以及為狀態傳遞第三個引數至瀏覽器命令。

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent(props) {
return (
<div>
Hello { props.name || 'World' }!
</div>
)
}

function App() {
return (
<div>
<MyComponent name="WebdriverIO" />
<MyComponent />
</div>
)
}

ReactDOM.render(<App />, document.querySelector('#root'))

如果您想選擇具有 props name 作為 WebdriverIOMyComponent 實例,您可以像這樣執行命令

const myCmp = await browser.react$('MyComponent', {
props: { name: 'WebdriverIO' }
})

如果您想依據狀態篩選我們的選擇,browser 命令會如下所示

const myCmp = await browser.react$('MyComponent', {
state: { myState: 'some value' }
})

處理 React.Fragment

當使用 react$ 命令選擇 React 片段時,WebdriverIO 會傳回該元件的第一個子元素作為元件的節點。如果您使用 react$$,您將收到一個陣列,其中包含片段中所有符合選擇器的 HTML 節點。

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent() {
return (
<React.Fragment>
<div>
MyComponent
</div>
<div>
MyComponent
</div>
</React.Fragment>
)
}

function App() {
return (<MyComponent />)
}

ReactDOM.render(<App />, document.querySelector('#root'))

以上述範例來說,這些指令的運作方式如下:

await browser.react$('MyComponent') // returns the WebdriverIO Element for the first <div />
await browser.react$$('MyComponent') // returns the WebdriverIO Elements for the array [<div />, <div />]

注意:如果您有多個 MyComponent 實例,並且您使用 react$$ 來選取這些片段元件,則會回傳一個包含所有節點的一維陣列。換句話說,如果您有 3 個 <MyComponent /> 實例,則會回傳一個包含六個 WebdriverIO 元素的陣列。

自訂選取器策略

如果您的應用程式需要以特定方式擷取元素,您可以定義自己的自訂選取器策略,並與 custom$custom$$ 一起使用。為此,請在測試開始時(例如在 before hook 中)註冊您的策略。

queryElements/customStrategy.js
loading...

假設有以下 HTML 片段:

queryElements/example.html
loading...

然後透過呼叫來使用它:

queryElements/customStrategy.js
loading...

注意:這僅在可以執行 execute 命令的 Web 環境中有效。

歡迎!我能幫您什麼嗎?

WebdriverIO AI Copilot