Выполнение JavaScript в контексте браузера

Protractor предоставляет гибкие возможности для взаимодействия с браузером на уровне JavaScript, позволяя выполнять скрипты напрямую в контексте страницы. Это особенно полезно для задач, которые невозможно реализовать стандартными методами WebDriver, таких как сложная манипуляция DOM, получение данных из элементов, не поддерживающих стандартные селекторы, или выполнение действий, зависящих от состояния страницы.

Метод browser.executeScript

Метод browser.executeScript выполняет переданный JavaScript-код в контексте текущей страницы. Он принимает функцию или строку с кодом и возвращает Promise, разрешающийся с результатом выполнения.

Пример использования:

let result = await browser.executeScript(function() {
    return document.title;
});
console.log(result); // выводит заголовок страницы

Важные моменты:

  • Код выполняется внутри браузера, а не в Node.js.
  • Можно передавать аргументы в скрипт через дополнительные параметры:
let sum = await browser.executeScript(function(a, b) {
    return a + b;
}, 5, 7);

console.log(sum); // 12
  • Результатом может быть любой примитив или объект, который может быть сериализован в JSON. DOM-элементы возвращаются как объекты WebElement.

Метод browser.executeAsyncScript

Для выполнения асинхронных операций используется browser.executeAsyncScript. Он позволяет запускать скрипты, которые вызывают callback при завершении. Это удобно, например, для работы с AJAX-запросами или таймерами внутри страницы.

Пример использования:

let data = await browser.executeAsyncScript(function(callback) {
    setTimeout(function() {
        callback('Готово через 2 секунды');
    }, 2000);
});
console.log(data); // 'Готово через 2 секунды'

Особенности:

  • Последний аргумент функции автоматически является callback, который нужно вызвать для завершения скрипта.
  • Можно передавать дополнительные аргументы перед callback.
  • Возвращаемое значение передается через callback в Node.js-контекст.

Взаимодействие с DOM

JavaScript в браузере позволяет получать элементы, манипулировать ими, изменять стили и выполнять события.

Пример получения значения элемента:

let inputValue = await browser.executeScript(function() {
    return document.querySelector('#username').value;
});
console.log(inputValue);

Изменение стиля элемента:

await browser.executeScript(function() {
    document.querySelector('#submitBtn').style.backgroundColor = 'red';
});

Вызов событий:

await browser.executeScript(function() {
    let event = new Event('click');
    document.querySelector('#submitBtn').dispatchEvent(event);
});

Работа с Angular-приложениями

Protractor изначально создан для Angular, поэтому выполнение скриптов можно сочетать с Angular API. Иногда полезно использовать JavaScript для доступа к Angular-моделям:

let modelValue = await browser.executeScript(function() {
    let el = document.querySelector('[ng-model="user.name"]');
    return angular.element(el).scope().user.name;
});
console.log(modelValue);

Важно помнить, что прямой доступ к Angular может зависеть от версии фреймворка и зоны видимости модели.

Передача данных между Node.js и браузером

Любые значения, возвращаемые executeScript или executeAsyncScript, проходят сериализацию. Сложные объекты должны быть преобразованы в JSON:

let data = await browser.executeScript(function() {
    let obj = {name: 'John', age: 30};
    return JSON.stringify(obj);
});

let parsed = JSON.parse(data);
console.log(parsed.name); // John

Ошибки и отладка

При выполнении скриптов возможны ошибки из-за:

  • Неправильного селектора.
  • Попытки обратиться к DOM до полной загрузки страницы.
  • Ограничений безопасности (например, CORS или sandbox).

Для отладки удобно использовать browser.pause() или вывод через console.log внутри скрипта. Также можно возвращать объект с информацией о состоянии элементов:

let info = await browser.executeScript(function() {
    let el = document.querySelector('#test');
    return {exists: !!el, tag: el ? el.tagName : null};
});
console.log(info);

Рекомендации по использованию

  • Использовать JavaScript только там, где стандартные методы Protractor не справляются.
  • Минимизировать сложные скрипты, чтобы не создавать зависимость от внутренней структуры страницы.
  • При работе с асинхронными операциями всегда использовать executeAsyncScript для надежного контроля завершения.

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