Работа с динамически загружаемыми элементами

Динамически загружаемые элементы на веб-странице представляют собой элементы, которые появляются или изменяются после выполнения определённых действий или после полной загрузки страницы. Работа с ними требует особого подхода, так как прямой поиск элемента может завершиться ошибкой NoSuchElementError, если элемент ещё не появился в DOM. WebdriverIO предоставляет инструменты для эффективного взаимодействия с такими элементами, включая ожидания, селекторы и асинхронное управление.


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

Implicit Waits

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

browser.setTimeout({ implicit: 5000 });
const button = $('#dynamic-button');
button.click();

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

Explicit Waits

Более гибкий способ — явные ожидания. Они позволяют дождаться конкретного состояния элемента, используя методы waitForExist, waitForDisplayed, waitForEnabled и другие:

const dynamicElement = $('#dynamic-content');

dynamicElement.waitForDisplayed({
    timeout: 10000,
    timeoutMsg: 'Элемент не появился на странице в течение 10 секунд'
});

dynamicElement.click();
  • timeout — максимальное время ожидания в миллисекундах.
  • timeoutMsg — сообщение об ошибке при превышении времени ожидания.
  • Явные ожидания лучше использовать для динамического контента, так как они проверяют состояние элемента, а не просто наличие в DOM.

Работа с асинхронным контентом

WebdriverIO поддерживает синтаксис async/await, который упрощает работу с элементами, загружаемыми после выполнения действий:

await $('#load-button').click();
const newItem = await $('#new-item');

await newItem.waitForDisplayed({ timeout: 8000 });
await newItem.click();

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


Использование стратегий поиска элементов

Селекторы CSS и XPath

Для динамических элементов часто используют селекторы с атрибутами или текстом, которые остаются стабильными, несмотря на динамическую подгрузку:

const item = await $('[data-test-id="item-42"]');
await item.waitForExist();

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

Сложные XPath выражения

XPath позволяет находить элементы по тексту, родителю или соседям:

const button = await $('//div[contains(text(), "Загрузить")]/following-sibling::button');
await button.waitForClickable();
await button.click();

Такой подход особенно полезен для элементов, которые не имеют уникальных идентификаторов.


Обработка изменений DOM

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

const element = await $('#dynamic-item');
await element.waitForDisplayed();
await element.click();

// После обновления DOM
const refreshedElement = await $('#dynamic-item');
await refreshedElement.waitForDisplayed();
await refreshedElement.click();

Попытка использовать старый объект вызовет ошибку stale element reference, так как ссылка на элемент устарела.


Ждущие функции и кастомные ожидания

WebdriverIO предоставляет метод browser.waitUntil для создания кастомных условий:

await browser.waitUntil(
    async () => (await $('#status').getText()) === 'Готово',
    {
        timeout: 10000,
        timeoutMsg: 'Статус не обновился на "Готово" за 10 секунд'
    }
);

Это позволяет дождаться конкретного состояния приложения, которое невозможно проверить стандартными методами waitForDisplayed или waitForExist.


Ловушки и рекомендации

  • Не использовать фиксированные sleep (например, browser.pause(5000)) для ожидания динамических элементов — это снижает стабильность и скорость тестов.
  • Всегда проверять актуальность ссылки на элемент после изменения DOM.
  • Предпочтение отдавать явным ожиданиям (waitFor* и waitUntil) вместо неявных.
  • Для сложных сценариев динамической подгрузки сочетать селекторы, явные ожидания и кастомные условия.

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