Концепция Angular-специфичных локаторов

Protractor является инструментом для автоматизированного тестирования веб-приложений на базе Angular. Одной из его ключевых особенностей является поддержка Angular-специфичных локаторов, которые позволяют взаимодействовать с элементами страницы, используя внутренние особенности фреймворка Angular. Это обеспечивает более надежное и точное определение элементов по сравнению с традиционными CSS или XPath локаторами.


Основные Angular-локаторы

1. by.model() Используется для поиска элементов, связанных с ng-model. Такой локатор особенно полезен при работе с формами, полями ввода и элементами, где данные двусторонне связываются с моделью Angular.

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

let usernameInput = element(by.model('user.name'));
usernameInput.sendKeys('admin');

Здесь user.name — это имя модели в Angular-контроллере. Любое изменение значения в этом поле автоматически синхронизируется с моделью.


2. by.binding() Позволяет находить элементы, в которых отображаются данные через биндинг Angular ({{ }}). Это полезно для проверки текста на странице, который динамически обновляется.

Пример:

let greeting = element(by.binding('user.greeting'));
expect(greeting.getText()).toEqual('Привет, админ!');

Если значение в модели user.greeting изменится, локатор найдет обновленный текст без необходимости дополнительного поиска по DOM.


3. by.repeater() Используется для работы с повторяющимися элементами, определенными через директиву ng-repeat. Позволяет получать как отдельные элементы списка, так и все элементы целиком.

Примеры:

// Получение всех элементов списка
let items = element.all(by.repeater('item in items'));

// Получение первого элемента списка
let firstItem = element(by.repeater('item in items').row(0));

// Получение конкретной колонки в ряду
let price = element(by.repeater('item in items').row(1).column('item.price'));

Использование by.repeater() обеспечивает точное взаимодействие с динамическими коллекциями данных Angular без сложных CSS-селекторов.


4. by.options() Применяется для выбора <option> внутри <select> элементов, где значения генерируются через ng-options.

Пример:

let dropdown = element(by.model('user.role'));
dropdown.element(by.options('role.id as role.name for role in roles')).click();

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


5. by.cssContainingText() и by.exactBinding() by.cssContainingText() часто используется вместе с Angular для поиска элементов по тексту, особенно когда биндинги сложные или содержат HTML. by.exactBinding() применяется для точного соответствия биндинга.

Примеры:

// Любой элемент с текстом "Привет"
let greeting = element(by.cssContainingText('.greeting', 'Привет'));

// Элемент с точным биндингом
let username = element(by.exactBinding('user.name'));

Синхронизация с Angular

Одним из преимуществ Protractor является автоматическая синхронизация с Angular. Это означает, что перед взаимодействием с элементами Protractor ожидает завершения всех асинхронных операций Angular, включая HTTP-запросы и таймеры. Благодаря этому локаторы работают надежнее, и не возникает ошибок, связанных с тем, что элемент еще не отрендерился.

Пример:

element(by.model('user.name')).sendKeys('admin');
// Не требуется использовать sleep или explicit wait для ожидания загрузки Angular

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

  • Для форм и полей ввода использовать by.model().
  • Для динамически изменяемого текста применять by.binding() или by.exactBinding().
  • Для списков и таблиц выбирать by.repeater().
  • Для селекторов <select>by.options().
  • В сложных случаях комбинировать Angular-локаторы с CSS для точного таргетирования.

Использование Angular-локаторов повышает устойчивость тестов, делает их более читаемыми и уменьшает зависимость от структуры HTML, которая может изменяться при редизайне интерфейса.


Особенности и ограничения

  • Angular-локаторы работают только с приложениями на AngularJS или Angular 2+.
  • Если на странице смешанный код с Angular и обычный HTML, для элементов вне Angular придется использовать стандартные локаторы (by.css, by.id).
  • Сложные директивы могут требовать комбинированного подхода, когда используется by.repeater() вместе с .row() и .column() для точного выбора.

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