by.exactRepeater() — специфичный для Angular

by.exactRepeater() — это один из локаторов в Protractor, предназначенный для работы с приложениями на Angular. Он позволяет точно идентифицировать элементы, созданные с помощью директивы ng-repeat, обеспечивая строгую привязку к повторяющимся выражениям. В отличие от by.repeater(), который ищет элементы по частичному совпадению шаблона, by.exactRepeater() выполняет точное соответствие, что снижает риск ошибок при наличии похожих повторяющихся блоков.

// Пример использования
let items = element.all(by.exactRepeater('item in itemList'));

Здесь item in itemList должно полностью совпадать с выражением, указанным в HTML. Любое дополнительное пространство или другое название переменной приведёт к тому, что элемент не будет найден.


Синтаксис и основные возможности

Сигнатура:

by.exactRepeater(repeaterString)
  • repeaterString — строка с точным выражением директивы ng-repeat.
  • Возвращает объект ElementArrayFinder, который представляет все элементы, соответствующие точному повторителю.

Ключевые моменты использования:

  1. Точность совпадения выражения обязательна.
  2. Поддерживает цепочки методов element() и element.all().
  3. Позволяет выполнять действия и получать данные для всех найденных элементов.

Пример получения текста всех элементов:

element.all(by.exactRepeater('item in itemList')).getText().then(function(texts) {
    console.log(texts);
});

Получение конкретного элемента из повторителя

Для работы с отдельными элементами внутри повторяющегося блока используется метод row(index):

let secondItem = element(by.exactRepeater('item in itemList').row(1));
  • Индексация начинается с нуля.
  • Можно комбинировать с методами .element() для поиска вложенных элементов:
let secondItemName = element(by.exactRepeater('item in itemList').row(1))
                       .element(by.css('.item-name'));

Получение столбцов (колонок) внутри повторителя

Если повторяющийся блок содержит таблицу или набор колонок, by.exactRepeater() позволяет извлекать данные конкретной колонки через метод column(columnName):

let itemPrices = element.all(by.exactRepeater('item in itemList').column('price'));
  • columnName должен совпадать с привязанной переменной внутри ng-repeat.
  • Возвращается массив всех значений выбранной колонки для всех строк.

Сравнение с by.repeater()

Свойство by.repeater() by.exactRepeater()
Совпадение выражения Частичное Точное
Подходит для Любых повторителей Когда важно точное соответствие
Риск ложных совпадений Есть Минимальный

Использование by.exactRepeater() рекомендуется там, где несколько похожих директив ng-repeat находятся на одной странице.


Работа с динамическими изменениями

Angular-приложения часто динамически изменяют содержимое ng-repeat. by.exactRepeater() корректно отслеживает изменения благодаря интеграции с Angular и Protractor’s waitForAngular():

let items = element.all(by.exactRepeater('item in itemList'));
browser.wait(function() {
    return items.count().then(function(count) {
        return count > 0;
    });
}, 5000);
  • Позволяет дождаться появления элементов перед взаимодействием.
  • Обеспечивает стабильность тестов при асинхронных обновлениях данных.

Частые ошибки при использовании

  1. Несовпадение пробелов или имен переменных: 'item in itemList' и ' item in itemList ' считаются разными выражениями.
  2. Попытка использовать с не-Angular приложениями: by.exactRepeater() работает только при наличии Angular.
  3. Игнорирование индекса при обращении к конкретной строке: без .row(index) возвращается массив элементов, а не одиночный элемент.
  4. Попытка доступа к колонке, которой нет: метод .column('columnName') выбрасывает ошибку, если columnName не привязан в ng-repeat.

Практические рекомендации

  • Использовать для точного выбора повторителей на страницах с множеством блоков ng-repeat.
  • Комбинировать с методами .row() и .column() для удобного доступа к отдельным данным.
  • Перед взаимодействием проверять количество элементов через .count().
  • Совмещать с browser.waitForAngular() для надежного выполнения асинхронных действий.

Пример комплексного использования

// Получить цену второго товара
let secondItemPrice = element(by.exactRepeater('item in itemList').row(1))
                      .element(by.binding('item.price'))
                      .getText();

// Проверить количество элементов
element.all(by.exactRepeater('item in itemList')).count().then(function(count) {
    expect(count).toBe(5);
});

// Получить все имена товаров
element.all(by.exactRepeater('item in itemList').column('item.name'))
       .getText().then(function(names) {
           console.log(names);
       });

Такой подход обеспечивает максимальную точность и устойчивость тестов в Angular-приложениях, особенно когда структура повторителей сложная и динамически изменяемая.