В Protractor работа с элементами страницы строится на использовании локаторов. Иногда одного локатора недостаточно для точного выбора элемента, особенно если структура DOM сложная или элементы имеют динамические атрибуты. Комбинирование локаторов позволяет создавать более гибкие и надежные селекторы.
Protractor наследует все возможности WebDriverJS, предоставляя стандартные локаторы:
by.id('value') — выбор по уникальному
идентификатору.by.css('selector') — выбор по CSS-селектору.by.className('value') — выбор по классу.by.tagName('tag') — выбор по имени тега.by.name('value') — выбор по атрибуту name.by.xpath('expression') — выбор с использованием
XPath.by.binding('angularBinding') — выбор
Angular-биндинга.by.model('modelName') — выбор по Angular-модели.Каждый локатор может использоваться отдельно, но при сложных структурах страницы требуется их комбинировать.
element внутри
element)Protractor позволяет находить дочерние элементы через метод
element:
let form = element(by.css('form.login-form'));
let usernameInput = form.element(by.name('username'));
let passwordInput = form.element(by.name('password'));
В этом примере сначала выбирается форма с классом
login-form, затем внутри формы выбираются поля
username и password. Такой подход уменьшает
риск выбора неправильного элемента при наличии нескольких одинаковых
полей на странице.
all и
фильтрацияМетод element.all() возвращает коллекцию элементов. Для
комбинирования локаторов часто используют цепочки методов:
let visibleButtons = element.all(by.css('.btn')).filter(function(btn) {
return btn.isDisplayed();
});
let firstVisibleButton = visibleButtons.first();
filter() позволяет отфильтровать элементы по
условию.first(), last() и get(index)
позволяют выбрать конкретный элемент из коллекции.Такой подход особенно полезен при работе с динамическими списками.
CSS-селекторы сами по себе поддерживают комбинации:
parent > childancestor descendant.class1.class2[attribute='value'],
[attribute^='start'], [attribute$='end'],
[attribute*='contains']Пример:
let submitButton = element(by.css('form.login-form button.btn.primary'));
Здесь сразу объединены форма, тег и классы, что делает локатор точным и читаемым.
XPath позволяет строить сложные выражения для выбора элементов:
let loginButton = element(by.xpath("//form[@class='login-form']//button[contains(@class, 'btn-primary')]"));
XPath особенно полезен, когда CSS не может выразить необходимую логику, например, выбор элемента по тексту:
let cancelButton = element(by.xpath("//button[text()='Cancel']"));
by.cssContainingTextProtractor предоставляет удобный локатор для поиска текста внутри элементов:
let menuItem = element(by.cssContainingText('ul.menu li', 'Settings'));
Можно комбинировать его с другими локаторами для точного выбора:
let submenuItem = element(by.css('ul.menu')).element(by.cssContainingText('li', 'Settings'));
by.model, by.binding,
by.repeater)Для Angular-приложений Protractor поддерживает локаторы специфичные для фреймворка:
let todoInput = element(by.model('newTodo'));
let firstTodo = element.all(by.repeater('todo INTOdos')).first();
let todoText = element(by.binding('todo.text'));
Комбинируя Angular-локаторы с CSS, можно точно выбрать элемент внутри повторяющихся блоков:
let completedTodo = element.all(by.repeater('todo INTOdos'))
.filter(todo => todo.element(by.model('todo.completed')).isSelected())
.first();
element или
all.let firstActiveUserEditButton = element.all(by.css('div.user-list div.user.active'))
.filter(user => user.element(by.css('span.status')).getText().then(text => text === 'Active'))
.first()
.element(by.css('button.edit'));
В этом примере:
Такой подход демонстрирует гибкость комбинирования локаторов и возможность создавать надежные селекторы даже в сложных интерфейсах.
Комбинирование локаторов — ключ к написанию устойчивых и читаемых тестов в Protractor. Оно позволяет точно выбирать элементы в любых структурах DOM, учитывая динамику приложения и особенности Angular.