Селекторы
Протокол 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') | ✅ Хорошо | Хорошо. Отражает, как пользователь взаимодействует со страницей. Рекомендуется использовать файлы перевода, чтобы ваши тесты не ломались при обновлении переводов. Примечание: Этот селектор может работать медленнее других на больших страницах. |
$('button=Submit') | ✅ Всегда | Лучший. Отражает, как пользователь взаимодействует со страницей и работает быстро. Рекомендуется использовать файлы перевода, чтобы ваши тесты не ломались при обновлении переводов. |
CSS селектор запроса
Если не указано иное, WebdriverIO будет запрашивать элементы с использованием шаблона CSS селектора, например:
loading...
Текст ссылки
Чтобы получить элемент привязки с определенным текстом, запрашивайте текст, начинающийся со знака равенства (=).
Например:
loading...
Вы можете запросить этот элемент, вызвав:
loading...
Частичный текст ссылки
Чтобы найти элемент привязки, чей видимый текст частично совпадает с вашим значением поиска,
запросите его, используя *= перед строкой запроса (например, *=driver).
Вы также можете запросить элемент из примера выше, вызвав:
loading...
Примечание: Вы не можете смешивать несколько стратегий селекторов в одном селекторе. Используйте несколько цепочек запросов элементов для достижения той же цели, например:
const elem = await $('header h1*=Welcome') // не работает!!!
// используйте вместо этого
const elem = await $('header').$('*=driver')
Элемент с определенным текстом
Та же техника может быть применена и к элементам. Кроме того, также возможно выполнить сопоставление без учета регистра с использованием .= или .*= в запросе.
Например, вот запрос для заголовка первого уровня с текстом "Welcome to my Page":
loading...
Вы можете запросить этот элемент, вызвав:
loading...
Или используя запрос частичного текста:
loading...
То же самое работает для имен id и class:
loading...
Вы можете запросить этот элемент, вызвав:
loading...
Примечание: Вы не можете смешивать несколько стратегий селекторов в одном селекторе. Испо льзуйте несколько цепочек запросов элементов для достижения той же цели, например:
const elem = await $('header h1*=Welcome') // не работает!!!
// используйте вместо этого
const elem = await $('header').$('h1*=Welcome')
Имя тега
Чтобы запросить элемент с определенным именем тега, используйте <tag> или <tag />.
loading...
Вы можете запросить этот элемент, вызвав:
loading...
Атрибут Name
Для запроса элементов с определенным атрибутом name вы можете использовать обычный селектор CSS3 или предоставленную стратегию name из JSONWireProtocol, передав что-то вроде [name="some-name"] в качестве параметра селектора:
loading...
loading...
Примечание: Эта стратегия селектора устарела и работает только в старых браузерах, которые работают по протоколу JSONWireProtocol или при использовании Appium.
xPath
Также возможно запрашивать элементы с помощью определенного xPath.
Селектор xPath имеет формат типа //body/div[6]/div[1]/span[1].
loading...
Вы можете запросить второй параграф, вызвав:
loading...
Вы можете использовать xPath для перемещения вверх и вниз по дереву DOM:
loading...
Селектор доступного имени
Запрос элементов по их доступному имени. Доступное имя - это то, что объявляется программой чтения с экрана, когда этот элемент получает фокус. Значение доступного имени может быть как визуальным контентом, так и скрытыми текстовыми альтернативами.
Вы можете прочитать больше об этом селекторе в нашем блоге о релизе
Получение по aria-label
loading...
loading...
Получение по aria-labelledby
loading...
loading...
Получение по содержимому
loading...
loading...
Получение по заголовку
loading...
loading...
Получение по свойству alt
loading...
loading...
ARIA - Атрибут Role
Для запроса элементов на основе ролей ARIA, вы можете напрямую указать роль элемента, например, [role=button] в качестве параметра селектора:
loading...
loading...
Атрибут ID
Стратегия локатора "id" не поддерживается в протоколе WebDriver, вместо этого следует использовать стратегии селекторов CSS или xPath для поиска элементов по ID.
Однако некоторые драйверы (например, Appium You.i Engine Driver) могут поддерживать этот селектор.
Текущие поддерживаемые синтаксисы селектора для ID:
//css локатор
const button = await $('#someid')
//xpath локатор
const button = await $('//*[@id="someid"]')
//стратегия id
// Примечание: работает только в Appium или подобных фреймворках, поддерживающих стратегию локатора "ID"
const button = await $('id=resource-id/iosname')
JS функция
Вы также можете использовать функции JavaScript для получения элементов с использованием нативных веб-API. Конечно, вы можете делать это только в веб-контексте (например, browser или веб-контекст на мобильных устройствах).
Учитывая следующую структуру HTML:
loading...
Вы можете запросить соседний элемент #elem следующим образом:
loading...
Глубокие селекторы
Начиная с v9 WebdriverIO, нет необходимости в этом специальном селекторе, так как WebdriverIO автоматически проникает через Shadow DOM для вас. Рекомендуется отказаться от этого селектора, удалив >>> перед ним.
Многие фронтенд-приложения сильно зависят от элементов с shadow DOM. Технически невозможно запрашивать элементы внутри shadow DOM без обходных путей. Функции shadow$ и shadow$$ были такими обходными путями, которые имели свои ограничения. С помощью глубокого селектора теперь вы можете запрашивать все элементы внутри любого shadow DOM, используя общую команду запроса.
Предположим, у нас есть приложение со следующей структурой:

