В веб-приложениях элементы <select> используются
для предоставления пользователю списка вариантов, из которых можно
выбрать один или несколько. В автоматизированном тестировании такие
элементы требуют особого подхода, так как взаимодействие с ними
отличается от работы с обычными полями ввода. Protractor предоставляет
инструменты для управления <select> и его
<option>.
Для начала необходимо получить ссылку на сам элемент
<select>. Используются стандартные локаторы
Protractor:
const selectElement = element(by.id('country'));
Каждый <option> внутри select также можно найти
через element.all():
const options = selectElement.all(by.tagName('option'));
element.all() возвращает массив элементов, с которым
можно производить итерации или выбирать конкретные варианты по индексу,
тексту или значению.
Наиболее читаемый и часто используемый способ — выбор опции по её
видимому тексту. В Protractor это делается с использованием метода
filter и click:
const desiredText = 'Россия';
options.filter(async (option) => {
const text = await option.getText();
return text === desiredText;
}).first().click();
Важно использовать async/await, чтобы дождаться
получения текста каждой опции перед сравнением.
Иногда удобнее выбирать опцию по значению атрибута
value, особенно если текст может изменяться или содержит
пробелы:
const desiredValue = 'RU';
options.filter(async (option) => {
const value = await option.getAttribute('value');
return value === desiredValue;
}).first().click();
Метод getAttribute('value') извлекает значение
value, указанное в HTML, что делает выбор более стабильным
при изменениях интерфейса.
Если порядок опций известен и фиксирован, можно выбрать элемент по индексу:
await options.get(2).click(); // выбираем третью опцию, индексация с нуля
Метод get(index) возвращает элемент из коллекции
element.all(), что позволяет работать с конкретной позицией
без поиска по тексту или значению.
Если <select> поддерживает атрибут
multiple, можно выбирать несколько значений:
const multipleSelect = element(by.id('fruits'));
const fruitsToSelect = ['Яблоко', 'Банан'];
for (const fruit of fruitsToSelect) {
await multipleSelect.all(by.tagName('option'))
.filter(async (option) => {
const text = await option.getText();
return text === fruit;
}).first().click();
}
В данном примере происходит последовательный клик по нужным элементам, что позволяет имитировать множественный выбор пользователя.
Для тестирования важно убедиться, что нужный элемент выбран. У
каждого <option> есть свойство
selected:
const selectedOption = await selectElement.element(by.css('option:checked')).getText();
console.log(selectedOption); // выводит текст выбранной опции
Использование CSS-селектора option:checked позволяет
получить активный элемент, что удобно для проверок в тестах.
Для упрощения работы с <select> полезно создавать
утилитарные функции:
async function selectByText(selectElem, text) {
const options = selectElem.all(by.tagName('option'));
await options.filter(async (option) => {
return await option.getText() === text;
}).first().click();
}
async function selectByValue(selectElem, value) {
const options = selectElem.all(by.tagName('option'));
await options.filter(async (option) => {
return await option.getAttribute('value') === value;
}).first().click();
}
Это повышает читаемость тестов и уменьшает дублирование кода.
Иногда опции <select> подгружаются динамически
через AJAX. В таких случаях необходимо дождаться появления элементов
перед выбором:
const EC = protractor.ExpectedConditions;
await browser.wait(EC.presenceOf(selectElement), 5000);
await selectByText(selectElement, 'Россия');
Использование ExpectedConditions гарантирует, что тест
не упадет из-за отсутствия элемента в DOM на момент взаимодействия.
Protractor изначально разработан для Angular-приложений, поэтому он
автоматически синхронизируется с Angular-зоной. Для
<select> это означает, что обычно нет необходимости
использовать browser.sleep(), если приложение полностью
основано на Angular. Однако при работе с внешними плагинами или
нестандартными компонентами <select> иногда требуется
явное ожидание.
Некоторые библиотеки UI заменяют обычный <select>
кастомными компонентами. В этом случае взаимодействие через
option невозможно, необходимо кликать по элементам,
имитирующим опции:
const dropdown = element(by.css('.custom-dropdown'));
await dropdown.click();
const optionToSelect = dropdown.element(by.cssContainingText('.dropdown-item', 'Россия'));
await optionToSelect.click();
Такая реализация универсальна для любых кастомных селекторов, не
зависящих от стандартного <select>.
filter вместо поиска через
element(by.cssContainingText()), если требуется точное
совпадение.value, если текст может
меняться.selected.Работа с <select> в Protractor требует
внимательности к асинхронности и правильного ожидания элементов. Следуя
описанным подходам, можно надежно управлять как стандартными, так и
кастомными выпадающими списками в автоматизированных тестах.