Protractor изначально разрабатывался для тестирования
Angular-приложений и построен на WebDriverJS, который использует промисы
для работы с асинхронными действиями. До появления
async/await управление асинхронностью в тестах было
громоздким: приходилось строить цепочки промисов через
.then(). Современный подход с async/await
делает код читаемым, линейным и поддерживаемым.
Любая асинхронная операция в Protractor возвращает промис. Примеры таких операций: навигация по странице, поиск элементов, клики, ввод текста. Ключевое правило: все действия с WebElement и браузером должны ожидать завершения промиса, иначе результат будет непредсказуемым.
it('пример использования async/await', async () => {
await browser.get('https://example.com');
const input = element(by.css('input[name="username"]'));
await input.sendKeys('testuser');
const button = element(by.css('button[type="submit"]'));
await button.click();
});
В этом примере каждая операция дожидается завершения предыдущей, что исключает состояние гонки и делает тест предсказуемым.
В Protractor элементы обозначаются через
element(locator) или массив элементов
element.all(locator). Асинхронная природа работы с DOM
требует явного ожидания:
const items = element.all(by.css('.list-item'));
const count = await items.count();
console.log(`Количество элементов: ${count}`);
Важно: методы вроде getText(),
getAttribute(), isDisplayed() также возвращают
промис и требуют await.
const title = await element(by.css('h1')).getText();
if (title === 'Главная страница') {
await element(by.css('button.next')).click();
}
Для синхронизации тестов используется ExpectedConditions
(EC). В связке с async/await это позволяет надежно ожидать
появления элементов или изменения состояния:
const EC = protractor.ExpectedConditions;
const submitButton = element(by.id('submit'));
await browser.wait(EC.elementToBeClickable(submitButton), 5000, 'Кнопка не стала кликабельной');
await submitButton.click();
Ключевые моменты:
browser.wait возвращает промис и требует
await.Асинхронные операции в циклах требуют особого внимания. Использование
обычного forEach не подходит, так как await
внутри него не работает корректно. Правильный подход — использовать
for...of:
const elementsList = element.all(by.css('.item'));
for (const el of await elementsList) {
const text = await el.getText();
console.log(text);
}
Или с map и Promise.all, если требуется
параллельное выполнение:
const texts = await Promise.all(
(await elementsList).map(el => el.getText())
);
console.log(texts);
При работе с async/await важно правильно обрабатывать
ошибки. Непойманные промисы приведут к падению теста без информативного
сообщения. Для этого используется try/catch:
try {
await browser.get('https://example.com');
await element(by.id('nonexistent')).click();
} catch (error) {
console.error('Ошибка при клике:', error);
}
Также полезно использовать browser.sleep() только для
отладки, так как это блокирует тест и увеличивает время выполнения.
Для упрощения кода рекомендуется выносить повторяющиеся действия в асинхронные функции:
async function login(username, password) {
await element(by.name('username')).sendKeys(username);
await element(by.name('password')).sendKeys(password);
await element(by.css('button[type="submit"]')).click();
}
it('тест логина', async () => {
await browser.get('https://example.com/login');
await login('user1', 'password1');
});
Такой подход улучшает читаемость и позволяет повторно использовать логику.
Protractor автоматически ожидает завершения асинхронных операций
Angular. Однако при использовании async/await важно
помнить:
browser.waitForAngularEnabled(false) отключают
ожидание Angular.await browser.waitForAngularEnabled(false);
await browser.get('https://non-angular-site.com');
await при взаимодействии с
браузером и элементами.async/await и .then() без
необходимости.ExpectedConditions вместо
browser.sleep() для надежных ожиданий.try/catch для информативного
логирования.Async/await превращает асинхронные тесты Protractor в линейные скрипты, упрощает синхронизацию и делает код понятным и поддерживаемым. Правильное применение этих принципов минимизирует состояние гонки и повышает стабильность тестов.