Protractor строится поверх Selenium WebDriver и обеспечивает
синхронизацию с Angular-приложениями. Однако, несмотря на
высокоуровневую абстракцию, стандартные методы WebDriver накладывают
ограничения на доступ к DOM, обработку асинхронных операций и выполнение
действий, недоступных через публичный API. Для обхода этих ограничений
активно используется JavaScript-интерфейс, предоставляемый методом
browser.executeScript().
browser.executeScript()Метод browser.executeScript() позволяет выполнять
произвольный JavaScript-код непосредственно в контексте страницы.
Основные моменты:
.then().Пример: получение текста скрытого элемента
const hiddenText = await browser.executeScript(
"return document.querySelector('#hidden-element').textContent;"
);
console.log(hiddenText);
В этом примере #hidden-element может быть скрыт
стандартными CSS-правилами (display: none или
visibility: hidden), что делает его недоступным для
element(by.css(...)).getText().
Прямое выполнение JavaScript позволяет инициировать события и изменять свойства элементов:
await browser.executeScript(() => {
const btn = document.querySelector('#submit');
btn.click();
});
Такой подход эффективен, если WebDriver не может корректно инициировать клик из-за перекрытия элементов или сложной анимации.
Для создания кастомных событий:
await browser.executeScript(() => {
const input = document.querySelector('#input-field');
const event = new Event('input', { bubbles: true });
input.value = 'Тестовое значение';
input.dispatchEvent(event);
});
Это позволяет обойти ограничения стандартного метода
sendKeys(), особенно для сложных Angular-форм с двумя-way
binding.
executeAsyncScript() используется для выполнения кода,
который завершает работу через колбек:
const result = await browser.executeAsyncScript((done) => {
setTimeout(() => {
done('Асинхронный результат');
}, 1000);
});
console.log(result); // 'Асинхронный результат'
done,
которую необходимо вызвать для завершения.Protractor предоставляет возможности работы с Angular через
browser.executeScript():
const angularScope = await browser.executeScript(() => {
const el = document.querySelector('[ng-controller="MyController"]');
return angular.element(el).scope().myModel;
});
console.log(angularScope);
Некоторые атрибуты или свойства, например hidden,
readonly, value, часто недоступны через
стандартный API:
const value = await browser.executeScript(
"return document.querySelector('#my-input').value;"
);
console.log(value);
Можно устанавливать свойства напрямую:
await browser.executeScript(
"document.querySelector('#my-input').value = 'Новое значение';"
);
Такой подход позволяет эмулировать действия пользователя, когда WebDriver ограничен политикой браузера или Angular-движком.
Обычные методы WebDriver для переключения между окнами или фреймами иногда оказываются недостаточны, особенно при сложной структуре DOM. Через JavaScript можно:
iframe без
необходимости переключения контекста:const iframeDoc = await browser.executeScript(
"return document.querySelector('#my-iframe').contentDocument;"
);
await browser.executeScript(
"document.querySelector('#overlay').style.display = 'none';"
);
executeScript() может
нарушить синхронизацию Angular в Protractor.executeScript() только для операций,
недоступных через стандартные методы Protractor.async/await.by.model, by.binding) с JS-обходами
при необходимости.Обход ограничений WebDriver через JavaScript открывает полный доступ к DOM и Angular-контексту, позволяя реализовать тесты, которые невозможно написать стандартными средствами Protractor. Это ключевой инструмент для обеспечения надёжности и гибкости тестового покрытия сложных приложений.