docs: add dialogs and downloads docs (#5042)
This commit is contained in:
parent
2db02c9a05
commit
1fc02e8823
|
|
@ -32,7 +32,20 @@ Some actions like [`method: Page.click`] support `force` option that disables no
|
||||||
| textContent | Yes | - | - | - | - | - |
|
| textContent | Yes | - | - | - | - | - |
|
||||||
| type | Yes | - | - | - | - | - |
|
| type | Yes | - | - | - | - | - |
|
||||||
|
|
||||||
<br/>
|
You can check the actionability state of the element using one of the following methods:
|
||||||
|
|
||||||
|
- [`method: ElementHandle.isChecked`]
|
||||||
|
- [`method: ElementHandle.isDisabled`]
|
||||||
|
- [`method: ElementHandle.isEditable`]
|
||||||
|
- [`method: ElementHandle.isEnabled`]
|
||||||
|
- [`method: ElementHandle.isHidden`]
|
||||||
|
- [`method: ElementHandle.isVisible`]
|
||||||
|
- [`method: Page.isChecked`]
|
||||||
|
- [`method: Page.isDisabled`]
|
||||||
|
- [`method: Page.isEditable`]
|
||||||
|
- [`method: Page.isEnabled`]
|
||||||
|
- [`method: Page.isHidden`]
|
||||||
|
- [`method: Page.isVisible`]
|
||||||
|
|
||||||
### Visible
|
### Visible
|
||||||
|
|
||||||
|
|
|
||||||
94
docs/src/dialogs.md
Normal file
94
docs/src/dialogs.md
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
---
|
||||||
|
id: dialogs
|
||||||
|
title: "Dialogs"
|
||||||
|
---
|
||||||
|
|
||||||
|
Playwright can interact with the web page dialogs such as [`alert`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert), [`confirm`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm), [`prompt`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) as well as [`beforeunload`](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) confirmation.
|
||||||
|
|
||||||
|
<!-- TOC -->
|
||||||
|
|
||||||
|
## alert(), confirm(), prompt() dialogs
|
||||||
|
|
||||||
|
You can register a dialog handler before the action that triggers the dialog to accept or decline it.
|
||||||
|
|
||||||
|
```js
|
||||||
|
page.on('dialog', dialog => dialog.accept());
|
||||||
|
await page.click('button');
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
|
await page.click("button")
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
|
page.click("button")
|
||||||
|
```
|
||||||
|
|
||||||
|
:::note
|
||||||
|
If your action, be it [`method: Page.click`], [`method: Page.evaluate`] or any other, results in a dialog, the action will stall until the dialog is handled. That's because dialogs in Web are modal and block further page execution until they are handled.
|
||||||
|
:::
|
||||||
|
|
||||||
|
As a result, following snippet will never resolve:
|
||||||
|
|
||||||
|
:::warn
|
||||||
|
WRONG!
|
||||||
|
:::
|
||||||
|
|
||||||
|
```js
|
||||||
|
await page.click('button'); // Will hang here
|
||||||
|
page.on('dialog', dialog => dialog.accept())
|
||||||
|
```
|
||||||
|
|
||||||
|
:::warn
|
||||||
|
WRONG!
|
||||||
|
:::
|
||||||
|
|
||||||
|
```python async
|
||||||
|
await page.click("button") # Will hang here
|
||||||
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
page.click("button") # Will hang here
|
||||||
|
page.on("dialog", lambda dialog: dialog.accept())
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API reference
|
||||||
|
|
||||||
|
- [`Dialog`]
|
||||||
|
- [`method: Dialog.accept`]
|
||||||
|
- [`method: Dialog.dismiss`]
|
||||||
|
|
||||||
|
## beforeunload dialog
|
||||||
|
|
||||||
|
When [`method: Page.close`] is invoked with the truthy [`option: runBeforeUnload`] value, it page runs its unload handlers. This is the only case when [`method: Page.close`] does not wait for the page to actually close, because it might be that the page stays open in the end of the operation.
|
||||||
|
|
||||||
|
You can register a dialog handler to handle the beforeunload dialog yourself:
|
||||||
|
|
||||||
|
```js
|
||||||
|
page.on('dialog', async dialog => {
|
||||||
|
assert(dialog.type() === 'beforeunload');
|
||||||
|
await dialog.dismiss();
|
||||||
|
});
|
||||||
|
await page.close({runBeforeUnload: true});
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
async def handle_dialog(dialog):
|
||||||
|
assert dialog.type == 'beforeunload'
|
||||||
|
await dialog.dismiss()
|
||||||
|
|
||||||
|
page.on('dialog', lambda: handle_dialog)
|
||||||
|
await page.close(run_before_unload=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
def handle_dialog(dialog):
|
||||||
|
assert dialog.type == 'beforeunload'
|
||||||
|
dialog.dismiss()
|
||||||
|
|
||||||
|
page.on('dialog', lambda: handle_dialog)
|
||||||
|
page.close(run_before_unload=True)
|
||||||
|
```
|
||||||
77
docs/src/downloads.md
Normal file
77
docs/src/downloads.md
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
---
|
||||||
|
id: downloads
|
||||||
|
title: "Downloads"
|
||||||
|
---
|
||||||
|
|
||||||
|
:::note
|
||||||
|
For uploading files, see the [uploading files](./input.md#upload-files) section.
|
||||||
|
:::
|
||||||
|
|
||||||
|
For every attachment downloaded by the page, [`event: Page.download`] event is emitted. If you create a browser context
|
||||||
|
with the [`option: acceptDownloads`] set, all these attachments are going to be downloaded into a temporary folder. You
|
||||||
|
can obtain the download url, file system path and payload stream using the [Download] object from the event.
|
||||||
|
|
||||||
|
You can specify where to persist downloaded files using the [`option: downloadsPath`] option in [`method: BrowserType.launch`].
|
||||||
|
|
||||||
|
:::note
|
||||||
|
Unless [`option: downloadsPath`] is set, downloaded files are deleted when the browser context that produced them is closed.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Here is the simplest way to handle the file download:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const [ download ] = await Promise.all([
|
||||||
|
// Start waiting for the download
|
||||||
|
page.waitForEvent('download'),
|
||||||
|
// Perform the action that initiates download
|
||||||
|
page.click('button#delayed-download')
|
||||||
|
]);
|
||||||
|
// Wait for the download process to complete
|
||||||
|
const path = await download.path();
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
# Start waiting for the download
|
||||||
|
async with page.expect_download() as download_info:
|
||||||
|
# Perform the action that initiates download
|
||||||
|
await page.click("button#delayed-download")
|
||||||
|
download = await download_info.value
|
||||||
|
# Wait for the download process to complete
|
||||||
|
path = await download.path()
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
# Start waiting for the download
|
||||||
|
with page.expect_download() as download_info:
|
||||||
|
# Perform the action that initiates download
|
||||||
|
page.click("button#delayed-download")
|
||||||
|
download = download_info.value
|
||||||
|
# Wait for the download process to complete
|
||||||
|
path = download.path()
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Variations
|
||||||
|
|
||||||
|
If you have no idea what initiates the download, you can still handle the event:
|
||||||
|
|
||||||
|
```js
|
||||||
|
page.on('download', download => download.path().then(console.log));
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
async def handle_download(download):
|
||||||
|
print(await download.path())
|
||||||
|
page.on("download", handle_download)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
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
|
||||||
|
- [Download]
|
||||||
|
- [`event: Page.download`]
|
||||||
|
- [`method: Page.waitForEvent`]
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
id: emulation
|
id: emulation
|
||||||
title: "Device and environment emulation"
|
title: "Emulation"
|
||||||
---
|
---
|
||||||
|
|
||||||
Playwright allows overriding various parameters of the device where the browser is running:
|
Playwright allows overriding various parameters of the device where the browser is running:
|
||||||
|
|
|
||||||
|
|
@ -43,68 +43,6 @@ page.goto("https://example.com")
|
||||||
#### API reference
|
#### API reference
|
||||||
- [`method: Browser.newContext`]
|
- [`method: Browser.newContext`]
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## Handle file downloads
|
|
||||||
|
|
||||||
```js
|
|
||||||
const [ download ] = await Promise.all([
|
|
||||||
page.waitForEvent('download'), // <-- start waiting for the download
|
|
||||||
page.click('button#delayed-download') // <-- perform the action that directly or indirectly initiates it
|
|
||||||
]);
|
|
||||||
const path = await download.path();
|
|
||||||
```
|
|
||||||
|
|
||||||
```python async
|
|
||||||
# Start waiting for the download
|
|
||||||
async with page.expect_download() as download_info:
|
|
||||||
# Perform the action that directly or indirectly initiates it
|
|
||||||
await page.click("button#delayed-download")
|
|
||||||
download = await download_info.value
|
|
||||||
path = await download.path()
|
|
||||||
```
|
|
||||||
|
|
||||||
```python sync
|
|
||||||
# Start waiting for the download
|
|
||||||
with page.expect_download() as download_info:
|
|
||||||
# Perform the action that directly or indirectly initiates it
|
|
||||||
page.click("button#delayed-download")
|
|
||||||
download = download_info.value
|
|
||||||
path = download.path()
|
|
||||||
```
|
|
||||||
|
|
||||||
For every attachment downloaded by the page, [`event: Page.download`] event is emitted. If you create a browser context
|
|
||||||
with the [`option: acceptDownloads`] set, all these attachments are going to be downloaded into a temporary folder. You
|
|
||||||
can obtain the download url, file system path and payload stream using the [Download] object from the event.
|
|
||||||
|
|
||||||
#### Variations
|
|
||||||
|
|
||||||
If you have no idea what initiates the download, you can still handle the event:
|
|
||||||
|
|
||||||
```js
|
|
||||||
page.on('download', download => download.path().then(console.log));
|
|
||||||
```
|
|
||||||
|
|
||||||
```python async
|
|
||||||
async def handle_download(download):
|
|
||||||
print(await download.path())
|
|
||||||
page.on("download", handle_download)
|
|
||||||
```
|
|
||||||
|
|
||||||
```python sync
|
|
||||||
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
|
|
||||||
- [Download]
|
|
||||||
- [`event: Page.download`]
|
|
||||||
- [`method: Page.waitForEvent`]
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## Network events
|
## Network events
|
||||||
|
|
||||||
You can monitor all the requests and responses:
|
You can monitor all the requests and responses:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue