Protractor — специализированный инструмент для end-to-end
тестирования Angular-приложений. Одной из ключевых особенностей Angular
является директива ng-repeat (или современный аналог
*ngFor в Angular 2+), которая позволяет динамически
генерировать списки элементов на основе массива данных. В тестировании
важно уметь корректно взаимодействовать с такими повторяющимися
элементами.
Protractor предоставляет встроенный локатор by.repeater,
который позволяет находить элементы, созданные с помощью директив
ng-repeat. Основной синтаксис:
element.all(by.repeater('item in items'))
где 'item in items' — это выражение, указанное в
ng-repeat или *ngFor.
element.all() возвращает объект
ElementArrayFinder, который позволяет работать с набором
элементов.element(by.repeater(...)) возвращает первый найденный
элемент повторителя (ElementFinder).Примеры:
// Найти все элементы повторителя
let rows = element.all(by.repeater('user in users'));
// Найти первый элемент повторителя
let firstRow = element(by.repeater('user in users'));
Элементы повторителя часто используются для проверки содержимого
таблиц и списков. ElementArrayFinder предоставляет методы
для работы с набором элементов.
// Получение всех текстовых значений элементов повторителя
rows.getText().then(function(texts) {
console.log(texts);
});
// Получение значения атрибута 'class' первого элемента
firstRow.getAttribute('class').then(function(attr) {
console.log(attr);
});
Метод get(index) позволяет получить конкретный элемент
из повторителя по индексу:
let thirdRow = rows.get(2); // Индексация с 0
thirdRow.getText().then(text => console.log(text));
Angular позволяет использовать повторители внутри других повторителей. Protractor поддерживает поиск вложенных элементов через цепочку локаторов:
let nestedElements = element.all(by.repeater('user in users'))
.all(by.repeater('order in user.orders'));
В этом примере для каждого пользователя извлекаются его заказы.
Методы all() можно комбинировать для любого уровня
вложенности.
Локатор by.repeater поддерживает уточнение
выражений:
.row(index) — получение конкретной строки
повторителя..column('user.name') — извлечение данных конкретного
свойства для всех элементов повторителя.Пример:
// Получить значения поля 'name' для всех пользователей
rows.column('user.name').then(function(names) {
console.log(names);
});
// Получить текст из второй строки
rows.get(1).getText().then(text => console.log(text));
Эти методы позволяют тестировать таблицы с данными без привязки к конкретной разметке, только через привязки данных Angular.
В Angular-приложениях данные повторителей часто обновляются асинхронно. Для корректного тестирования важно использовать ожидания:
let EC = protractor.ExpectedConditions;
let rows = element.all(by.repeater('user in users'));
// Ждать, пока появятся хотя бы 3 элемента
browser.wait(EC.presenceOf(rows.get(2)), 5000);
ExpectedConditions позволяет избегать гонок и ошибок,
связанных с тем, что элементы еще не загружены на странице.
Protractor позволяет не только получать данные, но и взаимодействовать с элементами:
// Нажать на кнопку в третьей строке повторителя
rows.get(2).element(by.buttonText('Редактировать')).click();
// Ввести текст в input внутри повторителя
rows.get(0).element(by.model('user.name')).sendKeys('Новый текст');
Использование element внутри
ElementArrayFinder позволяет работать с конкретными
элементами повторителя, независимо от того, сколько их на странице.
Для упрощения работы с повторителями часто создают функции-обертки:
function getUserRow(index) {
return element.all(by.repeater('user in users')).get(index);
}
function getUserName(index) {
return getUserRow(index).element(by.binding('user.name')).getText();
}
getUserName(1).then(name => console.log(name));
Такой подход повышает читаемость тестов и позволяет легко изменять локаторы в одном месте.
Protractor также поддерживает современные версии Angular с директивой
*ngFor. Локатор by.repeater работает, если
указано точное выражение итератора:
element.all(by.repeater('let user of users'));
Все методы для работы с массивами элементов (get,
getText, element, all)
сохраняются. Отличие только в синтаксисе повторителя.
element.all(by.repeater('item in items')) — получение
всех элементов повторителя.get(index) — доступ к элементу по индексу.getText() — извлечение текста.getAttribute(attr) — получение атрибута.element(locator) — поиск вложенного элемента внутри
повторителя.column('binding') — получение данных конкретного
свойства для всех элементовExpectedConditions для работы с
динамическими спискамиЭти инструменты позволяют создавать стабильные и читаемые тесты для всех сценариев, связанных с повторяющимися элементами Angular-приложений.