Таймауты в асинхронном коде

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

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

Таймауты ожидания

WebdriverIO использует механизм ожидания элементов, что позволяет эффективно взаимодействовать с ними только в тот момент, когда они становятся доступными. Таймауты ожидания можно разделить на несколько типов:

  1. Global Timeout (Общий таймаут) Этот таймаут определяет максимальное время, которое WebdriverIO будет ждать на выполнение всех асинхронных операций. Например, если элемент не будет найден за это время, тест завершится с ошибкой.

    Пример установки глобального таймаута:

    browser.setTimeout({ 'implicit': 5000 });

    Здесь задаётся глобальный таймаут в 5000 миллисекунд для всех ожиданий, если не указано иное.

  2. Implicit Wait (Неявное ожидание) Это время, в течение которого WebdriverIO будет пытаться найти элемент, прежде чем сдаться. Если элемент не будет найден в течение указанного времени, то будет выброшена ошибка.

    Установка неявного ожидания:

    browser.setTimeout({ 'implicit': 10000 });

    Такой таймаут полезен, когда нужно, чтобы WebdriverIO продолжал искать элементы в течение определённого времени, прежде чем выбрасывать исключение.

  3. Explicit Wait (Явное ожидание) Для явного ожидания WebdriverIO предоставляет методы, которые позволяют явно указать, что следует ожидать появления элемента или изменения его состояния. Явные ожидания часто используются в случае, когда необходимо дождаться загрузки динамического контента на странице.

    Пример явного ожидания:

    const element = await $('div.some-class');
    await element.waitForExist({ timeout: 5000 });

    В этом примере тест будет ожидать появления элемента с классом some-class на странице в течение 5 секунд.

  4. Custom Waits (Пользовательские ожидания) В некоторых случаях может потребоваться реализация более сложных условий ожидания, которые выходят за рамки стандартных методов. Для этого можно создать свои собственные ожидания, например, ждать, пока значение элемента не изменится.

    Пример пользовательского ожидания:

    const element = await $('#myElement');
    await browser.waitUntil(async () => {
      return (await element.getText()) === 'Ожидаемый текст';
    }, {
      timeout: 5000,
      timeoutMsg: 'Текст элемента не изменился в течение 5 секунд'
    });

    Этот код будет ожидать, пока текст элемента не изменится на “Ожидаемый текст”, или тест завершится с ошибкой, если текст не изменится за 5 секунд.

Таймауты для взаимодействия с элементами

WebdriverIO позволяет использовать таймауты в сочетании с методами взаимодействия с элементами, такими как click, setValue, getText и других. Это полезно, если элемент может стать доступен только через некоторое время после выполнения действия, и необходимо ожидать его появления или активации.

  1. waitForExist Этот метод используется для явного ожидания существования элемента на странице.

    await $('#submitButton').waitForExist({ timeout: 10000 });

    В случае если элемент не появится за 10 секунд, будет выброшено исключение.

  2. waitForClickable Применяется для ожидания того, чтобы элемент стал кликабельным. Это особенно важно, если на странице есть элементы, которые могут быть неактивными до полной загрузки контента.

    await $('#submitButton').waitForClickable({ timeout: 5000 });

    В случае если элемент не станет кликабельным за указанное время, тест завершится с ошибкой.

  3. waitForEnabled Этот метод применяется, чтобы дождаться, пока элемент станет активным (enabled), что важно при работе с формами и кнопками.

    await $('#submitButton').waitForEnabled({ timeout: 3000 });

Таймауты в асинхронных тестах

В WebdriverIO все операции, связанные с взаимодействием с браузером, являются асинхронными. Поэтому важно правильно настроить время ожидания, чтобы избежать ненужных таймаутов. Особенность асинхронных тестов заключается в том, что операции не блокируют выполнение теста, а продолжают работать в фоновом режиме.

Таймауты в асинхронных функциях

Асинхронные операции в WebdriverIO работают через промисы, что требует правильного использования await и соответствующих методов ожидания. Важно учитывать, что каждый метод, который может занять некоторое время (например, getText, click, setValue), может требовать отдельного таймаута для корректной работы.

Пример асинхронного теста с таймаутами:

it('Должен отправить форму', async () => {
  await browser.url('https://example.com');

  const input = await $('#username');
  await input.waitForExist({ timeout: 5000 });
  await input.setValue('testuser');

  const submitButton = await $('#submitButton');
  await submitButton.waitForClickable({ timeout: 5000 });
  await submitButton.click();

  const successMessage = await $('#successMessage');
  await successMessage.waitForExist({ timeout: 10000 });
});

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

Настройка таймаутов через конфигурацию

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

Пример конфигурации глобальных таймаутов:

exports.config = {
  // Общие таймауты
  waitforTimeout: 10000, // Ожидание элементов
  connectionRetryTimeout: 90000, // Таймаут подключения к серверу
  connectionRetryCount: 3, // Количество попыток подключения
  ...
};

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

Использование таймаутов для стабилизации тестов

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

Пример стабилизации теста с увеличением времени ожидания:

await browser.setTimeout({ 'pageLoad': 60000 });

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

Заключение

Таймауты являются неотъемлемой частью процесса тестирования в WebdriverIO. Их правильная настройка позволяет сделать тесты более гибкими и стабильными, особенно в условиях асинхронных операций и взаимодействия с динамически изменяющимися элементами на страницах. Правильное использование таймаутов помогает избежать ненужных ошибок и повысить качество автоматизированных тестов.