Protractor — это инструмент для автоматизированного тестирования приложений на Angular и AngularJS, построенный поверх WebDriverJS. Одной из ключевых особенностей современных веб-приложений является динамическая загрузка данных через AJAX, WebSocket или другие асинхронные механизмы. Тестирование таких компонентов требует особого подхода, поскольку элементы на странице могут появляться или изменяться с задержкой.
Для работы с динамическим контентом используется ожидание
появления элементов. Protractor предоставляет объект
ExpectedConditions (EC), позволяющий создавать условия для
ожидания:
const EC = protractor.ExpectedConditions;
const elementToWait = element(by.css('.dynamic-element'));
browser.wait(EC.presenceOf(elementToWait), 5000, 'Элемент не появился в течение 5 секунд');
Ключевые моменты:
presenceOf проверяет, что элемент существует в DOM,
независимо от того, видим он или нет.visibilityOf проверяет, что элемент видим
пользователю.textToBePresentInElement позволяет ожидать появления
определённого текста.Protractor интегрирован с async/await, что позволяет
писать последовательные и читаемые тесты. Пример проверки динамического
текста:
const dynamicElement = element(by.css('.dynamic-text'));
await browser.wait(EC.textToBePresentInElement(dynamicElement, 'Загружено'), 5000);
const text = await dynamicElement.getText();
console.log(text); // Ожидаемый результат: "Загружено"
Если данные подгружаются через AJAX, важно не использовать жесткие
таймауты browser.sleep(), так как это делает тесты
медленными и нестабильными. Вместо этого применяются условия
ожидания:
const listItem = element(by.repeater('item in items').row(0));
await browser.wait(EC.presenceOf(listItem), 10000);
Использование repeater позволяет работать с коллекциями
Angular, динамически обновляемыми на странице.
Для таблиц и списков, где элементы могут меняться после загрузки, Protractor позволяет работать с коллекциями:
const items = element.all(by.css('.list-item'));
await browser.wait(async () => {
const count = await items.count();
return count > 0;
}, 5000, 'Список не загрузился');
Особенности:
element.all возвращает коллекцию, которая
автоматически обновляется при изменении DOM.browser.wait позволяет гибко
проверять условие до его выполнения.В приложениях на Angular часто элементы получают значения через
привязку ng-model или ng-bind. Для проверки
этих значений:
const inputField = element(by.model('user.name'));
await browser.wait(EC.presenceOf(inputField), 5000);
await inputField.sendKeys('Тестовое имя');
const value = await inputField.getAttribute('value');
console.log(value); // "Тестовое имя"
Protractor автоматически ожидает завершения асинхронных операций Angular через механизм Angular Zone. Однако для нестандартных AJAX-запросов вне Angular нужно отключить автоматическую синхронизацию:
browser.waitForAngularEnabled(false);
После выполнения теста можно снова включить синхронизацию:
browser.waitForAngularEnabled(true);
Это особенно важно при работе с внешними библиотеками или REST API, которые не интегрированы с Angular.
Для отладки тестов с динамическим контентом полезно использовать:
browser.sleep(ms) только как временное средство для
проверки, что элемент появляется.browser.takeScreenshot() для фиксирования состояния
страницы в момент ошибки.console.log с результатами
getText() или getAttribute() для проверки
правильности данных.browser.sleep().isPresent(), isDisplayed()).element.all для динамических
списков и таблиц.const notification = element(by.css('.notification-success'));
await browser.wait(EC.visibilityOf(notification), 5000);
const message = await notification.getText();
expect(message).toEqual('Форма успешно отправлена');
const addButton = element(by.buttonText('Добавить'));
await addButton.click();
const newItem = element(by.cssContainingText('.list-item', 'Новый элемент'));
await browser.wait(EC.presenceOf(newItem), 5000);
Эти методы обеспечивают стабильное тестирование динамически изменяющихся страниц, минимизируют вероятность ошибок, связанных с асинхронной загрузкой данных, и позволяют создавать надежные автотесты для сложных веб-приложений на Angular.