Protractor — это инструмент для автоматизированного тестирования веб-приложений на основе Angular и AngularJS, построенный поверх WebDriverJS. Ключевой особенностью Protractor является асинхронное взаимодействие с браузером, что требует понимания особенностей Promise и управления асинхронным кодом.
В основе Protractor лежит WebDriverJS, который полностью асинхронен.
Любая операция с элементами страницы, такими как
element(by.css('.selector')).click(), возвращает объект
Promise. Promise представляет собой отложенное
значение, которое будет доступно после завершения асинхронной
операции.
Асинхронный код позволяет:
then.При взаимодействии с элементами необходимо помнить, что методы
click(), sendKeys(), getText() и
аналогичные возвращают Promise. Для правильной работы с ними
используются конструкции:
let elem = element(by.id('submitButton'));
elem.click().then(function() {
console.log('Кнопка нажата');
});
С использованием современного синтаксиса async/await код
становится более линейным и читаемым:
let elem = element(by.id('submitButton'));
await elem.click();
console.log('Кнопка нажата');
Protractor предоставляет встроенный механизм ExpectedConditions, который позволяет явно ожидать определённого состояния элементов перед выполнением действия. Это особенно важно для динамических Angular-приложений, где элементы могут подгружаться асинхронно.
Пример ожидания видимости элемента:
let EC = protractor.ExpectedConditions;
let elem = element(by.css('.dynamic-element'));
await browser.wait(EC.visibilityOf(elem), 5000, 'Элемент не появился на странице');
await elem.click();
Основные методы ExpectedConditions:
visibilityOf(element) — ожидание видимости
элемента.presenceOf(element) — ожидание присутствия в DOM.elementToBeClickable(element) — ожидание возможности
клика.textToBePresentInElement(element, text) — ожидание
появления текста в элементе.До появления async/await Protractor использовал
control flow, который автоматически управлял цепочкой
промисов. В новых версиях control flow устарел, поэтому
рекомендуется использовать явное управление асинхронностью через
async/await.
Пример сложной последовательности действий:
let input = element(by.model('user.name'));
let button = element(by.id('saveButton'));
let message = element(by.css('.alert-success'));
await input.sendKeys('Тестовое имя');
await button.click();
await browser.wait(EC.visibilityOf(message), 5000);
let text = await message.getText();
console.log(text);
При написании тестов важно помнить, что значения элементов нужно
извлекать через await, иначе проверки будут выполняться не
над фактическим содержимым:
let title = await element(by.css('h1')).getText();
expect(title).toEqual('Добро пожаловать');
Без await title будет Promise, и проверка
завершится некорректно.
Для работы с коллекциями элементов (element.all) также
используется асинхронный подход:
let items = element.all(by.repeater('item in items'));
let count = await items.count();
console.log(`Количество элементов: ${count}`);
for (let i = 0; i < count; i++) {
let text = await items.get(i).getText();
console.log(`Элемент ${i}: ${text}`);
}
Методы map, filter и each
также возвращают промисы, поэтому в асинхронном коде необходимо
использовать await внутри функций обратного вызова.
Асинхронные операции могут завершаться с ошибкой, если элемент не
найден, страница не загружена или истекло время ожидания. Для обработки
ошибок используется try/catch:
try {
let elem = element(by.css('.nonexistent'));
await browser.wait(EC.visibilityOf(elem), 3000);
} catch (error) {
console.error('Элемент не найден или не стал видимым:', error.message);
}
Это предотвращает аварийное завершение теста и позволяет выполнять дополнительные действия, например, делать скриншоты при ошибке.
Protractor предоставляет глобальный объект browser для
управления браузером. Методы browser.get(),
browser.refresh(), browser.executeScript()
также возвращают промисы и требуют асинхронного ожидания:
await browser.get('https://example.com');
let title = await browser.getTitle();
console.log(`Заголовок страницы: ${title}`);
browser.executeScript() позволяет выполнять JavaScript в
контексте страницы и возвращает результат промиса:
let innerText = await browser.executeScript('return document.querySelector("h1").innerText;');
console.log(innerText);
В Protractor избегается использование setTimeout и
других явных таймеров для ожидания элементов, так как это нарушает
синхронизацию с Angular. Вместо этого применяется:
browser.wait() с ExpectedConditions.await.async/await вместо старого control
flow.try/catch.ExpectedConditions.Асинхронное выполнение в Protractor обеспечивает гибкость и точность тестов, но требует строгого соблюдения правил работы с промисами и правильного управления ожиданиями. Такой подход гарантирует стабильность тестов даже для динамически изменяющихся Angular-приложений.