docs(evaluate): improve the guide (#32222)
This commit is contained in:
Родитель
109cab66f1
Коммит
b66cb6caaa
|
@ -68,9 +68,95 @@ int status = await page.EvaluateAsync<int>(@"async () => {
|
|||
}");
|
||||
```
|
||||
|
||||
## Different environments
|
||||
|
||||
Evaluated scripts run in the browser environment, while your test runs in a testing environments. This means you cannot use variables from your test in the page and vice versa. Instead, you should pass them explicitly as an argument.
|
||||
|
||||
The following snippet is **WRONG** because it uses the variable directly:
|
||||
|
||||
```js
|
||||
const data = 'some data';
|
||||
const result = await page.evaluate(() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data);
|
||||
});
|
||||
```
|
||||
|
||||
```java
|
||||
String data = "some data";
|
||||
Object result = page.evaluate("() => {\n" +
|
||||
" // WRONG: there is no 'data' in the web page.\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}");
|
||||
```
|
||||
|
||||
```python async
|
||||
data = "some data"
|
||||
result = await page.evaluate("""() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = "some data"
|
||||
result = page.evaluate("""() => {
|
||||
// WRONG: there is no "data" in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = "some data";
|
||||
var result = await page.EvaluateAsync(@"() => {
|
||||
// WRONG: there is no 'data' in the web page.
|
||||
window.myApp.use(data);
|
||||
}");
|
||||
```
|
||||
|
||||
The following snippet is **CORRECT** because it passes the value explicitly as an argument:
|
||||
|
||||
```js
|
||||
const data = 'some data';
|
||||
// Pass |data| as a parameter.
|
||||
const result = await page.evaluate(data => {
|
||||
window.myApp.use(data);
|
||||
}, data);
|
||||
```
|
||||
|
||||
```java
|
||||
String data = "some data";
|
||||
// Pass |data| as a parameter.
|
||||
Object result = page.evaluate("data => {\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}", data);
|
||||
```
|
||||
|
||||
```python async
|
||||
data = "some data"
|
||||
# Pass |data| as a parameter.
|
||||
result = await page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = "some data"
|
||||
# Pass |data| as a parameter.
|
||||
result = page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = "some data";
|
||||
// Pass |data| as a parameter.
|
||||
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
|
||||
```
|
||||
|
||||
## Evaluation Argument
|
||||
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] or [ElementHandle] instances. Handles are automatically converted to the value they represent.
|
||||
Playwright evaluation methods like [`method: Page.evaluate`] take a single optional argument. This argument can be a mix of [Serializable] values and [JSHandle] instances. Handles are automatically converted to the value they represent.
|
||||
|
||||
```js
|
||||
// A primitive value.
|
||||
|
@ -86,7 +172,7 @@ await page.evaluate(object => object.foo, { foo: 'bar' });
|
|||
const button = await page.evaluateHandle('window.button');
|
||||
await page.evaluate(button => button.textContent, button);
|
||||
|
||||
// Alternative notation using elementHandle.evaluate.
|
||||
// Alternative notation using JSHandle.evaluate.
|
||||
await button.evaluate((button, from) => button.textContent.substring(from), 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
@ -109,7 +195,7 @@ await page.evaluate(
|
|||
([b1, b2]) => b1.textContent + b2.textContent,
|
||||
[button1, button2]);
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
await page.evaluate(
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo),
|
||||
{ button1, list: [button2], foo: null });
|
||||
|
@ -131,7 +217,7 @@ page.evaluate("object => object.foo", obj);
|
|||
ElementHandle button = page.evaluateHandle("window.button");
|
||||
page.evaluate("button => button.textContent", button);
|
||||
|
||||
// Alternative notation using elementHandle.evaluate.
|
||||
// Alternative notation using JSHandle.evaluate.
|
||||
button.evaluate("(button, from) => button.textContent.substring(from)", 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
@ -156,7 +242,7 @@ page.evaluate(
|
|||
"([b1, b2]) => b1.textContent + b2.textContent",
|
||||
Arrays.asList(button1, button2));
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
Map<String, Object> arg = new HashMap<>();
|
||||
arg.put("button1", button1);
|
||||
arg.put("list", Arrays.asList(button2));
|
||||
|
@ -180,7 +266,7 @@ await page.evaluate('object => object.foo', { 'foo': 'bar' })
|
|||
button = await page.evaluate_handle('button')
|
||||
await page.evaluate('button => button.textContent', button)
|
||||
|
||||
# Alternative notation using elementHandle.evaluate.
|
||||
# Alternative notation using JSHandle.evaluate.
|
||||
await button.evaluate('(button, from) => button.textContent.substring(from)', 5)
|
||||
|
||||
# Object with multiple handles.
|
||||
|
@ -203,7 +289,7 @@ await page.evaluate("""
|
|||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
# Any mix of serializables and handles works.
|
||||
await page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
|
@ -223,7 +309,7 @@ page.evaluate('object => object.foo', { 'foo': 'bar' })
|
|||
button = page.evaluate_handle('window.button')
|
||||
page.evaluate('button => button.textContent', button)
|
||||
|
||||
# Alternative notation using elementHandle.evaluate.
|
||||
# Alternative notation using JSHandle.evaluate.
|
||||
button.evaluate('(button, from) => button.textContent.substring(from)', 5)
|
||||
|
||||
# Object with multiple handles.
|
||||
|
@ -245,7 +331,7 @@ page.evaluate("""
|
|||
([b1, b2]) => b1.textContent + b2.textContent""",
|
||||
[button1, button2])
|
||||
|
||||
# Any non-cyclic mix of serializables and handles works.
|
||||
# Any mix of serializables and handles works.
|
||||
page.evaluate("""
|
||||
x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
|
||||
{ 'button1': button1, 'list': [button2], 'foo': None })
|
||||
|
@ -265,7 +351,7 @@ 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);
|
||||
|
||||
// Alternative notation using elementHandle.EvaluateAsync.
|
||||
// Alternative notation using JSHandle.EvaluateAsync.
|
||||
await button.EvaluateAsync<string>("(button, from) => button.textContent.substring(from)", 5);
|
||||
|
||||
// Object with multiple handles.
|
||||
|
@ -282,93 +368,69 @@ await page.EvaluateAsync("({ button1, button2 }) => button1.textContent + button
|
|||
// Note the required parenthesis.
|
||||
await page.EvaluateAsync("([b1, b2]) => b1.textContent + b2.textContent", new[] { button1, button2 });
|
||||
|
||||
// Any non-cyclic mix of serializables and handles works.
|
||||
// Any mix of serializables and handles works.
|
||||
await page.EvaluateAsync("x => x.button1.textContent + x.list[0].textContent + String(x.foo)", new { button1, list = new[] { button2 }, foo = null as object });
|
||||
```
|
||||
|
||||
Right:
|
||||
## Init scripts
|
||||
|
||||
Sometimes it is convenient to evaluate something in the page before it starts loading. For example, you might want to setup some mocks or test data.
|
||||
|
||||
In this case, use [`method: Page.addInitScript`] or [`method: BrowserContext.addInitScript`]. In the example below, we will replace `Math.random()` with a constant value.
|
||||
|
||||
First, create a `preload.js` file that contains the mock.
|
||||
|
||||
```js browser
|
||||
// preload.js
|
||||
Math.random = () => 42;
|
||||
```
|
||||
|
||||
Next, add init script to the page.
|
||||
|
||||
```js
|
||||
const data = { text: 'some data', value: 1 };
|
||||
// Pass |data| as a parameter.
|
||||
const result = await page.evaluate(data => {
|
||||
window.myApp.use(data);
|
||||
}, data);
|
||||
```
|
||||
import { test, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
```java
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("text", "some data");
|
||||
data.put("value", 1);
|
||||
// Pass |data| as a parameter.
|
||||
Object result = page.evaluate("data => {\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}", data);
|
||||
```
|
||||
|
||||
```python async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = await page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
# Pass |data| as a parameter.
|
||||
result = page.evaluate("""data => {
|
||||
window.myApp.use(data)
|
||||
}""", data)
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync("data => { window.myApp.use(data); }", data);
|
||||
```
|
||||
|
||||
Wrong:
|
||||
|
||||
```js
|
||||
const data = { text: 'some data', value: 1 };
|
||||
const result = await page.evaluate(() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data);
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Add script for every test in the beforeEach hook.
|
||||
// Make sure to correctly resolve the script path.
|
||||
await page.addInitScript({ path: path.resolve(__dirname, '../mocks/preload.js') });
|
||||
});
|
||||
```
|
||||
|
||||
```java
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("text", "some data");
|
||||
data.put("value", 1);
|
||||
Object result = page.evaluate("() => {\n" +
|
||||
" // There is no |data| in the web page.\n" +
|
||||
" window.myApp.use(data);\n" +
|
||||
"}");
|
||||
// In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
page.addInitScript(Paths.get("mocks/preload.js"));
|
||||
```
|
||||
|
||||
```python async
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = await page.evaluate("""() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
# In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
await page.add_init_script(path="mocks/preload.js")
|
||||
```
|
||||
|
||||
```python sync
|
||||
data = { 'text': 'some data', 'value': 1 }
|
||||
result = page.evaluate("""() => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data)
|
||||
}""")
|
||||
# In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
page.add_init_script(path="mocks/preload.js")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var data = new { text = "some data", value = 1};
|
||||
// Pass data as a parameter
|
||||
var result = await page.EvaluateAsync(@"data => {
|
||||
// There is no |data| in the web page.
|
||||
window.myApp.use(data);
|
||||
}");
|
||||
// In your test, assuming the "preload.js" file is in the "mocks" directory.
|
||||
await Page.AddInitScriptAsync(scriptPath: "mocks/preload.js");
|
||||
```
|
||||
|
||||
######
|
||||
* langs: js
|
||||
|
||||
Alternatively, you can pass a function instead of creating a preload script file. This is more convenient for short or one-off scripts. You can also pass an argument this way.
|
||||
|
||||
```js
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// Add script for every test in the beforeEach hook.
|
||||
test.beforeEach(async ({ page }) => {
|
||||
const value = 42;
|
||||
await page.addInitScript(value => {
|
||||
Math.random = () => value;
|
||||
}, value);
|
||||
});
|
||||
```
|
||||
|
|
Загрузка…
Ссылка в новой задаче