Динамически загружаемые элементы на веб-странице представляют собой
элементы, которые появляются или изменяются после выполнения
определённых действий или после полной загрузки страницы. Работа с ними
требует особого подхода, так как прямой поиск элемента может завершиться
ошибкой 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 — сообщение об ошибке при превышении времени
ожидания.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();
Такой подход особенно полезен для элементов, которые не имеют уникальных идентификаторов.
При динамической подгрузке элементы могут удаляться и добавляться заново. В таких случаях важно использовать ожидания, а не кэшировать объект:
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)) для ожидания динамических элементов —
это снижает стабильность и скорость тестов.waitFor* и
waitUntil) вместо неявных.Работа с динамически загружаемыми элементами требует внимательного подхода к ожиданиям и правильного использования селекторов. Комбинация явных ожиданий, асинхронного синтаксиса и кастомных проверок обеспечивает надежное и стабильное взаимодействие с элементами, независимо от скорости их появления и изменений в DOM.