TimeoutError обработка

TimeoutError в Protractor — один из ключевых типов ошибок, напрямую связанных с асинхронной природой браузерного тестирования. Он возникает, когда ожидаемое состояние приложения не наступает за отведённое время. Глубокое понимание причин, механизмов и способов обработки TimeoutError критично для стабильности и воспроизводимости e2e-тестов.


Protractor построен поверх WebDriverJS и использует механизм ожиданий (waits), который контролирует синхронизацию тестов с состоянием Angular-приложения и DOM. TimeoutError выбрасывается в следующих случаях:

  • не выполнено явное ожидание (browser.wait);
  • не завершилась Angular-синхронизация;
  • элемент не появился, не стал кликабельным или не изменил состояние;
  • превышен глобальный таймаут сценария.

Фактически TimeoutError означает не «ошибку теста», а нарушение предположения о времени реакции приложения.


Основные типы таймаутов в Protractor

Таймаут ожиданий (browser.wait)

Используется для явных ожиданий:

browser.wait(EC.visibilityOf(element(by.css('.loader'))), 5000);

Если условие ExpectedConditions не выполнится за 5000 мс, будет выброшен TimeoutError.

Ключевые особенности:

  • таймаут задаётся явно;
  • ошибка локализована;
  • стек вызовов указывает на конкретное ожидание.

Таймауты Protractor (browser.manage().timeouts())

Protractor управляет тремя типами таймаутов WebDriver:

browser.manage().timeouts().implicitlyWait(0);
browser.manage().timeouts().pageLoadTimeout(30000);
browser.manage().timeouts().scriptTimeout(10000);

implicitlyWait Отвечает за неявные ожидания поиска элементов. При ненулевом значении может маскировать проблемы и затруднять диагностику TimeoutError.

pageLoadTimeout Возникает при слишком долгой загрузке страницы (редиректы, тяжёлые ресурсы).

scriptTimeout Связан с выполнением асинхронных скриптов, включая executeAsyncScript.


Таймаут синхронизации Angular

Protractor по умолчанию ожидает завершения $http, $timeout, $interval в Angular. TimeoutError возможен, если:

  • приложение не Angular;
  • Angular застрял в бесконечном $digest;
  • присутствуют долгоживущие асинхронные операции.

Управление:

browser.waitForAngularEnabled(false);

Отключение синхронизации часто используется для гибридных или не-Angular страниц.


ExpectedConditions и их влияние на TimeoutError

ExpectedConditions — основной инструмент управления ожиданиями. Неправильный выбор условия напрямую ведёт к TimeoutError.

Примеры типичных ошибок:

  • ожидание presenceOf, когда элемент есть в DOM, но скрыт;
  • ожидание visibilityOf, когда элемент перекрыт другим;
  • ожидание elementToBeClickable, когда атрибут disabled меняется динамически.

Комбинирование условий снижает риск таймаутов:

browser.wait(
  EC.and(
    EC.presenceOf(el),
    EC.visibilityOf(el)
  ),
  7000
);

Диагностика TimeoutError

TimeoutError редко является корневой проблемой. Он — симптом.

Эффективная диагностика включает:

  • логирование состояний перед ожиданием;
  • скриншоты в afterEach;
  • вывод HTML элемента, вызвавшего ожидание;
  • анализ Angular-стабильности.

Пример получения информации об элементе:

el.getOuterHtml().then(html => console.log(html));

Обработка TimeoutError в тестах

Перехват через try/catch

Protractor поддерживает async/await, что позволяет явно обрабатывать TimeoutError:

try {
  await browser.wait(EC.visibilityOf(el), 5000);
} catch (e) {
  if (e.name === 'TimeoutError') {
    // обработка
  }
}

Подход полезен для:

  • нестабильных внешних сервисов;
  • альтернативных сценариев;
  • условных проверок UI.

Увеличение таймаута как анти-паттерн

Простое увеличение таймаута:

browser.wait(EC.visibilityOf(el), 30000);

часто скрывает архитектурные проблемы:

  • некорректную синхронизацию;
  • медленные API;
  • race condition в UI.

Допустимо только при:

  • действительно долгих бизнес-процессах;
  • документированных SLA.

Глобальные таймауты Jasmine и Mocha

TimeoutError может возникать не на уровне Protractor, а тестового фреймворка.

Jasmine

jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;

Если тест не завершился за это время, будет выброшена ошибка, внешне похожая на TimeoutError, но с другим источником.

Mocha

this.timeout(60000);

Важно различать:

  • таймаут ожидания элемента;
  • таймаут выполнения теста целиком.

Race Condition как скрытая причина TimeoutError

Многие TimeoutError вызваны гонками:

  • клики до завершения анимаций;
  • переходы между страницами без ожиданий;
  • обновление DOM без Angular-хуков.

Решения:

  • ожидание URL (EC.urlContains);
  • ожидание исчезновения loader’ов;
  • ожидание стабильного состояния, а не конкретного элемента.

Практики минимизации TimeoutError

Отказ от implicit wait Явные ожидания предсказуемее и легче отлаживаются.

Единая стратегия ожиданий Использование централизованных helper-функций для ожиданий.

Синхронизация с бизнес-событиями Ожидание результата действия, а не самого действия.

Контроль Angular-синхронизации Явное включение/отключение waitForAngularEnabled.


TimeoutError и отказоустойчивые тесты

TimeoutError неизбежен в e2e-тестировании, особенно в распределённых средах CI. Качество тестовой архитектуры определяется не отсутствием таймаутов, а:

  • скоростью их диагностики;
  • точностью локализации;
  • корректной реакцией тестов на нестабильность среды.

Грамотная работа с TimeoutError превращает его из случайной помехи в управляемый инструмент контроля над поведением приложения и тестов.