Protractor — это инструмент для end-to-end тестирования веб-приложений на базе Angular и AngularJS. Одной из ключевых особенностей Protractor является автоматическая синхронизация с Angular, что позволяет тестам выполняться только после того, как Angular завершит все свои асинхронные операции, такие как обновление модели, HTTP-запросы или отрисовка элементов.
Angular использует внутренний цикл выполнения (digest cycle) для отслеживания изменений в модели и их отображения в DOM. Protractor интегрируется с этим циклом и выполняет следующие действия:
$http или HttpClient.$timeout и $interval.Как результат, команды WebDriver (click(),
sendKeys(), getText()) выполняются только
после того, как Angular закончил все внутренние операции, исключая
необходимость вручную использовать sleep() или
wait() в большинстве случаев.
Protractor по умолчанию включен для приложений на Angular. Основной механизм контроля синхронизации представлен методом:
browser.waitForAngularEnabled(true);
true — Protractor будет ждать завершения всех
Angular-операций перед взаимодействием с элементами.false — синхронизация отключена, что необходимо для
тестирования не-Angular страниц.Пример использования:
it('должен дождаться загрузки данных Angular', async () => {
await browser.waitForAngularEnabled(true);
await browser.get('/dashboard');
const title = await element(by.css('h1')).getText();
expect(title).toEqual('Dashboard');
});
Отключение автоматической синхронизации необходимо в следующих случаях:
$http
запросами, которые не критичны для теста.Пример отключения:
browser.waitForAngularEnabled(false);
await browser.get('https://external-site.com');
После выполнения таких действий следует вновь включить синхронизацию при переходе на Angular-страницы.
Хотя Protractor синхронизируется с Angular автоматически, иногда
возникает необходимость использовать явные ожидания для
элементов, загружаемых динамически или зависящих от пользовательских
событий. Для этого применяются ExpectedConditions:
const EC = protractor.ExpectedConditions;
const submitButton = element(by.id('submit'));
await browser.wait(EC.elementToBeClickable(submitButton), 5000);
await submitButton.click();
Ключевые моменты:
elementToBeClickable — ждет, пока элемент не станет
кликабельным.visibilityOf — ждет появления элемента в DOM и его
видимости.presenceOf — проверяет, что элемент присутствует в DOM,
даже если он невидим.Для AngularJS (1.x) Protractor использует глобальные
объекты $browser и $injector, чтобы
отслеживать pending операции.
Для Angular 2+ синхронизация строится на основе
Zone.js, который перехватывает все асинхронные операции.
Protractor автоматически определяет наличие Angular и корректно ждет
завершения всех зон.
Важно учитывать:
rootEl можно указать явно, если
приложение не использует <body> как корневой
элемент:browser.waitForAngularEnabled(true);
browser.rootEl = 'app-root';
rootEl обычно не требуется,
синхронизация работает с любым корневым компонентом.Часто встречаются ошибки типа
Timed out waiting for Angular. Основные причины:
rootEl).Для диагностики полезны методы:
browser.waitForAngularEnabled(false); // временно отключить синхронизацию
browser.getCurrentUrl(); // проверить переходы
Также можно использовать browser.sleep() для проверки
последовательности событий, но это временная мера и в автоматических
тестах не рекомендуется.
sleep() с автоматическим ожиданием, так
как это снижает надежность тестов.ExpectedConditions.$http и $timeout
в приложении: незавершенные асинхронные операции блокируют выполнение
тестов.Автоматическая синхронизация с Angular — одно из основных преимуществ Protractor, позволяющее создавать надежные и стабильные end-to-end тесты без постоянного контроля за асинхронными операциями. Она требует понимания внутренних механизмов Angular и грамотного использования методов включения/отключения синхронизации, а также явных ожиданий для динамических элементов.