В тестировании веб-приложений с использованием Protractor одной из самых частых и критических проблем является управление ожиданиями. Неправильное обращение с ожиданиями приводит к нестабильным тестам, ложноположительным или ложноотрицательным результатам. Protractor работает поверх WebDriverJS и использует асинхронные операции, что делает контроль времени выполнения элементов ключевым аспектом.
Protractor изначально был тесно интегрирован с Angular-приложениями,
что позволяло ему автоматически ожидать завершения всех асинхронных
операций Angular, таких как $http и $timeout.
Однако при работе с не-Angular страницами
автоматические ожидания не выполняются, и разработчик обязан явно
управлять задержками:
browser.waitForAngularEnabled(false);
Без этого вызова тесты могут завершаться раньше, чем элементы DOM
будут доступны, вызывая ошибки вида NoSuchElementError.
Protractor предоставляет несколько механизмов ожиданий:
Implicit Waits (не рекомендуется) WebDriver позволяет установить глобальное время ожидания появления элементов:
browser.manage().timeouts().implicitlyWait(5000);
Основной недостаток — непредсказуемость при работе с динамическим контентом. Имплиситные ожидания могут увеличивать общее время теста и не гарантируют стабильность.
Explicit Waits (рекомендуется) Позволяют ожидать
конкретное условие для конкретного элемента. Для этого используется
класс ExpectedConditions:
let EC = protractor.ExpectedConditions;
let button = element(by.id('submit'));
browser.wait(EC.elementToBeClickable(button), 5000, 'Кнопка не стала кликабельной за 5 секунд');
Основные предопределённые условия:
presenceOf(element) — элемент присутствует в DOM;visibilityOf(element) — элемент видим;elementToBeClickable(element) — элемент доступен для
клика;textToBePresentInElement(element, text) — текст
присутствует в элементе.Custom Expected Conditions Иногда стандартные условия не подходят, и требуется создать собственное условие:
let customCondition = function(elem) {
return elem.getText().then(text => text.includes('Готово'));
};
browser.wait(customCondition(element(by.id('status'))), 7000, 'Статус не обновился');sleep() вместо явных ожиданий.
browser.sleep(5000) может «сработать» случайно, но приводит
к нестабильности при изменении скорости загрузки.browser.wait() или ручную проверку
состояния.Избегать sleep(). Использование
фиксированных задержек замедляет тесты и не гарантирует корректное
выполнение.
Использовать explicit waits для всех элементов, с которыми планируется взаимодействие.
Разделять ожидания для разных типов действий:
Комбинировать условия при необходимости,
используя EC.and() или EC.or():
browser.wait(
EC.and(
EC.visibilityOf(elem),
EC.elementToBeClickable(elem)
),
5000,
'Элемент не видим и некликабелен'
);Логирование времени ожидания помогает отследить проблемные участки теста и понять, почему тесты «подвисают» или падают.
Protractor использует промисы для всех действий с элементами. Ошибки ожидания часто возникают, когда промисы обрабатываются неправильно:
// Неправильно
element(by.id('input')).sendKeys('тест');
expect(element(by.id('output')).getText()).toEqual('тест');
// Правильно
element(by.id('input')).sendKeys('тест').then(() => {
expect(element(by.id('output')).getText()).toEqual('тест');
});
Использование async/await делает код более читаемым и
безопасным:
await element(by.id('input')).sendKeys('тест');
const outputText = await element(by.id('output')).getText();
expect(outputText).toEqual('тест');
const EC = protractor.ExpectedConditions;
let row = element(by.cssContainingText('tr', 'Иванов'));
await browser.wait(EC.presenceOf(row), 5000, 'Строка Иванов не появилась в таблице');
await browser.wait(EC.visibilityOf(row), 5000, 'Строка Иванов не видна');
await row.element(by.css('.edit')).click();
В этом примере последовательные explicit waits гарантируют, что тест не упадет из-за того, что элемент ещё не добавлен в DOM или не видим пользователю.