Timeout и обработка ошибок при ожидании

В Protractor управление ожиданиями является одной из ключевых задач для стабильного выполнения тестов. Неправильная обработка таймаутов или отсутствие корректной обработки ошибок приводит к нестабильным тестам, ложным срабатываниям и замедлению тестового процесса.

Типы ожиданий в Protractor

Protractor использует механизм ожиданий на основе WebDriverJS и промисов. Существует несколько подходов к ожиданиям:

  1. Implicit Wait – косвенное ожидание элементов, задаваемое для всей сессии.

    browser.manage().timeouts().implicitlyWait(5000);

    Элемент будет ожидаться до 5 секунд, прежде чем будет выброшена ошибка NoSuchElementError. Использование implicit wait не рекомендуется вместе с explicit wait, так как это может привести к непредсказуемым задержкам.

  2. Explicit Wait – ожидание конкретного условия с помощью ExpectedConditions.

    const EC = protractor.ExpectedConditions;
    const elementToWait = element(by.id('submit-button'));
    
    browser.wait(EC.elementToBeClickable(elementToWait), 10000, 'Кнопка не стала кликабельной');

    Ключевые моменты:

    • Первый параметр — условие (ExpectedConditions).
    • Второй параметр — таймаут в миллисекундах.
    • Третий параметр — необязательное сообщение об ошибке.
  3. Fluent Wait – кастомное ожидание с проверкой состояния через интервалы:

    browser.wait(() => {
        return element(by.css('.loader')).isPresent().then(isPresent => !isPresent);
    }, 15000, 'Лоадер не исчез в течение 15 секунд');

Настройка таймаутов

В Protractor существует несколько ключевых таймаутов:

  • allScriptsTimeout — максимальное время выполнения скрипта в браузере:

    exports.config = {
        allScriptsTimeout: 11000
    };
  • getPageTimeout — максимальное время ожидания загрузки страницы:

    exports.config = {
        getPageTimeout: 10000
    };
  • defaultTimeoutInterval — для Jasmine, контролирует время выполнения одного теста:

    jasmineNodeOpts: {
        defaultTimeoutInterval: 20000
    }

Обработка ошибок при ожидании

Ошибки таймаута могут быть вызваны несколькими причинами:

  1. Элемент не появился вовремя Ошибка: TimeoutError: Element taking too long to appear Решение: использовать browser.wait с подходящим условием, проверять селекторы.

  2. Элемент существует, но не в нужном состоянии Ошибка: Element not clickable Решение: использовать ExpectedConditions.elementToBeClickable или EC.visibilityOf.

  3. Асинхронные ошибки в промисах Ошибка: UnhandledPromiseRejection Решение: всегда возвращать промисы в функциях ожидания и обрабатывать через .then или async/await.

Пример с обработкой ошибок через try/catch:

const EC = protractor.ExpectedConditions;
const loginButton = element(by.id('login'));

try {
    await browser.wait(EC.elementToBeClickable(loginButton), 10000);
    await loginButton.click();
} catch (error) {
    console.error('Ошибка при клике по кнопке логина:', error.message);
    // Дополнительные действия: скриншот, логирование
}

Рекомендации по устойчивым ожиданиям

  • Явные ожидания лучше, чем implicit. Явные дают контроль над условием и временем.
  • Не увеличивать таймауты без необходимости — это замедляет тесты.
  • Использовать ExpectedConditions для типичных сценариев: visibilityOf, elementToBeClickable, textToBePresentInElement.
  • Комбинировать проверки состояния элемента и наличие на странице для критических шагов.
  • Обрабатывать ошибки через try/catch или .catch(), особенно при асинхронных действиях.
  • Логи и скриншоты при таймаутах позволяют быстро выявить проблему.

Практические примеры ожиданий

  1. Ожидание видимости элемента

    const EC = protractor.ExpectedConditions;
    const alertBox = element(by.css('.alert-success'));
    await browser.wait(EC.visibilityOf(alertBox), 8000, 'Сообщение об успехе не появилось');
  2. Ожидание исчезновения лоадера

    const loader = element(by.css('.loading'));
    await browser.wait(EC.invisibilityOf(loader), 12000, 'Лоадер не скрылся');
  3. Комбинированное ожидание состояния и кликабельности

    const button = element(by.buttonText('Отправить'));
    await browser.wait(EC.and(EC.elementToBeClickable(button), EC.visibilityOf(button)), 10000);
    await button.click();

Эффективное управление таймаутами и обработкой ошибок позволяет создавать стабильные и предсказуемые тесты, минимизируя ложные падения и увеличивая скорость выполнения автоматизации.