Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add dialogs and downloads docs (#5042)
- Loading branch information
1 parent
2db02c9
commit 1fc02e8
Showing
5 changed files
with
186 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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`] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters