Перейти до основного вмісту

Селектори

WebDriver протокол надає кілька типів селекторів для пошуку елемента. WebdriverIO спрощує їх, щоб зробити пошук елементів простішим. Зауважте, що попри те, що команди для пошуку елементів називаються $ та $$, вони не мають нічого спільного з jQuery або Sizzle Selector Engine.

Зауважте, що не всі із великої кількості типів селекторів можуть забезпечити, надійний пошук потрібного вам елемента. Наприклад, маючи таку кнопку:

<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"]')⚠️ ОбережноЗв'язаний із атрибутом name, який має семантику HTML.
$('button[data-testid="submit"]')✅ МожнаВимагає додаткових атрибутів, не пов'язаних із доступністю.
$('aria/Submit') or $('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 із текстом "Welcome to my Page":

selectors/example.html
loading...

Ви можете знайти цей елемент, викликавши:

selectors/example.js
loading...

Або використовуючи пошук за частковим збігом тексту:

selectors/example.js
loading...

Те саме працює для атрибутів id та class:

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...

Атрибут name

Для запиту елементів із певним атрибутом name ви можете використовувати звичайний CSS селектор або спеціальний тип пошуку за цим атрибутом, що реалізований у JSONWire протоколі, вказавши щось на зразок [name="some-name"] у своєму селекторі:

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

Примітка: Цей тип пошуку застарів та працює лише в старих браузерах, які працюють із JSONWire протоколом або з 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

Тип пошуку «id» не підтримується протоколом WebDriver, замість цього слід використовувати 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 для пошуку елементів використовуючи вбудоване API. Звичайно, ви можете зробити це лише всередині вебконтексту (наприклад у браузері або вебконтексті на мобільному пристрої).

Маючи наступну структуру HTML:

selectors/js.html
loading...

Ви можете запитати сусідній від #elem елемент наступним чином:

selectors/example.js
loading...

Глибокі селектори

Багато вебзастосунків інтегрують елементи із тіньовим DOM. Без обхідних шляхів пошук елементів у тіньовому DOM є технічно неможливим. shadow$ і shadow$$ були такими обхідними шляхами, які мали свої обмеження. Але тепер за допомогою глибокого селектора ви можете шукати елементи всередині будь-якого тіньового DOM використовуючи стандартну функцію для пошуку.

Маючи вебзастосунок із такою структурою:

Приклад Chrome

За допомогою цього селектора ви можете знайти елемент <button />, який розташований в іншому тіньову DOM, наприклад:

selectors/example.js
loading...

Мобільні селектори

Для гібридного мобільного тестування важливо, щоб сервер автоматизації був у потрібному контексті перед виконанням команд. Для автоматизації жестів драйвер в ідеалі має бути налаштований на головний контекст. Але щоб знайти елементи у DOM, драйвер потрібно налаштувати на контекст вебпереглядача. Лише тоді можна використовувати методи, згадані вище.

Для нативного мобільного тестування не потрібно змінювати контексти, оскільки вам потрібно використовувати спеціальні мобільні типи селекторів та використовувати безпосередньо базову технологію автоматизації пристрою. Це особливо корисно, коли тест потребує тонкого контролю над пошуком елементів.

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)

Тип DataMatcher від Espresso забезпечує пошук елементів за DataMatcher

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

І аналогічно ViewMatcher

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

Ви також можете використовувати предикатний пошук з iOS UI Automation в Appium, щоб ще більш точно вибирати елементи. Дивіться тут щоб дізнатися більше.

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

Accessibility ID

Тип пошуку accessibility id призначена для пошуку за унікальним ідентифікатором елемента інтерфейсу користувача. Цей спосіб має перевагу, оскільки ідентифікатор не змінюється під час локалізації чи будь-якого іншого процесу. Крім того, це може бути корисно при створенні кросплатформних тестів, коли функціонально однакові елементи мають однаковий ідентифікатор доступності.

  • Для iOS це accessibility identifier викладений Apple тут.
  • Для Android accessibility id відповідає content-description елемента, як описано тут.

Для обох платформ зазвичай найкращим методом є пошук елемента (або кількох елементів) за їхнім accessibility id. Використання цього типу селекторів, також є більш бажаним за використання застарілого типу name.

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

Назва класу

Назва класу — це рядок, який представляє елемент інтерфейсу користувача у поточному контексті.

  • Для iOS це повна назва класу UIAutomation, що починається з UIA-, наприклад UIATextField для текстового поля. Повну довідку можна знайти тут.
  • Для Android це повна назва UI Automator класу, наприклад android.widget.EditText для текстового поля. Повну довідку можна знайти тут.
  • Для Youi.tv це повна назва класу Youi.tv і що починається з CYI-, наприклад CYIPushButtonView для елемента кнопки. Повну довідку можна знайти на GitHub сторінці You.i Engine Driver
// iOS example
await $('UIATextField').click()
// Android example
await $('android.widget.DatePicker').click()
// Youi.tv example
await $('CYIPushButtonView').click()

Ланцюжок селекторів

Якщо ви хочете більше конкретизувати свій пошук, ви можете об'єднувати селектори, доки не дійдете до потрібного елементу. Якщо ви маєте інший елемент перед командою пошуку, 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, а також на комп’ютерах Mac із дисплеєм Retina, оскільки DPR більший ніж 1). Це призведе до того, що збіг не буде знайдено, оскільки наданий селектор зображення міг бути взятий з оригінального знімка екрана. Ви можете виправити це, оновивши налаштування сервера Appium, перегляньте документацію 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 відображає всередині елемента HTML з id="root".

За допомогою команди browser.react$ ви можете отримати доступ до екземпляра MyComponent:

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

Тепер, коли у вас є елемент WebdriverIO, збережений у змінній myCmp, ви можете виконувати різні команди елемента із ним.

Фільтрація компонентів

Бібліотека, яку WebdriverIO використовує, дозволяє фільтрувати компоненти за параметрами та/або станом. Для цього вам потрібно передати команді браузера другий аргумент для параметрів та/або третій аргумент для стану.

// 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'))

Якщо ви хочете отримати екземпляр MyComponent, який має параметр name зі значенням WebdriverIO, ви можете виконати таку команду:

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

Якщо ви хочете відфільтрувати компоненти за станом, команда виглядатиме приблизно так:

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

Робота з React.Fragment

У разі використання команди react$ для вибору React fragments 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$$. Для цього зареєструйте свій тип селектора один раз на початку тесту:

browser.addLocatorStrategy('myCustomStrategy', (selector, root) => {
/**
* scope should be document if called on browser object
* and `root` if called on an element object
*/
const scope = root ? root : document
return scope.querySelectorAll(selector)
})

Маючи наступну структуру HTML:

<div class="foobar" id="first">
<div class="foobar" id="second">
barfoo
</div>
</div>

Потім використовуйте його, викликавши:

const elem = await browser.custom$('myCustomStrategy', '.foobar')
console.log(await elem.getAttribute('id')) // returns "first"
const nestedElem = await elem.custom$('myCustomStrategy', '.foobar')
console.log(await elem.getAttribute('id')) // returns "second"

Примітка: це працюватиме лише у вебсередовищі, де можна запустити команду execute.

Welcome! How can I help?

WebdriverIO AI Copilot