docs: extract handles, screenshots, videos docs (#5045)

This commit is contained in:
Pavel Feldman 2021-01-17 21:09:40 -08:00 committed by GitHub
parent 0a7b917ee3
commit 01fb3a6045
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 593 additions and 463 deletions

View file

@ -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"

View file

@ -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`]

View file

@ -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`]

View file

@ -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`]

View file

@ -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`]

View file

@ -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
View 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.$$`]

View file

@ -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`]

View file

@ -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`.

View file

@ -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`]

View file

@ -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`]

View file

@ -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
View 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`]

View file

@ -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
View 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`]