В автоматизированном тестировании веб-приложений с использованием Protractor критически важно уметь работать не только с отдельными элементами страницы, но и с группами элементов. Поиск множества элементов позволяет выполнять проверки, которые включают списки, таблицы, наборы кнопок или любых повторяющихся компонентов интерфейса.
Protractor предоставляет несколько способов получения коллекции элементов на странице:
element.all(locator) Основной метод
для работы с множеством элементов. Возвращает объект
ElementArrayFinder, который предоставляет набор методов для
работы с коллекцией.
let buttons = element.all(by.css('.btn'));
В данном примере buttons будет содержать все элементы с
классом btn.
Локаторы для поиска множества элементов
by.css(selector) — поиск по CSS-селектору. Позволяет
получать сразу несколько элементов.by.tagName(tag) — поиск по имени тега, полезно для
списков и таблиц.by.className(name) — поиск по имени класса.by.xpath(xpath) — гибкий способ поиска сложных
структур, когда CSS-селекторы недостаточны.let listItems = element.all(by.tagName('li'));
let highlightedRows = element.all(by.css('.table-row.highlighted'));ElementArrayFinder предоставляет методы, позволяющие
управлять множеством элементов как единым объектом, а также выполнять
проверки и взаимодействие с каждым элементом коллекции.
count() — возвращает количество
найденных элементов.
let totalButtons = element.all(by.css('.btn')).count();get(index) — получает элемент по
индексу. Индексация начинается с 0.
let firstButton = element.all(by.css('.btn')).get(0);
let lastButton = element.all(by.css('.btn')).last();first() и last() —
удобные методы для получения первого и последнего элемента.
each(function(element, index) {...})
— позволяет выполнить функцию для каждого элемента коллекции.
element.all(by.css('.item')).each(function(elem, index) {
elem.getText().then(function(text) {
console.log(`Элемент ${index}: ${text}`);
});
});map(function(element, index) {...})
— преобразует коллекцию, возвращая массив результатов.
let texts = element.all(by.css('.item')).map(function(elem) {
return elem.getText();
});filter(function(element, index) {...})
— позволяет отфильтровать элементы по заданному условию.
let visibleButtons = element.all(by.css('.btn')).filter(function(elem) {
return elem.isDisplayed();
});При работе с множеством элементов важно учитывать асинхронность.
Методы count(), getText(),
isDisplayed() возвращают промисы. Для обработки
используется await в сочетании с async
функциями:
let buttons = element.all(by.css('.btn'));
let total = await buttons.count();
for (let i = 0; i < total; i++) {
let text = await buttons.get(i).getText();
console.log(text);
}
Protractor автоматически синхронизируется с Angular-приложениями, но
для не-Angular страниц может потребоваться использование
browser.wait и ExpectedConditions:
let EC = protractor.ExpectedConditions;
let items = element.all(by.css('.list-item'));
await browser.wait(EC.visibilityOf(items.first()), 5000);
Для сложных структур часто нужно искать элементы внутри родительского
элемента. Protractor поддерживает метод all на объекте
ElementFinder:
let table = element(by.css('.table'));
let rows = table.all(by.css('tr'));
await rows.each(async function(row) {
let columns = row.all(by.css('td'));
let texts = await columns.map(col => col.getText());
console.log(texts);
});
Это позволяет работать с таблицами, списками и повторяющимися блоками интерфейса, сохраняя структуру данных и упрощая проверку содержимого.
ElementArrayFinder возвращают промисы, поэтому важно
использовать await или цепочки .then().element.all() не
выполняет поиск немедленно, поиск происходит только при вызове метода,
который требует реальные элементы (count(),
get(), each()).expect(await element.all(by.css('.todo-item')).count()).toBe(5);
let itemsText = await element.all(by.css('.menu-item')).map(el => el.getText());
expect(itemsText).toContain('Настройки');
let buttons = element.all(by.css('.btn')).filter(btn => btn.isDisplayed());
await buttons.get(0).click();
Использование методов поиска множества элементов делает тесты более гибкими, позволяет работать с динамическим контентом и минимизирует дублирование кода при проверке повторяющихся компонентов интерфейса.