docs: extract handles, screenshots, videos docs (#5045)
This commit is contained in:
parent
0a7b917ee3
commit
01fb3a6045
|
|
@ -1,15 +1,21 @@
|
|||
---
|
||||
id: actionability
|
||||
title: "Actionability"
|
||||
title: "Auto-waiting"
|
||||
---
|
||||
|
||||
Playwright does a range of actionability checks on the elements before performing certain actions. These checks ensure that action behaves as expected, for example Playwright does not click on a disabled button.
|
||||
Playwright performs a range of actionability checks on the elements before making actions to ensure these actions
|
||||
behave as expected. It auto-waits for all the relevant checks to pass and only then performs the requested action. If the required checks do not pass within the given `timeout`, action fails with the `TimeoutError`.
|
||||
|
||||
Playwright waits until all the relevant actionability checks pass before performing an action. This means that action will fail with the `TimeoutError` if checks do not pass within the specified `timeout`.
|
||||
For example, for [`method: Page.click`], Playwright will ensure that:
|
||||
- element is [Attached] to the DOM
|
||||
- element is [Visible]
|
||||
- element is [Stable], as in not animating or completed animation
|
||||
- element [Receives Events], as in not obscured by other elements
|
||||
- element is [Enabled]
|
||||
|
||||
Some actions like [`method: Page.click`] support `force` option that disables non-essential actionability checks, for example passing truthy `force` to [`method: Page.click`] method will not check that the target element actually receives click events.
|
||||
Here is the complete list of actionability checks performed for each action:
|
||||
|
||||
| Action | [Attached] | [Visible] | [Stable] | [Receiving Events] | [Enabled] | [Editable] |
|
||||
| Action | [Attached] | [Visible] | [Stable] | [Receives Events] | [Enabled] | [Editable] |
|
||||
| :- | :-: | :-: | :-: | :-: | :-: | :-: |
|
||||
| check | Yes | Yes | Yes | Yes | Yes | - |
|
||||
| click | Yes | Yes | Yes | Yes | Yes | - |
|
||||
|
|
@ -32,7 +38,19 @@ Some actions like [`method: Page.click`] support `force` option that disables no
|
|||
| textContent | Yes | - | - | - | - | - |
|
||||
| type | Yes | - | - | - | - | - |
|
||||
|
||||
You can check the actionability state of the element using one of the following methods:
|
||||
<br/>
|
||||
|
||||
## Forcing actions
|
||||
|
||||
Some actions like [`method: Page.click`] support `force` option that disables non-essential actionability checks,
|
||||
for example passing truthy `force` to [`method: Page.click`] method will not check that the target element actually
|
||||
receives click events.
|
||||
|
||||
## Assertions
|
||||
|
||||
You can check the actionability state of the element using one of the following methods as well. This is typically
|
||||
not necessary, but it helps writing assertive tests that ensure that after certain actions, elements reach
|
||||
actionable state:
|
||||
|
||||
- [`method: ElementHandle.isChecked`]
|
||||
- [`method: ElementHandle.isDisabled`]
|
||||
|
|
@ -47,33 +65,32 @@ You can check the actionability state of the element using one of the following
|
|||
- [`method: Page.isHidden`]
|
||||
- [`method: Page.isVisible`]
|
||||
|
||||
### Visible
|
||||
<br/>
|
||||
|
||||
Element is considered visible when it has non-empty bounding box and does not have `visibility:hidden` computed style. Note that elements of zero size or with `display:none` are not considered visible.
|
||||
|
||||
### Stable
|
||||
|
||||
Element is considered stable when it has maintained the same bounding box for at least two consecutive animation frames.
|
||||
|
||||
### Enabled
|
||||
|
||||
Element is considered enabled when it is not a `<button>`, `<select>`, `<input>` or `<textarea>` with a `disabled` property set.
|
||||
|
||||
### Editable
|
||||
|
||||
Element is considered editable when it is [enabled] and does not have `readonly` property set.
|
||||
|
||||
### Receiving events
|
||||
|
||||
Element is considered receiving pointer events when it is the hit target of the pointer event at the action point. For example, when clicking at the point `(10;10)`, Playwright checks whether some other element (usually an overlay) will instead capture the click at `(10;10)`.
|
||||
|
||||
### Attached
|
||||
## Attached
|
||||
|
||||
Element is considered attached when it is [connected](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected) to a Document or a ShadowRoot.
|
||||
|
||||
Attached check differs between selector-based and handle-based actions, like [`method: Page.click`] as opposite to [`method: ElementHandle.click`]:
|
||||
- For selector-based actions, Playwright first waits for an element matching `selector` to be attached to the DOM, and then checks that element is still attached before performing the action. If element was detached, the action is retried from the start.
|
||||
- For handle-based actions, Playwright throws if the element is not attached.
|
||||
## Visible
|
||||
|
||||
Element is considered visible when it has non-empty bounding box and does not have `visibility:hidden` computed style. Note that elements of zero size or with `display:none` are not considered visible.
|
||||
|
||||
## Stable
|
||||
|
||||
Element is considered stable when it has maintained the same bounding box for at least two consecutive animation frames.
|
||||
|
||||
## Enabled
|
||||
|
||||
Element is considered enabled when it is not a `<button>`, `<select>`, `<input>` or `<textarea>` with a `disabled` property set.
|
||||
|
||||
## Editable
|
||||
|
||||
Element is considered editable when it is [enabled] and does not have `readonly` property set.
|
||||
|
||||
## Receives Events
|
||||
|
||||
Element is considered receiving pointer events when it is the hit target of the pointer event at the action point. For example, when clicking at the point `(10;10)`, Playwright checks whether some other element (usually an overlay) will instead capture the click at `(10;10)`.
|
||||
|
||||
|
||||
For example, consider a scenario where Playwright will click `Sign Up` button regardless of when the [`method: Page.click`] call was made:
|
||||
- page is checking that user name is unique and `Sign Up` button is disabled;
|
||||
|
|
@ -83,5 +100,5 @@ For example, consider a scenario where Playwright will click `Sign Up` button re
|
|||
[Stable]: #stable "Stable"
|
||||
[Enabled]: #enabled "Enabled"
|
||||
[Editable]: #editable "Editable"
|
||||
[Receiving Events]: #receiving-events "Receiving Events"
|
||||
[Receives Events]: #receives-events "Receives Events"
|
||||
[Attached]: #attached "Attached"
|
||||
|
|
|
|||
|
|
@ -3,144 +3,175 @@ id: assertions
|
|||
title: "Assertions"
|
||||
---
|
||||
|
||||
The Playwright API can be used to read element contents and properties for test assertions. These values are fetched from the browser page and asserted in
|
||||
your script.
|
||||
Playwright provides convenience APIs for common tasks, like reading the
|
||||
text content of an element. These APIs can be used in your test assertions.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Common patterns
|
||||
|
||||
Playwright provides convenience APIs for common assertion tasks, like finding the
|
||||
text content of an element. These APIs require a [selector](./selectors.md) to locate
|
||||
the element.
|
||||
## Text content
|
||||
|
||||
```js
|
||||
// This example uses the Node.js's built-in `assert` module,
|
||||
// but any assertion library (Expect, Chai, etc.) will work.
|
||||
|
||||
// Assert text content
|
||||
const content = await page.textContent('nav:first-child');
|
||||
assert(content === 'home');
|
||||
|
||||
// Assert inner text
|
||||
const text = await page.innerText('.selected');
|
||||
assert(text === 'value');
|
||||
|
||||
// Assert inner HTML
|
||||
const html = await page.innerHTML('div.result');
|
||||
assert(html === '<p>Result</p>')
|
||||
|
||||
// Assert `checked` attribute
|
||||
const checked = await page.getAttribute('input', 'checked');
|
||||
assert(checked);
|
||||
expect(content).toBe('home');
|
||||
```
|
||||
|
||||
```python async
|
||||
# Assert text content
|
||||
content = await page.text_content('nav:first-child')
|
||||
assert content == 'home'
|
||||
|
||||
# Assert inner text
|
||||
text = await page.inner_text('.selected')
|
||||
assert text == 'value'
|
||||
|
||||
# Assert inner HTML
|
||||
html = await page.inner_html('div.result')
|
||||
assert html == '<p>Result</p>'
|
||||
|
||||
# Assert `checked` attribute
|
||||
checked = await page.get_attribute('input', 'checked')
|
||||
assert checked
|
||||
content = await page.text_content("nav:first-child")
|
||||
assert content == "home"
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Assert text content
|
||||
content = page.text_content('nav:first-child')
|
||||
assert content == 'home'
|
||||
|
||||
# Assert inner text
|
||||
text = page.inner_text('.selected')
|
||||
assert text == 'value'
|
||||
|
||||
# Assert inner HTML
|
||||
html = page.inner_html('div.result')
|
||||
assert html == '<p>Result</p>'
|
||||
|
||||
# Assert `checked` attribute
|
||||
checked = page.get_attribute('input', 'checked')
|
||||
assert checked
|
||||
content = page.text_content("nav:first-child")
|
||||
assert content == "home"
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: Page.textContent`]
|
||||
### API reference
|
||||
- [`method: Page.innerText`]
|
||||
- [`method: Page.innerHTML`]
|
||||
- [`method: Page.getAttribute`]
|
||||
- [`method: Frame.textContent`]
|
||||
- [`method: Frame.innerText`]
|
||||
- [`method: Frame.innerHTML`]
|
||||
- [`method: Frame.getAttribute`]
|
||||
- [`method: ElementHandle.innerText`]
|
||||
|
||||
<br/>
|
||||
|
||||
## Element Handles
|
||||
|
||||
[ElementHandle] objects represent in-page DOM
|
||||
elements. They can be used to assert for multiple properties of the element.
|
||||
|
||||
It is recommended to fetch the [ElementHandle] object with
|
||||
[`method: Page.waitForSelector`] or [`method: Frame.waitForSelector`]. These
|
||||
APIs wait for the element to be visible and then return an `ElementHandle`.
|
||||
## Inner text
|
||||
|
||||
```js
|
||||
// Get the element handle
|
||||
const elementHandle = page.waitForSelector('#box');
|
||||
|
||||
// Assert bounding box for the element
|
||||
const boundingBox = await elementHandle.boundingBox();
|
||||
assert(boundingBox.width === 100);
|
||||
|
||||
// Assert attribute for the element
|
||||
const classNames = await elementHandle.getAttribute('class');
|
||||
assert(classNames.includes('highlighted'));
|
||||
const text = await page.innerText('.selected');
|
||||
expect(text).toBe('value');
|
||||
```
|
||||
|
||||
```python async
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = await element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = await element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
text = await page.inner_text(".selected")
|
||||
assert text == "value"
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
text = page.inner_text(".selected")
|
||||
assert text == "value"
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
- [`method: ElementHandle.textContent`]
|
||||
### API reference
|
||||
- [`method: Page.innerText`]
|
||||
- [`method: ElementHandle.innerText`]
|
||||
- [`method: ElementHandle.innerHTML`]
|
||||
- [`method: ElementHandle.getAttribute`]
|
||||
- [`method: ElementHandle.boundingBox`]
|
||||
|
||||
<br/>
|
||||
## Attribute value
|
||||
|
||||
```js
|
||||
const alt = await page.getAttribute('input', 'alt');
|
||||
expect(alt).toBe('Text');
|
||||
```
|
||||
|
||||
```python async
|
||||
checked = await page.get_attribute("input", "alt")
|
||||
assert alt == "Text"
|
||||
```
|
||||
|
||||
```python sync
|
||||
checked = page.get_attribute("input", "alt")
|
||||
assert alt == "Text"
|
||||
```
|
||||
|
||||
## Checkbox state
|
||||
|
||||
```js
|
||||
const checked = await page.isChecked('input');
|
||||
expect(checked).toBeTruthy();
|
||||
```
|
||||
|
||||
```python async
|
||||
checked = await page.is_checked("input")
|
||||
assert checked
|
||||
```
|
||||
|
||||
```python sync
|
||||
checked = page.is_checked("input")
|
||||
assert checked
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.isChecked`]
|
||||
- [`method: ElementHandle.isChecked`]
|
||||
|
||||
## JS expression
|
||||
|
||||
```js
|
||||
const content = await page.$eval('nav:first-child', e => e.textContent);
|
||||
expect(content).toBe('home');
|
||||
```
|
||||
|
||||
```python async
|
||||
content = await page.eval_on_selector("nav:first-child", "e => e.textContent")
|
||||
assert content == "home"
|
||||
```
|
||||
|
||||
```python sync
|
||||
content = page.eval_on_selector("nav:first-child", "e => e.textContent")
|
||||
assert content == "home"
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.$eval`]
|
||||
- [`method: JSHandle.evaluate`]
|
||||
|
||||
## Inner HTML
|
||||
|
||||
```js
|
||||
const html = await page.innerHTML('div.result');
|
||||
expect(html).toBe('<p>Result</p>');
|
||||
```
|
||||
|
||||
```python async
|
||||
html = await page.inner_html("div.result")
|
||||
assert html == "<p>Result</p>"
|
||||
```
|
||||
|
||||
```python sync
|
||||
html = page.inner_html("div.result")
|
||||
assert html == "<p>Result</p>"
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.innerHTML`]
|
||||
- [`method: ElementHandle.innerHTML`]
|
||||
|
||||
## Visibility
|
||||
|
||||
```js
|
||||
const visible = await page.isVisible('input');
|
||||
expect(visible).toBeTruthy();
|
||||
```
|
||||
|
||||
```python async
|
||||
visible = await page.is_visible("input")
|
||||
assert visible
|
||||
```
|
||||
|
||||
```python sync
|
||||
visible = page.is_visible("input")
|
||||
assert visible
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.isVisible`]
|
||||
- [`method: ElementHandle.isVisible`]
|
||||
|
||||
## Enabled state
|
||||
|
||||
```js
|
||||
const enabled = await page.isEnabled('input');
|
||||
expect(visible).toBeTruthy();
|
||||
```
|
||||
|
||||
```python async
|
||||
enabled = await page.is_enabled("input")
|
||||
assert enabled
|
||||
```
|
||||
|
||||
```python sync
|
||||
enabled = page.is_enabled("input")
|
||||
assert enabled
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.isEnabled`]
|
||||
- [`method: ElementHandle.isEnabled`]
|
||||
|
||||
## Custom assertions
|
||||
|
||||
|
|
@ -148,27 +179,23 @@ With Playwright, you can also write custom JavaScript to run in the context of
|
|||
the browser. This is useful in situations where you want to assert for values
|
||||
that are not covered by the convenience APIs above.
|
||||
|
||||
The following APIs do not auto-wait for the element. It is recommended to use
|
||||
[`method: Page.waitForSelector`] or
|
||||
[`method: Frame.waitForSelector`].
|
||||
|
||||
```js
|
||||
// Assert local storage value
|
||||
const userId = page.evaluate(() => window.localStorage.getItem('userId'));
|
||||
assert(userId);
|
||||
expect(userId).toBeTruthy();
|
||||
|
||||
// Assert value for input element
|
||||
await page.waitForSelector('#search');
|
||||
const value = await page.$eval('#search', el => el.value);
|
||||
assert(value === 'query');
|
||||
expect(value === 'query').toBeTruthy();
|
||||
|
||||
// Assert computed style
|
||||
const fontSize = await page.$eval('div', el => window.getComputedStyle(el).fontSize);
|
||||
assert(fontSize === '16px');
|
||||
expect(fontSize === '16px').toBeTruthy();
|
||||
|
||||
// Assert list length
|
||||
const length = await page.$$eval('li.selected', (items) => items.length);
|
||||
assert(length === 3);
|
||||
expect(length === 3).toBeTruthy();
|
||||
```
|
||||
|
||||
```python async
|
||||
|
|
@ -209,8 +236,7 @@ length = page.eval_on_selector_all('li.selected', '(items) => items.length')
|
|||
assert length == 3
|
||||
```
|
||||
|
||||
#### API reference
|
||||
|
||||
### API reference
|
||||
- [`method: Page.evaluate`]
|
||||
- [`method: Page.$eval`]
|
||||
- [`method: Page.$$eval`]
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ with sync_playwright() as p:
|
|||
Launching a browser instance can be expensive, and Playwright is designed to
|
||||
maximize what a single instance can do through multiple browser contexts.
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [Browser]
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ with sync_playwright() as p:
|
|||
browser.close()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [BrowserContext]
|
||||
- [`method: Browser.newContext`]
|
||||
|
|
@ -249,7 +249,7 @@ frame = frame_element_handle.content_frame()
|
|||
frame.fill('#username-input', 'John')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [Page]
|
||||
- [Frame]
|
||||
|
|
@ -475,7 +475,7 @@ page.wait_for_selector('#details', state='hidden')
|
|||
page.wait_for_selector('#promo', state='detached')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.click`]
|
||||
- [`method: Page.fill`]
|
||||
|
|
@ -483,12 +483,12 @@ page.wait_for_selector('#promo', state='detached')
|
|||
|
||||
<br/>
|
||||
|
||||
## Execution contexts: Node.js and Browser
|
||||
## Execution contexts: Playwright and Browser
|
||||
|
||||
Playwright scripts run in your Node.js environment. Your page scripts run in the browser page environment. Those environments don't intersect, they are running in different virtual machines in different processes and even potentially on different computers.
|
||||
Playwright scripts run in your Playwright environment. Your page scripts run in the browser page environment. Those environments don't intersect, they are running in different virtual machines in different processes and even potentially on different computers.
|
||||
|
||||
The [`method: Page.evaluate`] API can run a JavaScript function in the context
|
||||
of the web page and bring results back to the Node.js environment. Browser globals like
|
||||
of the web page and bring results back to the Playwright environment. Browser globals like
|
||||
`window` and `document` can be used in `evaluate`.
|
||||
|
||||
```js
|
||||
|
|
@ -710,157 +710,10 @@ result = page.evaluate("""() => {
|
|||
}""")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.evaluate`]
|
||||
- [`method: Frame.evaluate`]
|
||||
- [EvaluationArgument]
|
||||
|
||||
<br/>
|
||||
|
||||
## Object & Element handles
|
||||
|
||||
Playwright can create Node-side handles to the page DOM elements or any other objects inside the page. These handles live in the Node.js process, whereas the actual objects reside in browser.
|
||||
|
||||
There are two types of handles:
|
||||
- [JSHandle] to reference any JavaScript objects in the page
|
||||
- [ElementHandle] to reference DOM elements in the page
|
||||
|
||||
Note that since any DOM element in the page is also a JavaScript object,
|
||||
Playwright's [ElementHandle] extends [JSHandle].
|
||||
|
||||
### Handles Lifecycle
|
||||
- Handles can be acquired using the page methods [`method: Page.evaluateHandle`], [`method: Page.$`] or [`method: Page.$$`] or
|
||||
their frame counterparts [`method: Frame.evaluateHandle`], [`method: Frame.$`] or [`method: Frame.$$`].
|
||||
- Once created, handles will retain object from [garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management).
|
||||
- Handles will be **automatically disposed** once the page or frame they belong to navigates or closes.
|
||||
- Handles can be **manually disposed** using [`method: JSHandle.dispose`] method.
|
||||
|
||||
### Example: ElementHandle
|
||||
|
||||
```js
|
||||
// The first parameter of the elementHandle.evaluate callback is the element handle points to.
|
||||
const ulElementHandle = await page.$('ul');
|
||||
await ulElementHandle.evaluate(ulElement => getComputedStyle(ulElement).getPropertyValue('display'));
|
||||
```
|
||||
|
||||
```python async
|
||||
# The first parameter of the elementHandle.evaluate callback is the element handle points to.
|
||||
ul_element_handle = await page.query_selector('ul')
|
||||
await ul_element_handle.evaluate("ulElement => getComputedStyle(ulElement).getPropertyValue('display')")
|
||||
```
|
||||
|
||||
```python sync
|
||||
# The first parameter of the elementHandle.evaluate callback is the element handle points to.
|
||||
ul_element_handle = page.query_selector('ul')
|
||||
ul_element_handle.evaluate("ulElement => getComputedStyle(ulElement).getPropertyValue('display')")
|
||||
```
|
||||
|
||||
Handles can also be passed as arguments to [`method: Page.evaluate`] function:
|
||||
|
||||
```js
|
||||
// In the page API, you can pass handle as a parameter.
|
||||
const ulElementHandle = await page.$('ul');
|
||||
await page.evaluate(uiElement => getComputedStyle(uiElement).getPropertyValue('display'), uiElement);
|
||||
```
|
||||
|
||||
```python async
|
||||
ul_element_handle = await page.query_selector('ul')
|
||||
await page.evaluate("uiElement => getComputedStyle(uiElement).getPropertyValue('display')", uiElement)
|
||||
```
|
||||
|
||||
```python sync
|
||||
ul_element_handle = page.query_selector('ul')
|
||||
page.evaluate("uiElement => getComputedStyle(uiElement).getPropertyValue('display')", uiElement)
|
||||
```
|
||||
|
||||
### Example: JSHandle
|
||||
|
||||
```js
|
||||
// Create a new array in the page, write a reference to it in
|
||||
// window.myArray and get a handle to it.
|
||||
const myArrayHandle = await page.evaluateHandle(() => {
|
||||
window.myArray = [1];
|
||||
return myArray;
|
||||
});
|
||||
|
||||
// Get current length of the array using the handle.
|
||||
const length = await page.evaluate(
|
||||
(arg) => arg.myArray.length,
|
||||
{ myArray: myArrayHandle }
|
||||
);
|
||||
|
||||
// Add one more element to the array using the handle
|
||||
await page.evaluate((arg) => arg.myArray.push(arg.newElement), {
|
||||
myArray: myArrayHandle,
|
||||
newElement: 2
|
||||
});
|
||||
|
||||
// Get current length of the array using window.myArray reference.
|
||||
const newLength = await page.evaluate(() => window.myArray.length);
|
||||
|
||||
// Release the object when it's no longer needed.
|
||||
await myArrayHandle.dispose();
|
||||
```
|
||||
|
||||
```python async
|
||||
# Create a new array in the page, write a reference to it in
|
||||
# window.myArray and get a handle to it.
|
||||
my_array_handle = await page.evaluate_handle("""() => {
|
||||
window.myArray = [1]
|
||||
return myArray
|
||||
}""")
|
||||
|
||||
# Get current length of the array using the handle.
|
||||
length = await page.evaluate("""
|
||||
(arg) => arg.myArray.length""",
|
||||
{ 'myArray': my_array_handle }
|
||||
)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
await page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Get current length of the array using window.myArray reference.
|
||||
new_length = await page.evaluate("() => window.myArray.length")
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
await my_array_handle.dispose()
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Create a new array in the page, write a reference to it in
|
||||
# window.myArray and get a handle to it.
|
||||
my_array_handle = page.evaluate_handle("""() => {
|
||||
window.myArray = [1]
|
||||
return myArray
|
||||
}""")
|
||||
|
||||
# Get current length of the array using the handle.
|
||||
length = page.evaluate("""
|
||||
(arg) => arg.myArray.length""",
|
||||
{ 'myArray': my_array_handle }
|
||||
)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Get current length of the array using window.myArray reference.
|
||||
new_length = page.evaluate("() => window.myArray.length")
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
my_array_handle.dispose()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
- [JSHandle]
|
||||
- [ElementHandle]
|
||||
- [`method: Page.evaluateHandle`]
|
||||
- [`method: Page.$`]
|
||||
- [`method: Page.$$`]
|
||||
- [`method: JSHandle.evaluate`]
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ page.click("button") # Will hang here
|
|||
page.on("dialog", lambda dialog: dialog.accept())
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`Dialog`]
|
||||
- [`method: Dialog.accept`]
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ page.on("download", lambda download: print(download.path()))
|
|||
Note that handling the event forks the control flow and makes script harder to follow. Your scenario might end while you
|
||||
are downloading a file since your main control flow is not awaiting for this operation to resolve.
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [Download]
|
||||
- [`event: Page.download`]
|
||||
- [`method: Page.waitForEvent`]
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ with sync_playwright() as playwright:
|
|||
|
||||
All pages created in the context above will share the same device parameters.
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`property: Playwright.devices`]
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ context = browser.new_context(
|
|||
)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
<br/>
|
||||
|
|
@ -148,7 +148,7 @@ context = browser.new_context(
|
|||
device_scale_factor=2,
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Page.setViewportSize`]
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ context = browser.new_context(
|
|||
)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
<br/>
|
||||
|
|
@ -249,7 +249,7 @@ await context.clear_permissions()
|
|||
context.clear_permissions()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: BrowserContext.grantPermissions`]
|
||||
- [`method: BrowserContext.clearPermissions`]
|
||||
|
|
@ -297,7 +297,7 @@ context.set_geolocation({"longitude": 29.979097, "latitude": 31.134256})
|
|||
|
||||
**Note** you can only change geolocation for all pages in the context.
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: BrowserContext.setGeolocation`]
|
||||
|
||||
|
|
@ -361,6 +361,6 @@ page.emulate_media(color_scheme='dark')
|
|||
page.emulate_media(media='print')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Page.emulateMedia`]
|
||||
193
docs/src/handles.md
Normal file
193
docs/src/handles.md
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
---
|
||||
id: handles
|
||||
title: "Handles"
|
||||
---
|
||||
|
||||
Playwright can create handles to the page DOM elements or any other objects inside the
|
||||
page. These handles live in the Playwright process, whereas the actual objects live
|
||||
in the browser. There are two types of handles:
|
||||
- [JSHandle] to reference any JavaScript objects in the page
|
||||
- [ElementHandle] to reference DOM elements in the page, it has extra methods that allow
|
||||
performing actions on the elements and asserting their properties.
|
||||
|
||||
Since any DOM element in the page is also a JavaScript object, any [ElementHandle] is
|
||||
a [JSHandle] as well.
|
||||
|
||||
Handles are used to perform operations on those actual objects in the page. You can evaluate
|
||||
on a handle, get handle properties, pass handle as an evaluation parameter, serialize page
|
||||
object into JSON etc. See the [JSHandle] class API for these and methods.
|
||||
|
||||
### API reference
|
||||
- [JSHandle]
|
||||
- [ElementHandle]
|
||||
|
||||
Here is the easiest way to obtain a [JSHandle].
|
||||
|
||||
```js
|
||||
const jsHandle = await page.evaluateHandle('window');
|
||||
// Use jsHandle for evaluations.
|
||||
```
|
||||
|
||||
```python async
|
||||
js_handle = await page.evaluate_handle('window')
|
||||
# Use jsHandle for evaluations.
|
||||
```
|
||||
|
||||
```python sync
|
||||
js_handle = page.evaluate_handle('window')
|
||||
# Use jsHandle for evaluations.
|
||||
```
|
||||
|
||||
```js
|
||||
const ulElementHandle = await page.waitForSelector('ul');
|
||||
// Use ulElementHandle for actions and evaluation.
|
||||
```
|
||||
|
||||
```python async
|
||||
ul_element_handle = await page.wait_for_selector('ul')
|
||||
# Use ul_element_handle for actions and evaluation.
|
||||
```
|
||||
|
||||
```python sync
|
||||
ul_element_handle = page.wait_for_selector('ul')
|
||||
# Use ul_element_handle for actions and evaluation.
|
||||
```
|
||||
|
||||
## Element Handles
|
||||
|
||||
:::note
|
||||
It is recommended to use selector-based actions like [`method: Page.click`] rather than using the [ElementHandle] for input actions, unless your use case specifically requires the use of handles.
|
||||
:::
|
||||
|
||||
When [ElementHandle] is required, it is recommended to fetch it with the
|
||||
[`method: Page.waitForSelector`] or [`method: Frame.waitForSelector`] methods. These
|
||||
APIs wait for the element to be attached and visible.
|
||||
|
||||
```js
|
||||
// Get the element handle
|
||||
const elementHandle = page.waitForSelector('#box');
|
||||
|
||||
// Assert bounding box for the element
|
||||
const boundingBox = await elementHandle.boundingBox();
|
||||
expect(boundingBox.width).toBe(100);
|
||||
|
||||
// Assert attribute for the element
|
||||
const classNames = await elementHandle.getAttribute('class');
|
||||
expect(classNames.includes('highlighted')).toBeTruthy();
|
||||
```
|
||||
|
||||
```python async
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = await element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = await element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Get the element handle
|
||||
element_handle = page.wait_for_selector('#box')
|
||||
|
||||
# Assert bounding box for the element
|
||||
bounding_box = element_handle.bounding_box()
|
||||
assert bounding_box.width == 100
|
||||
|
||||
# Assert attribute for the element
|
||||
class_names = element_handle.get_attribute('class')
|
||||
assert 'highlighted' in class_names
|
||||
```
|
||||
|
||||
## Handles as parameters
|
||||
|
||||
Handles can be passed into the [`method: Page.evaluate`] and similar methods.
|
||||
The following snippet creates a new array in the page, initializes it with data
|
||||
and returns a handle to this array into Playwright. It then uses the handle
|
||||
in subsequent evaluations:
|
||||
|
||||
```js
|
||||
// Create new array in page.
|
||||
const myArrayHandle = await page.evaluateHandle(() => {
|
||||
window.myArray = [1];
|
||||
return myArray;
|
||||
});
|
||||
|
||||
// Get the length of the array.
|
||||
const length = await page.evaluate(a => a.length, myArrayHandle);
|
||||
|
||||
// Add one more element to the array using the handle
|
||||
await page.evaluate(arg => arg.myArray.push(arg.newElement), {
|
||||
myArray: myArrayHandle,
|
||||
newElement: 2
|
||||
});
|
||||
|
||||
// Release the object when it's no longer needed.
|
||||
await myArrayHandle.dispose();
|
||||
```
|
||||
|
||||
```python async
|
||||
# Create new array in page.
|
||||
my_array_handle = await page.evaluate_handle("""() => {
|
||||
window.myArray = [1];
|
||||
return myArray;
|
||||
}""")
|
||||
|
||||
# Get current length of the array.
|
||||
length = await page.evaluate("a => a.length", my_array_handle)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
await page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
await my_array_handle.dispose()
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Create new array in page.
|
||||
my_array_handle = page.evaluate_handle("""() => {
|
||||
window.myArray = [1];
|
||||
return myArray;
|
||||
}""")
|
||||
|
||||
# Get current length of the array.
|
||||
length = page.evaluate("a => a.length", my_array_handle)
|
||||
|
||||
# Add one more element to the array using the handle
|
||||
page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
|
||||
'myArray': my_array_handle,
|
||||
'newElement': 2
|
||||
})
|
||||
|
||||
# Release the object when it's no longer needed.
|
||||
my_array_handle.dispose()
|
||||
```
|
||||
|
||||
## Handle Lifecycle
|
||||
|
||||
Handles can be acquired using the page methods such as [`method: Page.evaluateHandle`],
|
||||
[`method: Page.$`] or [`method: Page.$$`] or their frame counterparts
|
||||
[`method: Frame.evaluateHandle`], [`method: Frame.$`] or [`method: Frame.$$`]. Once
|
||||
created, handles will retain object from
|
||||
[garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management)
|
||||
unless page navigates or the handle is manually disposed via the [`method: JSHandle.dispose`] method.
|
||||
|
||||
|
||||
### API reference
|
||||
- [JSHandle]
|
||||
- [ElementHandle]
|
||||
- [`method: ElementHandle.boundingBox`]
|
||||
- [`method: ElementHandle.getAttribute`]
|
||||
- [`method: ElementHandle.innerText`]
|
||||
- [`method: ElementHandle.innerHTML`]
|
||||
- [`method: ElementHandle.textContent`]
|
||||
- [`method: JSHandle.evaluate`]
|
||||
- [`method: Page.evaluateHandle`]
|
||||
- [`method: Page.$`]
|
||||
- [`method: Page.$$`]
|
||||
|
|
@ -60,7 +60,7 @@ page.fill('#local', '2020-03-02T05:15')
|
|||
page.fill('text=First Name', 'Peter')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.fill`]
|
||||
- [`method: Frame.fill`]
|
||||
|
|
@ -76,6 +76,9 @@ This is the easiest way to check and uncheck a checkbox or a radio button. This
|
|||
// Check the checkbox
|
||||
await page.check('#agree');
|
||||
|
||||
// Assert the checked state
|
||||
expect(await page.isChecked('#agree')).toBeTruthy()
|
||||
|
||||
// Uncheck by input <label>.
|
||||
await page.uncheck('#subscribe-label');
|
||||
|
||||
|
|
@ -87,6 +90,9 @@ await page.check('text=XL');
|
|||
# Check the checkbox
|
||||
await page.check('#agree')
|
||||
|
||||
# Assert the checked state
|
||||
assert await page.is_checked('#agree') is True
|
||||
|
||||
# Uncheck by input <label>.
|
||||
await page.uncheck('#subscribe-label')
|
||||
|
||||
|
|
@ -98,6 +104,9 @@ await page.check('text=XL')
|
|||
# Check the checkbox
|
||||
page.check('#agree')
|
||||
|
||||
# Assert the checked state
|
||||
assert page.is_checked('#agree') is True
|
||||
|
||||
# Uncheck by input <label>.
|
||||
page.uncheck('#subscribe-label')
|
||||
|
||||
|
|
@ -105,13 +114,13 @@ page.uncheck('#subscribe-label')
|
|||
page.check('text=XL')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.check`]
|
||||
- [`method: Page.isChecked`]
|
||||
- [`method: Page.uncheck`]
|
||||
- [`method: Frame.check`]
|
||||
- [`method: Frame.uncheck`]
|
||||
- [`method: ElementHandle.check`]
|
||||
- [`method: ElementHandle.isChecked`]
|
||||
- [`method: ElementHandle.uncheck`]
|
||||
|
||||
<br/>
|
||||
|
|
@ -166,7 +175,7 @@ option = page.query_selector('#best-option')
|
|||
page.select_option('select#colors', option)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.selectOption`]
|
||||
- [`method: Frame.selectOption`]
|
||||
|
|
@ -279,7 +288,7 @@ await page.dispatch_event('button#submit', 'click')
|
|||
page.dispatch_event('button#submit', 'click')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.click`]
|
||||
- [`method: Frame.click`]
|
||||
|
|
@ -321,7 +330,7 @@ This method will emit all the necessary keyboard events, with all the `keydown`,
|
|||
Most of the time, [`method: Page.fill`] will just work. You only need to type characters if there is special keyboard handling on the page.
|
||||
:::
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.type`]
|
||||
- [`method: Frame.type`]
|
||||
|
|
@ -409,7 +418,7 @@ Shortcuts such as `"Control+o"` or `"Control+Shift+T"` are supported as well. Wh
|
|||
Note that you still need to specify the capital `A` in `Shift-A` to produce the capital character. `Shift-a` produces a lower-case one as if you had the `CapsLock` toggled.
|
||||
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.press`]
|
||||
- [`method: Frame.press`]
|
||||
|
|
@ -482,7 +491,7 @@ You can select input files for upload using the [`method: Page.setInputFiles`] m
|
|||
|
||||
[This script](https://github.com/microsoft/playwright/blob/master/utils/docs/examples/upload.js) uploads a file to an `input` element that accepts file uploads.
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.setInputFiles`]
|
||||
- [`method: Frame.setInputFiles`]
|
||||
|
|
@ -506,7 +515,7 @@ await page.focus('input#name')
|
|||
page.focus('input#name')
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
|
||||
- [`method: Page.focus`]
|
||||
- [`method: Frame.focus`]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
---
|
||||
id: mobile
|
||||
title: "Experimental support for Chrome for Android"
|
||||
title: "Mobile (experimental)"
|
||||
---
|
||||
|
||||
<!-- TOC -->
|
||||
:::warning
|
||||
Mobile support is experimental and uses prefixed provisional API.
|
||||
:::
|
||||
|
||||
You can try Playwright against Chrome for Android today. This support is experimental. Support for devices is tracked in the issue [#1122](https://github.com/microsoft/playwright/issues/1122).
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Playwright 1.6](https://www.npmjs.com/package/playwright) or newer
|
||||
- [ADB daemon](https://developer.android.com/studio/command-line/adb) running and authenticated with your device.
|
||||
- [`Chrome 87`](https://play.google.com/store/apps/details?id=com.android.chrome) or newer installed on the device
|
||||
- "Enable command line on non-rooted devices" enabled in `chrome://flags`.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ with sync_playwright() as playwright:
|
|||
run(playwright)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [BrowserContext]
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: BrowserContext.addCookies`]
|
||||
|
|
@ -110,7 +110,7 @@ page_two = context.new_page()
|
|||
all_pages = context.pages()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [Page]
|
||||
- [`method: BrowserContext.newPage`]
|
||||
- [`method: BrowserContext.pages`]
|
||||
|
|
@ -178,7 +178,7 @@ def handle_page(page):
|
|||
context.on("page", handle_page)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`event: BrowserContext.page`]
|
||||
|
||||
## Handling popups
|
||||
|
|
@ -245,5 +245,5 @@ def handle_popup(popup):
|
|||
page.on("popup", handle_popup)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`event: Page.popup`]
|
||||
|
|
@ -108,7 +108,7 @@ page.goto("https://example.com")
|
|||
page.click("text=example domain")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Page.goto`]
|
||||
- [`method: Page.reload`]
|
||||
- [`method: Page.goBack`]
|
||||
|
|
@ -297,7 +297,7 @@ popup = popup_info.value
|
|||
popup.wait_for_load_state("load")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Page.click`]
|
||||
- [`method: Page.waitForLoadState`]
|
||||
- [`method: Page.waitForSelector`]
|
||||
|
|
@ -331,5 +331,5 @@ page.wait_for_function("() => window.amILoadedYet()")
|
|||
page.screenshot()
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Page.waitForFunction`]
|
||||
|
|
@ -40,7 +40,7 @@ page = context.new_page()
|
|||
page.goto("https://example.com")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Browser.newContext`]
|
||||
|
||||
## Network events
|
||||
|
|
@ -166,7 +166,7 @@ with page.expect_response(lambda response: token in response.url) as response_in
|
|||
response = response_info.value
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [Request]
|
||||
- [Response]
|
||||
- [`event: Page.request`]
|
||||
|
|
@ -233,7 +233,7 @@ context.route(
|
|||
page.goto("https://example.com")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: BrowserContext.route`]
|
||||
- [`method: BrowserContext.unroute`]
|
||||
- [`method: Page.route`]
|
||||
|
|
@ -308,7 +308,7 @@ page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())
|
|||
page.route("**/*", lambda route: route.abort() if route.request.resource_type == "image" else route.continue_())
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [`method: Page.route`]
|
||||
- [`method: BrowserContext.route`]
|
||||
- [`method: Route.abort`]
|
||||
|
|
|
|||
82
docs/src/screenshots.md
Normal file
82
docs/src/screenshots.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
id: screenshots
|
||||
title: "Screenshots"
|
||||
---
|
||||
|
||||
Here is a quick way to capture a screenshot and save it into a file:
|
||||
|
||||
```js
|
||||
await page.screenshot({ path: 'screenshot.png' });
|
||||
```
|
||||
|
||||
```python async
|
||||
await page.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
```python sync
|
||||
page.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
Screenshots API accepts many parameters for image format, clip area, quality, etc. Make sure to check them out.
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Full page screenshots
|
||||
|
||||
Full page screenshot is a screenshot of a full scrollable page, as if you had a very
|
||||
tall screen and the page could fit it entirely.
|
||||
|
||||
```js
|
||||
await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
||||
```
|
||||
|
||||
```python async
|
||||
await page.screenshot(path="screenshot.png", full_page=True)
|
||||
```
|
||||
|
||||
```python sync
|
||||
page.screenshot(path="screenshot.png", full_page=True)
|
||||
```
|
||||
|
||||
## Capture into buffer
|
||||
|
||||
Rather than writing into a file, you can get a buffer with the image and post-process it or pass it to a third party pixel diff facility.
|
||||
|
||||
```js
|
||||
const buffer = await page.screenshot();
|
||||
console.log(buffer.toString('base64'));
|
||||
```
|
||||
|
||||
```python async
|
||||
# Capture into Image
|
||||
screenshot_bytes = await page.screenshot()
|
||||
image = Image.open(io.BytesIO(screenshot_bytes))
|
||||
```
|
||||
|
||||
```python sync
|
||||
screenshot_bytes = page.screenshot()
|
||||
image = Image.open(io.BytesIO(screenshot_bytes))
|
||||
```
|
||||
|
||||
## Element screenshot
|
||||
|
||||
Sometimes it is useful to take a screenshot of a single element.
|
||||
|
||||
```js
|
||||
const elementHandle = await page.$('.header');
|
||||
await elementHandle.screenshot({ path: 'screenshot.png' });
|
||||
```
|
||||
|
||||
```python async
|
||||
element_handle = await page.query_selector(".header")
|
||||
await element_handle.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
```python sync
|
||||
element_handle = page.query_selector(".header")
|
||||
element_handle.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [`method: Page.screenshot`]
|
||||
- [`method: ElementHandle.screenshot`]
|
||||
|
|
@ -5,132 +5,9 @@ title: "Verification"
|
|||
|
||||
<!-- TOC -->
|
||||
|
||||
## Videos
|
||||
|
||||
Playwright can record videos for all pages in a [browser context](./core-concepts.md#browser-contexts). Videos are saved
|
||||
upon context closure, so make sure to await [`method: BrowserContext.close`].
|
||||
|
||||
```js
|
||||
// With browser.newContext()
|
||||
const context = await browser.newContext({ recordVideo: { dir: 'videos/' } });
|
||||
// Make sure to await close, so that videos are saved.
|
||||
await context.close();
|
||||
|
||||
// With browser.newPage()
|
||||
const page = await browser.newPage({ recordVideo: { dir: 'videos/' } });
|
||||
// Make sure to await close, so that videos are saved.
|
||||
await page.close();
|
||||
|
||||
// [Optional] Specify video size; defaults to viewport size
|
||||
const context = await browser.newContext({
|
||||
recordVideo: {
|
||||
dir: 'videos/',
|
||||
size: { width: 800, height: 600 },
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
```python async
|
||||
# With browser.new_context()
|
||||
context = await browser.new_context(record_video_dir="videos/")
|
||||
# Make sure to await close, so that videos are saved.
|
||||
await context.close()
|
||||
|
||||
# With browser.new_page()
|
||||
page = await browser.new_page(record_video_dir="videos/")
|
||||
# Make sure to await close, so that videos are saved.
|
||||
await page.close()
|
||||
|
||||
# [Optional] specify video size; defaults to viewport size
|
||||
context = await browser.new_context(
|
||||
record_video_dir="videos/",
|
||||
record_video_size={"width": 800, "height": 600}
|
||||
)
|
||||
```
|
||||
|
||||
```python sync
|
||||
# With browser.new_context()
|
||||
context = browser.new_context(record_video_dir="videos/")
|
||||
# Make sure to close, so that videos are saved.
|
||||
context.close()
|
||||
|
||||
# With browser.new_page()
|
||||
page = browser.new_page(record_video_dir="videos/")
|
||||
# Make sure to close, so that videos are saved.
|
||||
page.close()
|
||||
|
||||
# [Optional] specify video size; defaults to viewport size
|
||||
context = browser.new_context(
|
||||
record_video_dir="videos/",
|
||||
record_video_size={"width": 800, "height": 600}
|
||||
)
|
||||
```
|
||||
|
||||
#### API reference
|
||||
- [BrowserContext]
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Browser.newPage`]
|
||||
- [`method: BrowserContext.close`]
|
||||
|
||||
## Screenshots
|
||||
|
||||
```js
|
||||
// Save to file
|
||||
await page.screenshot({ path: 'screenshot.png' });
|
||||
|
||||
// Capture full page
|
||||
await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
||||
|
||||
// Capture into buffer
|
||||
const buffer = await page.screenshot();
|
||||
console.log(buffer.toString('base64'));
|
||||
|
||||
// Capture given element
|
||||
const elementHandle = await page.$('.header');
|
||||
await elementHandle.screenshot({ path: 'screenshot.png' });
|
||||
```
|
||||
|
||||
```python async
|
||||
# Save to file
|
||||
await page.screenshot(path="screenshot.png")
|
||||
|
||||
# Capture full page
|
||||
await page.screenshot(path="screenshot.png", full_page=True)
|
||||
|
||||
# Capture into Image
|
||||
screenshot_bytes = await page.screenshot()
|
||||
image = Image.open(io.BytesIO(screenshot_bytes))
|
||||
|
||||
# Capture given element
|
||||
element_handle = await page.query_selector(".header")
|
||||
await element_handle.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
```python sync
|
||||
# Save to file
|
||||
page.screenshot(path="screenshot.png")
|
||||
|
||||
# Capture full page
|
||||
page.screenshot(path="screenshot.png", full_page=True)
|
||||
|
||||
# Capture into Image
|
||||
screenshot_bytes = page.screenshot()
|
||||
image = Image.open(io.BytesIO(screenshot_bytes))
|
||||
|
||||
# Capture given element
|
||||
element_handle = page.query_selector(".header")
|
||||
element_handle.screenshot(path="screenshot.png")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
- [`method: Page.screenshot`]
|
||||
- [`method: ElementHandle.screenshot`]
|
||||
|
||||
<br/>
|
||||
|
||||
## Console logs
|
||||
|
||||
Console messages logged in the page can be brought into the Node.js context.
|
||||
Console messages logged in the page can be brought into the Playwright context.
|
||||
|
||||
```js
|
||||
// Listen for all console logs
|
||||
|
|
@ -192,7 +69,7 @@ msg.args[0].json_value() # hello
|
|||
msg.args[1].json_value() # 42
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [ConsoleMessage]
|
||||
- [Page]
|
||||
- [`event: Page.console`]
|
||||
|
|
@ -229,7 +106,7 @@ page.on("pageerror", lambda exc: print(f"uncaught exception: {exc}"))
|
|||
page.goto("data:text/html,<script>throw new Error('test')</script>")
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [Page]
|
||||
- [`event: Page.pageerror`]
|
||||
|
||||
|
|
@ -282,7 +159,7 @@ with page.expect_popup() as popup_info:
|
|||
popup = popup_info.value
|
||||
```
|
||||
|
||||
#### API reference
|
||||
### API reference
|
||||
- [Page]
|
||||
- [`event: Page.requestfailed`]
|
||||
- [`event: Page.dialog`]
|
||||
|
|
|
|||
71
docs/src/videos.md
Normal file
71
docs/src/videos.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
id: videos
|
||||
title: "Videos"
|
||||
---
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
Playwright can record videos for all pages in a [browser context](./core-concepts.md#browser-contexts). Videos are saved
|
||||
upon context closure, so make sure to await [`method: BrowserContext.close`].
|
||||
|
||||
```js
|
||||
// With browser.newContext()
|
||||
const context = await browser.newContext({ recordVideo: { dir: 'videos/' } });
|
||||
// Make sure to await close, so that videos are saved.
|
||||
await context.close();
|
||||
|
||||
// With browser.newPage()
|
||||
const page = await browser.newPage({ recordVideo: { dir: 'videos/' } });
|
||||
// Make sure to await close, so that videos are saved.
|
||||
await page.close();
|
||||
|
||||
// [Optional] Specify video size; defaults to viewport size
|
||||
const context = await browser.newContext({
|
||||
recordVideo: {
|
||||
dir: 'videos/',
|
||||
size: { width: 800, height: 600 },
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
```python async
|
||||
# With browser.new_context()
|
||||
context = await browser.new_context(record_video_dir="videos/")
|
||||
# Make sure to await close, so that videos are saved.
|
||||
await context.close()
|
||||
|
||||
# With browser.new_page()
|
||||
page = await browser.new_page(record_video_dir="videos/")
|
||||
# Make sure to await close, so that videos are saved.
|
||||
await page.close()
|
||||
|
||||
# [Optional] specify video size; defaults to viewport size
|
||||
context = await browser.new_context(
|
||||
record_video_dir="videos/",
|
||||
record_video_size={"width": 800, "height": 600}
|
||||
)
|
||||
```
|
||||
|
||||
```python sync
|
||||
# With browser.new_context()
|
||||
context = browser.new_context(record_video_dir="videos/")
|
||||
# Make sure to close, so that videos are saved.
|
||||
context.close()
|
||||
|
||||
# With browser.new_page()
|
||||
page = browser.new_page(record_video_dir="videos/")
|
||||
# Make sure to close, so that videos are saved.
|
||||
page.close()
|
||||
|
||||
# [Optional] specify video size; defaults to viewport size
|
||||
context = browser.new_context(
|
||||
record_video_dir="videos/",
|
||||
record_video_size={"width": 800, "height": 600}
|
||||
)
|
||||
```
|
||||
|
||||
### API reference
|
||||
- [BrowserContext]
|
||||
- [`method: Browser.newContext`]
|
||||
- [`method: Browser.newPage`]
|
||||
- [`method: BrowserContext.close`]
|
||||
Loading…
Reference in a new issue