Перейти к основному содержимому

Выполнение JavaScript

Введение

Скрипты Playwright выполняются в вашей среде Playwright. Скрипты вашей страницы выполняются в среде страницы браузера. Эти среды не пересекаются, они работают в разных виртуальных машинах в разных процессах и даже потенциально на разных компьютерах.

API Page.evaluate() может выполнять JavaScript-функцию в контексте веб-страницы и возвращать результаты в среду Playwright. Глобальные объекты браузера, такие как window и document, могут использоваться в evaluate.

String href = (String) page.evaluate("document.location.href");

Если результат является Promise или если функция асинхронная, evaluate автоматически дождется ее разрешения:

int status = (int) page.evaluate("async () => {\n" +
" const response = await fetch(location.href);\n" +
" return response.status;\n" +
"}");

Разные среды

Оцениваемые скрипты выполняются в среде браузера, в то время как ваш тест выполняется в тестовой среде. Это означает, что вы не можете использовать переменные из вашего теста на странице и наоборот. Вместо этого вы должны передавать их явно в качестве аргумента.

Следующий фрагмент НЕПРАВИЛЬНЫЙ, потому что он использует переменную напрямую:

String data = "some data";
Object result = page.evaluate("() => {\n" +
" // НЕПРАВИЛЬНО: на веб-странице нет 'data'.\n" +
" window.myApp.use(data);\n" +
"}");

Следующий фрагмент ПРАВИЛЬНЫЙ, потому что он передает значение явно в качестве аргумента:

String data = "some data";
// Передаем |data| в качестве параметра.
Object result = page.evaluate("data => {\n" +
" window.myApp.use(data);\n" +
"}", data);

Аргумент оценки

Методы оценки Playwright, такие как Page.evaluate(), принимают один необязательный аргумент. Этот аргумент может быть смесью значений Serializable и экземпляров JSHandle. Обработчики автоматически преобразуются в представляемое ими значение.

// Примитивное значение.
page.evaluate("num => num", 42);

// Массив.
page.evaluate("array => array.length", Arrays.asList(1, 2, 3));

// Объект.
Map<String, Object> obj = new HashMap<>();
obj.put("foo", "bar");
page.evaluate("object => object.foo", obj);

// Один обработчик.
ElementHandle button = page.evaluateHandle("window.button");
page.evaluate("button => button.textContent", button);

// Альтернативная нотация с использованием JSHandle.evaluate.
button.evaluate("(button, from) => button.textContent.substring(from)", 5);

// Объект с несколькими обработчиками.
ElementHandle button1 = page.evaluateHandle("window.button1");
ElementHandle button2 = page.evaluateHandle("window.button2");
Map<String, ElementHandle> arg = new HashMap<>();
arg.put("button1", button1);
arg.put("button2", button2);
page.evaluate("o => o.button1.textContent + o.button2.textContent", arg);

// Деструктуризация объекта работает. Обратите внимание, что имена свойств должны совпадать
// между деструктурированным объектом и аргументом.
// Также обратите внимание на обязательные скобки.
Map<String, ElementHandle> arg = new HashMap<>();
arg.put("button1", button1);
arg.put("button2", button2);
page.evaluate("({ button1, button2 }) => button1.textContent + button2.textContent", arg);

// Массив также работает. Для деструктуризации можно использовать произвольные имена.
// Обратите внимание на обязательные скобки.
page.evaluate(
"([b1, b2]) => b1.textContent + b2.textContent",
Arrays.asList(button1, button2));

// Любая смесь сериализуемых и обработчиков работает.
Map<String, Object> arg = new HashMap<>();
arg.put("button1", button1);
arg.put("list", Arrays.asList(button2));
arg.put("foo", 0);
page.evaluate(
"x => x.button1.textContent + x.list[0].textContent + String(x.foo)",
arg);

Скрипты инициализации

Иногда удобно выполнить что-то на странице до того, как она начнет загружаться. Например, вы можете захотеть настроить некоторые моки или тестовые данные.

В этом случае используйте Page.addInitScript() или BrowserContext.addInitScript(). В примере ниже мы заменим Math.random() на постоянное значение.

Сначала создайте файл preload.js, содержащий мок.

// preload.js
Math.random = () => 42;

Затем добавьте скрипт инициализации на страницу.

// В вашем тесте, предполагая, что файл "preload.js" находится в каталоге "mocks".
page.addInitScript(Paths.get("mocks/preload.js"));