Protractor — это инструмент для end-to-end тестирования Angular и не только Angular приложений. Одной из ключевых особенностей работы с Protractor является асинхронность взаимодействий с браузером и элементами страницы. Управление таймаутами и корректная обработка reject промисов играет критическую роль в стабильности и предсказуемости тестов.
Protractor использует WebDriverJS, который построен
на промисах. Любое действие с элементом страницы, будь то поиск, клик
или получение текста, возвращает объект Promise.
Асинхронная модель позволяет тестам не блокировать поток
выполнения, но требует правильного управления таймаутами и
обработкой ошибок.
Ключевые моменты:
reject) при ошибках взаимодействия, например, элемент не
найден или истёк таймаут.element(locator).click()
или element(locator).getText(), не выбрасывают
исключение напрямую, а возвращают промис, который может быть
rejected.Protractor предоставляет несколько уровней таймаутов:
Implicit Waits (неявные ожидания)
Устанавливаются через
browser.manage().timeouts().implicitlyWait(ms). Пример:
browser.manage().timeouts().implicitlyWait(5000); // 5 секунд
Особенности:
Explicit Waits (явные ожидания) Реализуются
через ExpectedConditions:
const EC = protractor.ExpectedConditions;
const elem = element(by.id('submit'));
browser.wait(EC.elementToBeClickable(elem), 10000, 'Элемент не кликабелен');
Особенности:
Page Load Timeout и Script Timeout Настройки
браузера через browser.manage().timeouts():
browser.manage().timeouts().pageLoadTimeout(20000); // Таймаут загрузки страницы
browser.manage().timeouts().setScriptTimeout(15000); // Таймаут выполнения скрипта
pageLoadTimeout контролирует время ожидания полной
загрузки страницы.setScriptTimeout применяется при выполнении
асинхронного JavaScript через
browser.executeAsyncScript().Reject промиса возникает в случаях:
NoSuchElementError)ElementNotInteractableError)TimeoutError)Правильная обработка reject критична для предотвращения падений тестов и получения информативных логов.
Пример с .then() и
.catch():
element(by.id('submit')).click()
.then(() => {
console.log('Клик выполнен успешно');
})
.catch(err => {
if (err.name === 'TimeoutError') {
console.error('Элемент не появился вовремя');
} else {
console.error('Ошибка при клике:', err);
}
});
Использование async/await с
try/catch:
async function clickSubmit() {
const submitBtn = element(by.id('submit'));
try {
await browser.wait(protractor.ExpectedConditions.elementToBeClickable(submitBtn), 10000);
await submitBtn.click();
console.log('Клик успешен');
} catch (err) {
if (err.name === 'TimeoutError') {
console.error('Элемент не стал кликабельным вовремя');
} else {
console.error('Ошибка клика:', err);
}
}
}
async/await позволяет писать асинхронный код линейно,
улучшая читаемость.try/catch гарантирует обработку всех rejected
промисов.Не использовать только implicit wait Неявные ожидания могут замедлять тесты и скрывать реальные проблемы. Предпочтительнее комбинировать явные ожидания для ключевых элементов.
Использовать специфичные ExpectedConditions
Вместо presenceOf использовать visibilityOf
или elementToBeClickable для операций, требующих
взаимодействия.
Оборачивать действия с элементами в try/catch Даже при использовании явных ожиданий возможны ошибки. Это помогает создавать устойчивые тесты.
Использовать кастомные таймауты для критичных шагов Для сложных страниц или динамических элементов стандартный таймаут 5–10 секунд может быть недостаточным.
Логировать причины reject Всегда фиксировать тип
ошибки (err.name) и сообщение (err.message)
для упрощения отладки.
В protractor.conf.js можно задать глобальные
таймауты:
exports.config = {
allScriptsTimeout: 11000, // Максимальное время выполнения скриптов
getPageTimeout: 10000, // Таймаут загрузки страницы
jasmineNodeOpts: {
defaultTimeoutInterval: 30000 // Таймаут для тестов
}
};
allScriptsTimeout — контролирует выполнение асинхронных
скриптов, используемых в browser.executeAsyncScript().getPageTimeout — максимальное время загрузки каждой
страницы.defaultTimeoutInterval — таймаут ожидания завершения
каждого it блока в Jasmine.В Protractor часто используются цепочки промисов:
element(by.id('input')).sendKeys('test')
.then(() => element(by.id('submit')).click())
.then(() => element(by.id('result')).getText())
.then(text => console.log('Результат:', text))
.catch(err => console.error('Ошибка в цепочке:', err));
catch.Promise.all() для параллельных
операций с элементами и обрабатывать их общий reject:Promise.all([
element(by.id('input1')).sendKeys('a'),
element(by.id('input2')).sendKeys('b')
])
.then(() => console.log('Оба ввода выполнены'))
.catch(err => console.error('Ошибка при вводе:', err));
Тщательное управление таймаутами и корректная обработка reject промисов является основой устойчивого и предсказуемого тестирования с Protractor. Правильная настройка ожиданий, комбинирование explicit waits и обработка ошибок в цепочках промисов позволяет создавать надежные скрипты для сложных веб-приложений.