Protractor — это инструмент для автоматизированного тестирования веб-приложений на Angular и не только. Одной из ключевых особенностей при работе с Protractor является управление потоком выполнения асинхронных операций. Важно понимать, что тесты в Protractor часто взаимодействуют с элементами страницы, выполнение которых требует времени, поэтому правильное управление асинхронностью критично для стабильности тестов.
Protractor использует Promise для работы с асинхронными операциями, такими как поиск элементов или выполнение действий над ними. Каждое взаимодействие с элементом возвращает Promise, который разрешается после завершения операции. Например:
let button = element(by.id('submit'));
button.click(); // возвращает Promise
Если попытаться обратиться к результату асинхронной операции
напрямую, без ожидания завершения Promise, тест может завершиться с
ошибкой. Для управления этим применяются конструкции then,
async/await.
then для управления потокомМетод then позволяет выполнять действия после
завершения предыдущей асинхронной операции:
element(by.id('username')).sendKeys('admin').then(function() {
return element(by.id('password')).sendKeys('1234');
}).then(function() {
return element(by.id('login')).click();
});
В данном примере каждая операция выполняется последовательно, что предотвращает гонку состояний и ошибки из-за недоступных элементов.
async /
await — современный подходС версии Protractor 5+ и с внедрением Node.js с поддержкой
async/await появилась возможность писать тесты, которые
выглядят синхронно, хотя остаются асинхронными:
it('должен залогиниться', async () => {
await element(by.id('username')).sendKeys('admin');
await element(by.id('password')).sendKeys('1234');
await element(by.id('login')).click();
});
Преимущества:
try/catch.browser.waitДля корректного управления потоком выполнения часто требуется
явное ожидание определённых условий. Для этого
используется browser.wait:
let EC = protractor.ExpectedConditions;
let loginButton = element(by.id('login'));
await browser.wait(EC.elementToBeClickable(loginButton), 5000);
await loginButton.click();
Ключевые моменты:
ExpectedConditions содержит набор готовых условий:
видимость, кликабельность, наличие текста.Когда нужно выполнить серию действий над множеством элементов, следует использовать цикл с await:
let items = element.all(by.css('.todo-item'));
for (let i = 0; i < await items.count(); i++) {
let item = items.get(i);
await item.click();
}
Важно:
count() также возвращает Promise, поэтому перед
циклом используется await.В некоторых случаях действия можно выполнять параллельно, используя
Promise.all:
let usernameField = element(by.id('username')).sendKeys('admin');
let passwordField = element(by.id('password')).sendKeys('1234');
await Promise.all([usernameField, passwordField]);
await element(by.id('login')).click();
Применяется, когда операции не зависят друг от друга. Это ускоряет тесты, но требует внимательного контроля состояния страницы.
Частые ошибки при работе с асинхронностью:
TimeoutError.Использование async/await совместно с
browser.wait и ExpectedConditions минимизирует
такие ошибки.
Ранее Protractor имел WebDriver Control Flow,
который автоматически управлял Promise. Начиная с версии 6+, Control
Flow отключён, и теперь все тесты требуют явного управления
асинхронностью с использованием async/await. Это повышает
прозрачность выполнения тестов и упрощает отладку.
browser.wait или ExpectedConditions.await для каждого действия, если оно зависит от
предыдущего.Promise.all.try/catch.Контроль потока выполнения в Protractor — это фундаментальный навык,
обеспечивающий корректность тестов и их стабильность. Понимание Promise,
правильное применение async/await и явных ожиданий
позволяет создавать надёжные автоматизированные сценарии для любых
веб-приложений.