Protractor — инструмент для автоматизированного тестирования Angular-приложений, который расширяет возможности Selenium WebDriver, добавляя поддержку асинхронного Angular-кода. Работа с динамическим содержимым является одной из ключевых задач при тестировании современных веб-приложений, где элементы страницы могут появляться, исчезать или изменяться в процессе взаимодействия пользователя.
Важной особенностью динамических элементов является их
непредсказуемое время появления в DOM. Protractor предоставляет
несколько методов для ожидания элементов, которые позволяют избежать
ошибок ElementNotVisible или
NoSuchElementError.
Методы ожидания:
browser.wait() Метод используется для явного ожидания условий.
const EC = protractor.ExpectedConditions;
const dynamicButton = element(by.id('dynamic-button'));
browser.wait(EC.visibilityOf(dynamicButton), 5000, 'Кнопка не появилась на странице');
dynamicButton.click();ExpectedConditions (EC) Protractor включает набор встроенных условий для удобного использования:
visibilityOf(element) — элемент видим на страницеpresenceOf(element) — элемент присутствует в DOMelementToBeClickable(element) — элемент кликабеленtextToBePresentInElement(element, text) — текст
появился в элементеПрименение async/await Современный подход с
использованием async/await повышает читаемость кода:
it('ожидает появления текста', async () => {
const message = element(by.css('.message'));
await browser.wait(EC.textToBePresentInElement(message, 'Завершено'), 7000);
const text = await message.getText();
expect(text).toEqual('Завершено');
});Динамическое содержимое часто связано с изменением списка элементов
или таблиц. Protractor предоставляет возможности для работы с массивами
элементов через element.all() и фильтры.
Пример фильтрации элементов:
const items = element.all(by.css('.item'));
const visibleItems = items.filter(async (elem) => {
return await elem.isDisplayed();
});
expect(await visibleItems.count()).toBeGreaterThan(0);
Получение текста из динамического списка:
const itemTexts = await element.all(by.css('.item')).map(async (elem) => {
return await elem.getText();
});
console.log(itemTexts);
Protractor автоматически синхронизируется с Angular-приложениями,
используя механизм ngZone. Однако в некоторых случаях,
например при загрузке данных через сторонние библиотеки, может
понадобиться ручное ожидание.
Ожидание завершения Angular:
await browser.waitForAngular();
Пример с нестандартным AJAX-запросом:
await browser.wait(async () => {
const status = await element(by.id('ajax-status')).getText();
return status === 'Готово';
}, 10000, 'AJAX-запрос не завершился вовремя');
Многие динамические элементы появляются после кликов, ввода текста или других действий пользователя. Для надежного тестирования важно комбинировать действия и ожидания.
Пример последовательного взаимодействия:
const loadButton = element(by.id('load-data'));
const table = element(by.id('data-table'));
await loadButton.click();
await browser.wait(EC.presenceOf(table), 5000);
const rows = await table.all(by.css('tr'));
expect(rows.length).toBeGreaterThan(0);
Работа с динамическими элементами требует аккуратного управления таймаутами. Стандартное ожидание можно настроить глобально:
browser.manage().timeouts().implicitlyWait(5000);
Однако для критически важных элементов предпочтительнее использовать
явные ожидания через browser.wait(), чтобы тесты оставались
предсказуемыми и не зависели от случайных задержек.
Иногда элементы создаются с изменяющимися атрибутами, что делает фиксированные локаторы ненадежными. В таких случаях используют функции-локаторы или регулярные выражения:
const dynamicElement = element(by.cssContainingText('div.item', /Позиция \d+/));
await browser.wait(EC.presenceOf(dynamicElement), 5000);
Также часто применяются xpath-выражения для поиска элементов с частично совпадающими атрибутами:
const button = element(by.xpath("//button[contains(@id,'submit-')]"));
await button.click();
Dynamically changing elements могут быть видимыми только после завершения CSS-анимации. Для корректного взаимодействия стоит использовать проверку кликабельности:
const animatedButton = element(by.id('animated-btn'));
await browser.wait(EC.elementToBeClickable(animatedButton), 5000);
await animatedButton.click();
Для надежного тестирования динамических страниц рекомендуется сочетать:
Такой подход обеспечивает стабильность тестов даже при сложных и непредсказуемых изменениях DOM.