docs: add file chooser example, remove links to js samples (#5054)
This commit is contained in:
parent
449bcdcbf9
commit
f10f170946
|
|
@ -1,34 +0,0 @@
|
||||||
const { firefox } = require("playwright");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this script, we will upload a file to a web page.
|
|
||||||
*
|
|
||||||
* Steps summary
|
|
||||||
* 1. Open the sample file upload at https://cgi-lib.berkeley.edu/ex/fup.html
|
|
||||||
* 2. Automate file upload with setInputFiles
|
|
||||||
*/
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
// Launch a headless browser instance of chromium, webkit or firefox
|
|
||||||
const browser = await firefox.launch();
|
|
||||||
|
|
||||||
// Use the default browser context to create a new tab and navigate to URL
|
|
||||||
const page = await browser.newPage();
|
|
||||||
await page.goto('https://cgi-lib.berkeley.edu/ex/fup.html');
|
|
||||||
|
|
||||||
// Get an element handle to the file upload input
|
|
||||||
const handle = await page.$('input[type="file"]');
|
|
||||||
|
|
||||||
// Use the setInputFiles API to upload this file. File paths are relative to
|
|
||||||
// the current working directory. It is also possible to upload multiple files
|
|
||||||
// or use base64 encoded data, instead of a file. See API docs.
|
|
||||||
// https://github.com/microsoft/playwright/blob/master/docs/api.md#elementhandlesetinputfilesfiles
|
|
||||||
await handle.setInputFiles('upload.js');
|
|
||||||
|
|
||||||
// Click on the form submit element
|
|
||||||
await page.click('input[type="submit"]');
|
|
||||||
|
|
||||||
// Take a screenshot of the uploaded state and close the browser
|
|
||||||
await page.screenshot({ path: 'uploaded.png' });
|
|
||||||
await browser.close();
|
|
||||||
})();
|
|
||||||
|
|
@ -716,7 +716,7 @@ Returns storage state for this browser context, contains current cookies and loc
|
||||||
- `path` <[path]>
|
- `path` <[path]>
|
||||||
|
|
||||||
The file path to save the storage state to. If [`option: path`] is a relative path, then it is resolved relative to
|
The file path to save the storage state to. If [`option: path`] is a relative path, then it is resolved relative to
|
||||||
[current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, storage
|
current working directory. If no path is provided, storage
|
||||||
state is still returned, but won't be saved to the disk.
|
state is still returned, but won't be saved to the disk.
|
||||||
|
|
||||||
## async method: BrowserContext.unroute
|
## async method: BrowserContext.unroute
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,10 @@ const backgroundPage = await context.waitForEvent('backgroundpage');
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# FIXME
|
|
||||||
background_page = await context.wait_for_event("backgroundpage")
|
background_page = await context.wait_for_event("backgroundpage")
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
# FIXME
|
|
||||||
background_page = context.wait_for_event("backgroundpage")
|
background_page = context.wait_for_event("backgroundpage")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ asyncio.run(main())
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
# FIXME
|
|
||||||
from playwright.sync_api import sync_playwright
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
def handle_dialog(dialog):
|
def handle_dialog(dialog):
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,6 @@ expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# FIXME
|
|
||||||
feed_handle = await page.query_selector(".feed")
|
feed_handle = await page.query_selector(".feed")
|
||||||
assert await feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
|
assert await feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
|
||||||
```
|
```
|
||||||
|
|
@ -577,7 +576,6 @@ handle.select_option(value=["red", "green", "blue"])
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
# FIXME
|
|
||||||
# single selection matching the value
|
# single selection matching the value
|
||||||
handle.select_option("blue")
|
handle.select_option("blue")
|
||||||
# single selection matching both the value and the label
|
# single selection matching both the value and the label
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,25 @@
|
||||||
[FileChooser] objects are dispatched by the page in the [`event: Page.filechooser`] event.
|
[FileChooser] objects are dispatched by the page in the [`event: Page.filechooser`] event.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
page.on('filechooser', async (fileChooser) => {
|
const [fileChooser] = await Promise.all([
|
||||||
await fileChooser.setFiles('/tmp/myfile.pdf');
|
page.waitForEvent('filechooser'),
|
||||||
});
|
page.click('upload')
|
||||||
|
]);
|
||||||
|
await fileChooser.setFiles('myfile.pdf');
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
page.on("filechooser", lambda file_chooser: file_chooser.set_files("/tmp/myfile.pdf"))
|
async with page.expect_file_chooser() as fc_info:
|
||||||
|
await page.click("upload")
|
||||||
|
file_chooser = await fc_info.value
|
||||||
|
await file_chooser.set_files("myfile.pdf")
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
page.on("filechooser", lambda file_chooser: file_chooser.set_files("/tmp/myfile.pdf"))
|
with page.expect_file_chooser() as fc_info:
|
||||||
|
page.click("upload")
|
||||||
|
file_chooser = fc_info.value
|
||||||
|
file_chooser.set_files("myfile.pdf")
|
||||||
```
|
```
|
||||||
|
|
||||||
## method: FileChooser.element
|
## method: FileChooser.element
|
||||||
|
|
|
||||||
|
|
@ -505,7 +505,6 @@ aWindowHandle; // Handle for the window object.
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# FIXME
|
|
||||||
a_window_handle = await frame.evaluate_handle("Promise.resolve(window)")
|
a_window_handle = await frame.evaluate_handle("Promise.resolve(window)")
|
||||||
a_window_handle # handle for the window object.
|
a_window_handle # handle for the window object.
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -925,7 +925,6 @@ aWindowHandle; // Handle for the window object.
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
# FIXME
|
|
||||||
a_window_handle = await page.evaluate_handle("Promise.resolve(window)")
|
a_window_handle = await page.evaluate_handle("Promise.resolve(window)")
|
||||||
a_window_handle # handle for the window object.
|
a_window_handle # handle for the window object.
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -112,10 +112,26 @@ storage_state = json.loads(os.environ["STORAGE"])
|
||||||
context = browser.new_context(storage_state=storage_state)
|
context = browser.new_context(storage_state=storage_state)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Session storage
|
Logging in via the UI and then reusing authentication state can be combined to
|
||||||
|
implement **login once and run multiple scenarios**. The lifecycle looks like:
|
||||||
|
|
||||||
Session storage ([`window.sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage))
|
1. Run tests (for example, with `npm run test`).
|
||||||
is specific to a particular domain. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage.
|
1. Login via UI and retrieve authentication state.
|
||||||
|
* In Jest, this can be executed in [`globalSetup`](https://jestjs.io/docs/en/configuration#globalsetup-string).
|
||||||
|
1. In each test, load authentication state in `beforeEach` or `beforeAll` step.
|
||||||
|
|
||||||
|
This approach will also **work in CI environments**, since it does not rely on any external state.
|
||||||
|
|
||||||
|
### API reference
|
||||||
|
- [`method: BrowserContext.storageState`]
|
||||||
|
- [`method: Browser.newContext`]
|
||||||
|
|
||||||
|
## Session storage
|
||||||
|
|
||||||
|
Rarely, [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) is used for storing information
|
||||||
|
associated with the logged-in state. Session storage is specific to a particular domain and is not persisted across page loads.
|
||||||
|
Playwright does not provide API to persist session storage, but the following snippet can be used to
|
||||||
|
save/load session storage.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Get session storage and store as env variable
|
// Get session storage and store as env variable
|
||||||
|
|
@ -170,24 +186,6 @@ context.add_init_script(storage => {
|
||||||
}, session_storage)
|
}, session_storage)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lifecycle
|
|
||||||
|
|
||||||
Logging in via the UI and then reusing authentication state can be combined to
|
|
||||||
implement **login once and run multiple scenarios**. The lifecycle looks like:
|
|
||||||
|
|
||||||
1. Run tests (for example, with `npm run test`).
|
|
||||||
1. Login via UI and retrieve authentication state.
|
|
||||||
* In Jest, this can be executed in [`globalSetup`](https://jestjs.io/docs/en/configuration#globalsetup-string).
|
|
||||||
1. In each test, load authentication state in `beforeEach` or `beforeAll` step.
|
|
||||||
|
|
||||||
This approach will also **work in CI environments**, since it does not rely
|
|
||||||
on any external state.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
[This example script](https://github.com/microsoft/playwright/blob/master/docs/examples/authentication.js) logs in
|
|
||||||
on GitHub.com with Chromium, and then reuses the logged in storage state in WebKit.
|
|
||||||
|
|
||||||
### API reference
|
### API reference
|
||||||
- [`method: BrowserContext.storageState`]
|
- [`method: BrowserContext.storageState`]
|
||||||
- [`method: Browser.newContext`]
|
- [`method: Browser.newContext`]
|
||||||
|
|
@ -195,6 +193,7 @@ on GitHub.com with Chromium, and then reuses the logged in storage state in WebK
|
||||||
- [`method: BrowserContext.addInitScript`]
|
- [`method: BrowserContext.addInitScript`]
|
||||||
|
|
||||||
## Multi-factor authentication
|
## Multi-factor authentication
|
||||||
|
|
||||||
Accounts with multi-factor authentication (MFA) cannot be fully automated, and need
|
Accounts with multi-factor authentication (MFA) cannot be fully automated, and need
|
||||||
manual intervention. Persistent authentication can be used to partially automate
|
manual intervention. Persistent authentication can be used to partially automate
|
||||||
MFA scenarios.
|
MFA scenarios.
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,8 @@ Note that you still need to specify the capital `A` in `Shift-A` to produce the
|
||||||
|
|
||||||
## Upload files
|
## Upload files
|
||||||
|
|
||||||
|
You can select input files for upload using the [`method: Page.setInputFiles`] method. It expects first argument to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) with the type `"file"`. Multiple files can be passed in the array. If some of the file paths are relative, they are resolved relative to the current working directory. Empty array clears the selected files.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Select one file
|
// Select one file
|
||||||
await page.setInputFiles('input#upload', 'myfile.pdf');
|
await page.setInputFiles('input#upload', 'myfile.pdf');
|
||||||
|
|
@ -485,14 +487,33 @@ page.set_input_files(
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
You can select input files for upload using the [`method: Page.setInputFiles`] method. It expects first argument to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) with the type `"file"`. Multiple files can be passed in the array. If some of the file paths are relative, they are resolved relative to the [current working directory](https://nodejs.org/api/process.html#process_process_cwd). Empty array clears the selected files.
|
If you don't have input element in hand (it is created dynamically), you can handle the [`event: Page.filechooser`] event
|
||||||
|
or use a corresponding waiting method upon your action:
|
||||||
|
|
||||||
#### Example
|
```js
|
||||||
|
const [fileChooser] = await Promise.all([
|
||||||
|
page.waitForEvent('filechooser'),
|
||||||
|
page.click('upload')
|
||||||
|
]);
|
||||||
|
await fileChooser.setFiles('myfile.pdf');
|
||||||
|
```
|
||||||
|
|
||||||
[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.
|
```python async
|
||||||
|
async with page.expect_file_chooser() as fc_info:
|
||||||
|
await page.click("upload")
|
||||||
|
file_chooser = await fc_info.value
|
||||||
|
await file_chooser.set_files("myfile.pdf")
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
with page.expect_file_chooser() as fc_info:
|
||||||
|
page.click("upload")
|
||||||
|
file_chooser = fc_info.value
|
||||||
|
file_chooser.set_files("myfile.pdf")
|
||||||
|
```
|
||||||
|
|
||||||
### API reference
|
### API reference
|
||||||
|
- [FileChooser]
|
||||||
- [`method: Page.setInputFiles`]
|
- [`method: Page.setInputFiles`]
|
||||||
- [`method: Frame.setInputFiles`]
|
- [`method: Frame.setInputFiles`]
|
||||||
- [`method: ElementHandle.setInputFiles`]
|
- [`method: ElementHandle.setInputFiles`]
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,6 @@ await page.screenshot()
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
# FIXME
|
|
||||||
page.goto("http://example.com")
|
page.goto("http://example.com")
|
||||||
page.wait_for_function("() => window.amILoadedYet()")
|
page.wait_for_function("() => window.amILoadedYet()")
|
||||||
# Ready to take a screenshot, according to the page itself.
|
# Ready to take a screenshot, according to the page itself.
|
||||||
|
|
|
||||||
13
types/types.d.ts
vendored
13
types/types.d.ts
vendored
|
|
@ -5070,9 +5070,8 @@ export interface BrowserContext {
|
||||||
*/
|
*/
|
||||||
storageState(options?: {
|
storageState(options?: {
|
||||||
/**
|
/**
|
||||||
* The file path to save the storage state to. If `path` is a relative path, then it is resolved relative to
|
* The file path to save the storage state to. If `path` is a relative path, then it is resolved relative to current
|
||||||
* [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, storage
|
* working directory. If no path is provided, storage state is still returned, but won't be saved to the disk.
|
||||||
* state is still returned, but won't be saved to the disk.
|
|
||||||
*/
|
*/
|
||||||
path?: string;
|
path?: string;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
|
|
@ -8082,9 +8081,11 @@ export interface Download {
|
||||||
* [page.on('filechooser')](https://github.com/microsoft/playwright/blob/master/docs/api.md#pageonfilechooser) event.
|
* [page.on('filechooser')](https://github.com/microsoft/playwright/blob/master/docs/api.md#pageonfilechooser) event.
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* page.on('filechooser', async (fileChooser) => {
|
* const [fileChooser] = await Promise.all([
|
||||||
* await fileChooser.setFiles('/tmp/myfile.pdf');
|
* page.waitForEvent('filechooser'),
|
||||||
* });
|
* page.click('upload')
|
||||||
|
* ]);
|
||||||
|
* await fileChooser.setFiles('myfile.pdf');
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue