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

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


Основные принципы работы by.binding()

by.binding() ищет элементы, которые используют выражение Angular в шаблоне. Например, в шаблоне Angular можно встретить конструкцию:

<p>{{username}}</p>

В этом случае username является binding. С помощью by.binding() можно получить ссылку на элемент, отображающий значение этой переменной:

let usernameElement = element(by.binding('username'));

Ключевой момент: Protractor понимает Angular-specific bindings и корректно ожидает изменения данных в асинхронном режиме, что облегчает работу с динамическим контентом.


Синтаксис и использование

Синтаксис:

element(by.binding('bindingName'));
  • bindingName — имя переменной или выражения, к которому привязан элемент.
  • Локатор возвращает объект ElementFinder, с которым можно взаимодействовать с помощью методов getText(), click(), isDisplayed() и других.

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

let greeting = element(by.binding('greetingMessage'));
greeting.getText().then(function(text) {
    console.log(text);
});

Если в шаблоне Angular присутствует более сложное выражение:

<p>{{user.firstName + ' ' + user.lastName}}</p>

его можно искать точно так же, используя весь выраженный текст в by.binding():

let fullName = element(by.binding("user.firstName + ' ' + user.lastName"));

Особенности работы с by.binding()

  1. Поддержка вложенных объектов Можно обращаться к свойствам объектов внутри binding:

    <span>{{user.address.city}}</span>

    Локатор:

    element(by.binding('user.address.city'));
  2. Автоматическая синхронизация с Angular Protractor автоматически ждёт завершения асинхронных операций Angular перед выполнением действий над найденным элементом. Это избавляет от необходимости ручного использования browser.wait() для стандартных Angular-компонентов.

  3. Использование в списках и таблицах Если binding встречается в повторяющемся элементе ng-repeat:

    <li ng-repeat="item in items">{{item.name}}</li>

    Получение всех элементов:

    let items = element.all(by.binding('item.name'));
    items.each(function(elem) {
        elem.getText().then(function(text) {
            console.log(text);
        });
    });
  4. Ограничения

    • Работает только с Angular-приложениями.
    • Не поддерживает не Angular-шаблоны или элементы, рендеренные вне зоны Angular.
    • Для динамически обновляемых binding выражений требуется убедиться, что Angular завершил обновление модели.

Советы по эффективному использованию

  • Предпочтительно использовать точные binding-имена, избегая коротких или неоднозначных выражений, чтобы локатор находил только нужный элемент.
  • В комбинации с element.all() можно создавать коллекции элементов для валидации списков.
  • Для сложных выражений рекомендуется сначала проверить их наличие в DOM с помощью isPresent():
let bindingElement = element(by.binding('complex.expression'));
bindingElement.isPresent().then(function(present) {
    if (present) {
        console.log('Элемент найден');
    } else {
        console.log('Элемент отсутствует');
    }
});
  • При работе с асинхронными данными, изменяемыми через Angular сервисы, by.binding() корректно обновляет значение без дополнительных ожиданий.

Примеры практического применения

  1. Проверка текста после ввода данных
element(by.model('user.name')).sendKeys('Иван');
expect(element(by.binding('user.name')).getText()).toEqual('Иван');
  1. Валидация списка пользователей
let users = element.all(by.binding('user.name'));
expect(users.count()).toBe(5);
  1. Проверка сложного выражения
let fullName = element(by.binding("user.firstName + ' ' + user.lastName"));
expect(fullName.getText()).toContain('Иван Иванов');

by.binding() является мощным инструментом для тестирования Angular-приложений, позволяя напрямую связываться с данными, отображаемыми в DOM. Использование этого локатора упрощает автоматизацию, минимизирует задержки, связанные с ожиданием асинхронных обновлений, и делает тесты более читаемыми и устойчивыми.