С этим селектором вы можете запросить элемент <button />, который вложен в другой shadow DOM, например:
loading...
Мобильные селекторы
Для гибридного мобильного тестирования важно, чтобы сервер автоматизации находился в правильном контексте перед выполнением команд. Для автоматизации жестов драйвер в идеале должен быть установлен в нативный контекст. Но для выбора элементов из DOM драйвер должен быть установлен в контекст webview платформы. Только после этого могут быть использованы методы, упомянутые выше.
Для нативного мобильного тестирования нет переключения между контекстами, так как вы должны использовать мобильные стратегии и использовать базовую технологию автоматизации устройства напрямую. Это особенно полезно, когда тесту необходим тонкий контроль над поиском элементов.
Android UiAutomator
Фреймворк Android UI Automator предоставляет несколько способов поиска элементов. Вы можете использовать API UI Automator, в частности, класс 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)
Стратегия тега представления предоставляет удобный способ поиска элементов по их тегам.
const elem = await $('-android viewtag:tag_identifier')
await elem.click()
iOS UIAutomation
При автоматизации приложения iOS можно использовать UI Automation framework от Apple для поиска элементов.
Этот 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 предназначена для чтения уникального идентификатора элемента пользовательского интерфейса. Это имеет преимущество в том, что не меняется при локализации или любом другом процессе, который может изменить текст. Кроме того, это может помочь в создании кроссплатф орменных тестов, если элементы, которые функционально одинаковы, имеют одинаковый accessibility id.
- Для iOS это
accessibility identifier, установленный Apple здесь. - Для Android
accessibility idсопоставляется сcontent-descriptionдля элемента, как описано здесь.
Для обеих платформ получение элемента (или нескольких элементов) по их accessibility id обычно является лучшим методом. Это также предпочтительный способ по сравнению с устаревшей стратегией name.
const elem = await $('~my_accessibility_identifier')
await elem.click()
Имя класса
Стратегия class name - это строка, представляющая элемент пользовательского интерфейса в текущем представлении.
- Для iOS это полное имя класса UIAutomation, и оно будет начинаться с
UIA-, например,UIATextFieldдля текстового поля. Полный справочник можно найти здесь. - Для Android это полностью квалифицированное имя класса UI Automator class, такое как
android.widget.EditTextдля текстового поля. Полный справочник можно найти здесь. - Для Youi.tv это полное имя класса Youi.tv, и оно будет начинаться с
CYI-, например,CYIPushButtonViewдля элемента кнопки push. Полный справочник можно найти на странице GitHub You.i Engine Driver
// пример iOS
await $('UIATextField').click()
// пример Android
await $('android.widget.DatePicker').click()
// пример Youi.tv
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 работает с этим селектором, заключается в том, что он внутренне делает (app)скриншот и использует предоставленный селектор изображения для проверки, может ли элемент быть найден на этом (app)скриншоте.
Имейте в виду, что Appium может изменить размер сделанного (app)скриншота, чтобы он соответствовал CSS-размеру вашего (app)экрана (это произойдет на 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' }
})
Если вы хотите фильтровать наш выбор по состоянию, команда 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') // возвращает элемент WebdriverIO для первого <div />
await browser.react$$('MyComponent') // возвращает элементы WebdriverIO для массива [<div />, <div />]
Примечание: Если у вас несколько экземпляров MyComponent и вы используете react$$ для выбора этих компонентов фрагментов, вам будет возвращен одномерный массив всех узлов. Другими словами, если у вас есть 3 экземпляра <MyComponent />, вам будет возвращен массив с шестью элементами WebdriverIO.
Пользовательские стратегии селекторов
Если ваше приложение требует определенного способа получения элементов, вы можете определить свою собственную стратегию селектора, которую можно использовать с custom$ и custom$$. Для этого зарегистрируйте свою стратегию один раз в начале теста, например, в хуке before:
loading...
Учитывая следующий HTML-фрагмент:
loading...
Затем используйте его, вызвав:
loading...
Примечание: это работает только в веб-среде, в которой может быть запущена команда execute.