chore: refactor the file chooser api (#107)
This commit is contained in:
parent
cf9c4d153a
commit
56b4f009ac
58
docs/api.md
58
docs/api.md
|
|
@ -71,6 +71,7 @@
|
|||
* [event: 'console'](#event-console)
|
||||
* [event: 'dialog'](#event-dialog)
|
||||
* [event: 'domcontentloaded'](#event-domcontentloaded)
|
||||
* [event: 'filechooser'](#event-filechooser)
|
||||
* [event: 'frameattached'](#event-frameattached)
|
||||
* [event: 'framedetached'](#event-framedetached)
|
||||
* [event: 'framenavigated'](#event-framenavigated)
|
||||
|
|
@ -176,10 +177,6 @@
|
|||
* [chromium.startTracing(page, [options])](#chromiumstarttracingpage-options)
|
||||
* [chromium.stopTracing()](#chromiumstoptracing)
|
||||
* [chromium.wsEndpoint()](#chromiumwsendpoint)
|
||||
- [class: FileChooser](#class-filechooser)
|
||||
* [fileChooser.accept(filePaths)](#filechooseracceptfilepaths)
|
||||
* [fileChooser.cancel()](#filechoosercancel)
|
||||
* [fileChooser.isMultiple()](#filechooserismultiple)
|
||||
- [class: Dialog](#class-dialog)
|
||||
* [dialog.accept([promptText])](#dialogacceptprompttext)
|
||||
* [dialog.defaultValue()](#dialogdefaultvalue)
|
||||
|
|
@ -972,6 +969,19 @@ Emitted when a JavaScript dialog appears, such as `alert`, `prompt`, `confirm` o
|
|||
|
||||
Emitted when the JavaScript [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event is dispatched.
|
||||
|
||||
#### event: 'filechooser'
|
||||
- <[Object]>
|
||||
- `element` <[ElementHandle]> handle to the input element that was clicked
|
||||
- `multiple` <[boolean]> Whether file chooser allow for [multiple](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple) file selection.
|
||||
|
||||
Emitted when a file chooser is supposed to appear, such as after clicking the `<input type=file>`. Playwright can respond to it via setting the input files using [`elementHandle.setInputFiles`](#elementhandlesetinputfilesfiles).
|
||||
|
||||
```js
|
||||
page.on('filechooser', async ({element, multiple}) => {
|
||||
await element.setInputFiles('/tmp/myfile.pdf');
|
||||
});
|
||||
```
|
||||
|
||||
#### event: 'frameattached'
|
||||
- <[Frame]>
|
||||
|
||||
|
|
@ -1795,7 +1805,9 @@ Shortcut for [page.mainFrame().waitFor(selectorOrFunctionOrTimeout[, options[, .
|
|||
#### page.waitForFileChooser([options])
|
||||
- `options` <[Object]> Optional waiting parameters
|
||||
- `timeout` <[number]> Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) method.
|
||||
- returns: <[Promise]<[FileChooser]>> A promise that resolves after a page requests a file picker.
|
||||
- returns: <[Promise]<[Object]>>
|
||||
- `element` <[ElementHandle]> handle to the input element that was clicked
|
||||
- `multiple` <[boolean]> Whether file chooser allow for [multiple](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple) file selection.
|
||||
|
||||
> **NOTE** In non-headless Chromium, this method results in the native file picker dialog **not showing up** for the user.
|
||||
|
||||
|
|
@ -1804,16 +1816,15 @@ The following example clicks a button that issues a file chooser, and then
|
|||
responds with `/tmp/myfile.pdf` as if a user has selected this file.
|
||||
|
||||
```js
|
||||
const [fileChooser] = await Promise.all([
|
||||
const [{element, multiple}] = await Promise.all([
|
||||
page.waitForFileChooser(),
|
||||
page.click('#upload-file-button'), // some button that triggers file selection
|
||||
]);
|
||||
await fileChooser.accept(['/tmp/myfile.pdf']);
|
||||
await element.setInputFiles('/tmp/myfile.pdf');
|
||||
```
|
||||
|
||||
> **NOTE** This must be called *before* the file chooser is launched. It will not return a currently active file chooser.
|
||||
|
||||
|
||||
#### page.waitForFunction(pageFunction[, options[, ...args]])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in browser context
|
||||
- `options` <[Object]> Optional waiting parameters
|
||||
|
|
@ -2396,37 +2407,6 @@ Browser websocket endpoint which can be used as an argument to
|
|||
|
||||
You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`. Learn more about the [devtools protocol](https://chromedevtools.github.io/devtools-protocol) and the [browser endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target).
|
||||
|
||||
### class: FileChooser
|
||||
|
||||
[FileChooser] objects are returned via the ['page.waitForFileChooser'](#pagewaitforfilechooseroptions) method.
|
||||
|
||||
File choosers let you react to the page requesting for a file.
|
||||
|
||||
An example of using [FileChooser]:
|
||||
|
||||
```js
|
||||
const [fileChooser] = await Promise.all([
|
||||
page.waitForFileChooser(),
|
||||
page.click('#upload-file-button'), // some button that triggers file selection
|
||||
]);
|
||||
await fileChooser.accept(['/tmp/myfile.pdf']);
|
||||
```
|
||||
|
||||
> **NOTE** In browsers, only one file chooser can be opened at a time.
|
||||
> All file choosers must be accepted or canceled. Not doing so will prevent subsequent file choosers from appearing.
|
||||
|
||||
#### fileChooser.accept(filePaths)
|
||||
- `filePaths` <[Array]<[string]>> Accept the file chooser request with given paths. If some of the `filePaths` are relative paths, then they are resolved relative to the [current working directory](https://nodejs.org/api/process.html#process_process_cwd).
|
||||
- returns: <[Promise]>
|
||||
|
||||
#### fileChooser.cancel()
|
||||
- returns: <[Promise]>
|
||||
|
||||
Closes the file chooser without selecting any files.
|
||||
|
||||
#### fileChooser.isMultiple()
|
||||
- returns: <[boolean]> Whether file chooser allow for [multiple](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple) file selection.
|
||||
|
||||
### class: Dialog
|
||||
|
||||
[Dialog] objects are dispatched by page via the ['dialog'](#event-dialog) event.
|
||||
|
|
|
|||
|
|
@ -161,9 +161,10 @@ export class Page extends EventEmitter {
|
|||
const interceptors = Array.from(this._fileChooserInterceptors);
|
||||
this._fileChooserInterceptors.clear();
|
||||
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
||||
const fileChooser = new FileChooser(handle, multiple);
|
||||
const fileChooser = { element: handle, multiple };
|
||||
for (const interceptor of interceptors)
|
||||
interceptor.call(null, fileChooser);
|
||||
this.emit(Events.Page.FileChooser, fileChooser);
|
||||
}
|
||||
|
||||
async waitForFileChooser(options: { timeout?: number; } = {}): Promise<FileChooser> {
|
||||
|
|
@ -729,28 +730,7 @@ export class ConsoleMessage {
|
|||
}
|
||||
}
|
||||
|
||||
export class FileChooser {
|
||||
private _element: ElementHandle;
|
||||
private _multiple: boolean;
|
||||
private _handled = false;
|
||||
|
||||
constructor(element: ElementHandle, multiple: boolean) {
|
||||
this._element = element;
|
||||
this._multiple = multiple;
|
||||
}
|
||||
|
||||
isMultiple(): boolean {
|
||||
return this._multiple;
|
||||
}
|
||||
|
||||
async accept(filePaths: string[]): Promise<any> {
|
||||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
await this._element.setInputFiles(...filePaths);
|
||||
}
|
||||
|
||||
async cancel(): Promise<any> {
|
||||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
}
|
||||
}
|
||||
type FileChooser = {
|
||||
element: ElementHandle,
|
||||
multiple: boolean
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@ export { Frame } from '../frames';
|
|||
export { Keyboard, Mouse } from '../input';
|
||||
export { ElementHandle } from './JSHandle';
|
||||
export { Request, Response } from '../network';
|
||||
export { ConsoleMessage, FileChooser, Page } from './Page';
|
||||
export { ConsoleMessage, Page } from './Page';
|
||||
export { Playwright } from './Playwright';
|
||||
export { Target } from './Target';
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const Events = {
|
|||
Close: 'close',
|
||||
Console: 'console',
|
||||
Dialog: 'dialog',
|
||||
FileChooser: 'filechooser',
|
||||
DOMContentLoaded: 'domcontentloaded',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
|
|
|
|||
|
|
@ -552,9 +552,10 @@ export class Page extends EventEmitter {
|
|||
const interceptors = Array.from(this._fileChooserInterceptors);
|
||||
this._fileChooserInterceptors.clear();
|
||||
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
||||
const fileChooser = new FileChooser(handle, multiple);
|
||||
const fileChooser = { element: handle, multiple };
|
||||
for (const interceptor of interceptors)
|
||||
interceptor.call(null, fileChooser);
|
||||
this.emit(Events.Page.FileChooser, fileChooser);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -619,28 +620,7 @@ export type Viewport = {
|
|||
hasTouch?: boolean;
|
||||
}
|
||||
|
||||
export class FileChooser {
|
||||
private _element: ElementHandle;
|
||||
private _multiple: boolean;
|
||||
private _handled = false;
|
||||
|
||||
constructor(element: ElementHandle, multiple: boolean) {
|
||||
this._element = element;
|
||||
this._multiple = multiple;
|
||||
}
|
||||
|
||||
isMultiple(): boolean {
|
||||
return this._multiple;
|
||||
}
|
||||
|
||||
async accept(filePaths: string[]): Promise<any> {
|
||||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
await this._element.setInputFiles(...filePaths);
|
||||
}
|
||||
|
||||
async cancel(): Promise<any> {
|
||||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
}
|
||||
}
|
||||
type FileChooser = {
|
||||
element: ElementHandle,
|
||||
multiple: boolean
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ export { Permissions } from './features/permissions';
|
|||
export { Frame } from './FrameManager';
|
||||
export { ElementHandle } from './JSHandle';
|
||||
export { Request, Response } from '../network';
|
||||
export { ConsoleMessage, FileChooser, Page } from './Page';
|
||||
export { ConsoleMessage, Page } from './Page';
|
||||
export { Playwright } from './Playwright';
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const Events = {
|
|||
Close: 'close',
|
||||
Console: 'console',
|
||||
Dialog: 'dialog',
|
||||
FileChooser: 'filechooser',
|
||||
DOMContentLoaded: 'domcontentloaded',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
|
|
|
|||
|
|
@ -462,9 +462,10 @@ export class Page extends EventEmitter {
|
|||
const interceptors = Array.from(this._fileChooserInterceptors);
|
||||
this._fileChooserInterceptors.clear();
|
||||
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
||||
const fileChooser = new FileChooser(handle, multiple);
|
||||
const fileChooser = { element: handle, multiple };
|
||||
for (const interceptor of interceptors)
|
||||
interceptor.call(null, fileChooser);
|
||||
this.emit(Events.Page.FileChooser, fileChooser);
|
||||
}
|
||||
|
||||
get mouse(): input.Mouse {
|
||||
|
|
@ -586,28 +587,7 @@ export class ConsoleMessage {
|
|||
}
|
||||
}
|
||||
|
||||
export class FileChooser {
|
||||
private _element: ElementHandle;
|
||||
private _multiple: boolean;
|
||||
private _handled = false;
|
||||
|
||||
constructor(element: ElementHandle, multiple: boolean) {
|
||||
this._element = element;
|
||||
this._multiple = multiple;
|
||||
}
|
||||
|
||||
isMultiple(): boolean {
|
||||
return this._multiple;
|
||||
}
|
||||
|
||||
async accept(filePaths: string[]): Promise<any> {
|
||||
assert(!this._handled, 'Cannot accept FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
await this._element.setInputFiles(...filePaths);
|
||||
}
|
||||
|
||||
async cancel(): Promise<any> {
|
||||
assert(!this._handled, 'Cannot cancel FileChooser which is already handled!');
|
||||
this._handled = true;
|
||||
}
|
||||
}
|
||||
type FileChooser = {
|
||||
element: ElementHandle,
|
||||
multiple: boolean
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export const Events = {
|
|||
Close: 'close',
|
||||
Console: 'console',
|
||||
Dialog: 'dialog',
|
||||
FileChooser: 'filechooser',
|
||||
DOMContentLoaded: 'domcontentloaded',
|
||||
Request: 'request',
|
||||
Response: 'response',
|
||||
|
|
|
|||
Loading…
Reference in a new issue