Protractor — это инструмент для автоматизированного тестирования Angular-приложений, который изначально был создан с учётом особенностей работы Angular. Одной из ключевых задач Protractor является управление синхронизацией между тестами и приложением, чтобы избежать ошибок, связанных с асинхронной природой веб-приложений.
В веб-приложениях на Angular многие действия происходят асинхронно: HTTP-запросы, обновление DOM, анимации и таймеры. Если тест пытается взаимодействовать с элементом до того, как он станет доступен, возникает ошибка типа:
ElementNotVisibleError
NoSuchElementError
StaleElementReferenceError
Protractor изначально предоставляет механизм автоматической синхронизации с Angular, который ожидает завершения всех асинхронных операций, прежде чем выполнять действия в тесте. Однако этот механизм не всегда срабатывает идеально, особенно при:
Для решения синхронизационных проблем в Protractor применяются различные методы:
1. browser.wait()
Позволяет явно дождаться выполнения определённого условия:
const EC = protractor.ExpectedConditions;
const myElement = element(by.id('submit-button'));
browser.wait(EC.visibilityOf(myElement), 5000, 'Элемент не появился за 5 секунд');
myElement.click();
Здесь ExpectedConditions предоставляет готовые функции
для проверки видимости, кликабельности, присутствия элементов и т.д.
2. browser.sleep()
Принудительная пауза выполнения теста:
browser.sleep(2000);
Используется редко и только в крайних случаях, так как увеличивает время выполнения тестов и не решает проблему асинхронного поведения корректно.
3. Ожидание элементов через element.isPresent()
и element.isDisplayed()
Позволяет проверять состояние элемента перед взаимодействием:
const myElement = element(by.css('.alert'));
if (myElement.isPresent() && myElement.isDisplayed()) {
myElement.click();
}
4. Игнорирование синхронизации Angular для не-Angular страниц
Protractor по умолчанию синхронизируется с Angular. Для страниц без Angular используется:
browser.waitForAngularEnabled(false);
После этого все асинхронные операции приходится контролировать вручную.
ExpectedConditions вместо
sleep. Это делает тесты более стабильными и
ускоряет их выполнение.StaleElementReferenceError
Возникает, когда элемент DOM обновился после того, как тест его нашёл:
let myElement = element(by.css('.dynamic-item'));
myElement.click(); // ошибка может возникнуть
Решение — заново искать элемент перед действием:
let myElement = element(by.css('.dynamic-item'));
browser.wait(EC.stalenessOf(myElement), 5000);
myElement = element(by.css('.dynamic-item'));
myElement.click();
ElementNotVisibleError
Элемент существует в DOM, но ещё не отображается:
const myButton = element(by.buttonText('Submit'));
myButton.click(); // может вызвать ошибку
Решение — дождаться видимости:
browser.wait(EC.visibilityOf(myButton), 5000);
myButton.click();
Для Angular приложений Protractor умеет автоматически ожидать
завершения всех $http и $timeout операций.
Однако если используется Angular без zone.js или нестандартные
асинхронные вызовы, автоматическая синхронизация не работает. В таких
случаях:
browser.executeAsyncScript() для контроля
состояния приложения из теста.Эффективная стратегия работы с синхронизацией в Protractor может быть представлена следующим образом:
browser.wait() с
ExpectedConditions.sleep().Эта стратегия обеспечивает стабильность тестов и уменьшает вероятность возникновения ошибок, связанных с асинхронностью.