Ожидание появления элемента в DOM

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

Асинхронные ожидания

WebdriverIO использует промисы и async/await для работы с элементами. При взаимодействии с элементом, который ещё не загружен на страницу, прямой вызов методов (click, setValue) может привести к ошибке element not found. Для предотвращения таких ситуаций применяются методы ожидания:

const button = await $('#submit');
await button.waitForExist({ timeout: 5000 });
await button.click();
  • waitForExist проверяет, что элемент появился в DOM.
  • timeout задаёт максимальное время ожидания в миллисекундах.
  • Если элемент не появляется за указанное время, генерируется исключение.

Различие между видимостью и существованием элемента

Важно различать наличие элемента в DOM и его видимость на странице. В WebdriverIO есть отдельные методы для этих случаев:

  • waitForExist() — проверяет наличие элемента в DOM, независимо от его отображения.
  • waitForDisplayed() — проверяет, что элемент видим пользователю, то есть отображается и имеет ненулевые размеры.

Пример:

const modal = await $('#modal');
await modal.waitForDisplayed({ timeout: 7000 });
await modal.click();

waitForDisplayed полезен для модальных окон, всплывающих подсказок и элементов, которые появляются после анимации или AJAX-запроса.

Настройка интервала проверки

Методы ожидания WebdriverIO позволяют настраивать интервал между проверками состояния элемента через параметр interval. По умолчанию проверка происходит каждые 500 миллисекунд.

await $('#notification').waitForExist({ timeout: 10000, interval: 200 });
  • interval уменьшает задержку между проверками и ускоряет обнаружение элементов, если страница динамическая.
  • Избыточное уменьшение интервала может увеличить нагрузку на браузер, особенно при большом количестве элементов.

Использование условий с waitUntil

Для более сложных сценариев применяется метод browser.waitUntil(). Он позволяет задать кастомное условие, которое должно быть выполнено:

await browser.waitUntil(async () => {
    const notifications = await $$('#notification');
    return notifications.length > 0;
}, {
    timeout: 8000,
    timeoutMsg: 'Элемент уведомления не появился на странице'
});
  • waitUntil принимает функцию, возвращающую булево значение.
  • timeoutMsg позволяет задать собственное сообщение об ошибке при превышении времени ожидания.
  • Используется для проверки динамических списков, таблиц и состояния элементов после AJAX-запросов.

Комбинирование ожиданий

Часто возникает необходимость проверять как наличие, так и видимость элемента:

const banner = await $('#banner');
await banner.waitForExist({ timeout: 5000 });
await banner.waitForDisplayed({ timeout: 3000 });
  • Сначала проверяется, что элемент добавлен в DOM.
  • Затем проверяется, что он видим пользователю.
  • Такая последовательность снижает вероятность ошибок при попытке взаимодействовать с элементами, которые ещё не готовы.

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

Для надёжных тестов важно обрабатывать ситуации, когда элемент не появился. Используется блок try/catch:

try {
    const tooltip = await $('#tooltip');
    await tooltip.waitForDisplayed({ timeout: 4000 });
    await tooltip.click();
} catch (error) {
    console.error('Элемент не появился:', error.message);
}
  • Позволяет логировать или выполнять альтернативные действия, если элемент не загрузился.
  • В крупных проектах предотвращает падение всего тестового сценария из-за одной задержки на странице.

Практические рекомендации

  • Использовать waitForExist для проверки присутствия элемента в DOM, если необходимо взаимодействовать с ним независимо от видимости.
  • Использовать waitForDisplayed для элементов, с которыми пользователь реально взаимодействует.
  • Не задавать чрезмерно короткие таймауты, чтобы избежать ложных срабатываний на медленных страницах.
  • Комбинировать с waitUntil для кастомных условий, например для динамических списков и таблиц.
  • Оборачивать критичные ожидания в try/catch, чтобы сохранить стабильность тестов.

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