Выполнение JavaScript
Введение
Скрипты Playwright выполняются в вашей среде Playwright. Скрипты страницы выполняются в среде браузерной страницы. Эти среды не пересекаются, они работают в разных виртуальных машинах в разных процессах и даже потенциально на разных компьютерах.
API Page.EvaluateAsync() может выполнять JavaScript-функцию в контексте веб-страницы и возвращать результаты в среду Playwright. Глобальные объекты браузера, такие как window
и document
, могут использоваться в evaluate
.
var href = await page.EvaluateAsync<string>("document.location.href");
Если результат является Promise или если функция асинхронная, evaluate автоматически дождется ее разрешения:
int status = await page.EvaluateAsync<int>(@"async () => {
const response = await fetch(location.href);
return response.status;
}");
Разные среды
Выполняемые скрипты работают в среде браузера, в то время как ваш тест выполняется в тестовой среде. Это означает, что вы не можете использовать переменные из вашего теста на странице и наоборот. Вместо этого вы должны передавать их явно в качестве аргумента.
Следующий фрагмент НЕПРАВИЛЬНЫЙ, потому что он использует переменную напрямую:
var data = "some data";
var result = await page.EvaluateAsync(@"() => {
// НЕПРАВИЛЬНО: на веб-странице нет 'data'.
window.myApp.use(data);
}");
Следующий фрагмент ПРАВИЛЬНЫЙ, потому что он передает значение явно в качестве аргумента:
var data = "some data";
// Передаем |data| как параметр.
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
Аргумент для выполнения
Методы выполнения Playwright, такие как Page.EvaluateAsync(), принимают один необязательный аргумент. Этот аргумент может быть смесью значений Serializable и экземпляров JSHandle. Обработчики автоматически преобразуются в представляемое ими значение.
// Примитивное значение.
await page.EvaluateAsync<int>("num => num", 42);
// Массив.
await page.EvaluateAsync<int[]>("array => array.length", new[] { 1, 2, 3 });
// Объект.
await page.EvaluateAsync<object>("object => object.foo", new { foo = "bar" });
// Один обработчик.
var button = await page.EvaluateHandleAsync("window.button");
await page.EvaluateAsync<IJSHandle>("button => button.textContent", button);
// Альтернативная нотация с использованием JSHandle.EvaluateAsync.
await button.EvaluateAsync<string>("(button, from) => button.textContent.substring(from)", 5);
// Объект с несколькими обработчиками.
var button1 = await page.EvaluateHandleAsync("window.button1");
var button2 = await page.EvaluateHandleAsync("window.button2");
await page.EvaluateAsync("o => o.button1.textContent + o.button2.textContent", new { button1, button2 });
// Деструктуризация объекта работает. Обратите внимание, что имена свойств должны совпадать
// между деструктурированным объектом и аргументом.
// Также обратите внимание на обязательные скобки.
await page.EvaluateAsync("({ button1, button2 }) => button1.textContent + button2.textContent", new { button1, button2 });
// Массив также работает. Можно использовать произвольные имена для деструктуризации.
// Обратите внимание на обязательные скобки.
await page.EvaluateAsync("([b1, b2]) => b1.textContent + b2.textContent", new[] { button1, button2 });
// Любая смесь сериализуемых и обработчиков работает.
await page.EvaluateAsync("x => x.button1.textContent + x.list[0].textContent + String(x.foo)", new { button1, list = new[] { button2 }, foo = null as object });
Скрипты инициализации
Иногда удобно выполнить что-то на странице до того, как она начнет загружаться. Например, вы можете захотеть настроить некоторые моки или тестовые данные.
В этом случае используйте Page.AddInitScriptAsync() или BrowserContext.AddInitScriptAsync(). В примере ниже мы заменим Math.random()
на постоянное значение.
Сначала создайте файл preload.js
, содержащий мок.
// preload.js
Math.random = () => 42;
Затем добавьте скрипт инициализации на страницу.
// В вашем тесте, предполагая, что файл "preload.js" находится в директории "mocks".
await Page.AddInitScriptAsync(scriptPath: "mocks/preload.js");