mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 21:53:35 +03:00
feature(filechooser): move waitForFileChooser to common waitForEvent (#281)
This commit is contained in:
parent
533d058ea6
commit
0f8333ba89
@ -125,7 +125,7 @@ class Helper {
|
|||||||
});
|
});
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
eventTimeout = setTimeout(() => {
|
eventTimeout = setTimeout(() => {
|
||||||
rejectCallback(new TimeoutError('Timeout exceeded while waiting for event'));
|
rejectCallback(new TimeoutError(`Timeout exceeded while waiting for ${String(eventName)}`));
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}
|
}
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
|
22
src/page.ts
22
src/page.ts
@ -98,7 +98,6 @@ export class Page extends EventEmitter {
|
|||||||
readonly _state: PageState;
|
readonly _state: PageState;
|
||||||
private _pageBindings = new Map<string, Function>();
|
private _pageBindings = new Map<string, Function>();
|
||||||
readonly _screenshotter: Screenshotter;
|
readonly _screenshotter: Screenshotter;
|
||||||
private _fileChooserInterceptors = new Set<(chooser: FileChooser) => void>();
|
|
||||||
readonly _frameManager: frames.FrameManager;
|
readonly _frameManager: frames.FrameManager;
|
||||||
|
|
||||||
constructor(delegate: PageDelegate, browserContext: BrowserContext) {
|
constructor(delegate: PageDelegate, browserContext: BrowserContext) {
|
||||||
@ -138,30 +137,15 @@ export class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
async _onFileChooserOpened(handle: dom.ElementHandle) {
|
||||||
if (!this._fileChooserInterceptors.size) {
|
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
||||||
|
if (!this.listenerCount(Events.Page.FileChooser)) {
|
||||||
await handle.dispose();
|
await handle.dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const interceptors = Array.from(this._fileChooserInterceptors);
|
const fileChooser: FileChooser = { element: handle, multiple };
|
||||||
this._fileChooserInterceptors.clear();
|
|
||||||
const multiple = await handle.evaluate((element: HTMLInputElement) => !!element.multiple);
|
|
||||||
const fileChooser = { element: handle, multiple };
|
|
||||||
for (const interceptor of interceptors)
|
|
||||||
interceptor.call(null, fileChooser);
|
|
||||||
this.emit(Events.Page.FileChooser, fileChooser);
|
this.emit(Events.Page.FileChooser, fileChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForFileChooser(options: types.TimeoutOptions = {}): Promise<FileChooser> {
|
|
||||||
const { timeout = this._timeoutSettings.timeout() } = options;
|
|
||||||
let callback;
|
|
||||||
const promise = new Promise<FileChooser>(x => callback = x);
|
|
||||||
this._fileChooserInterceptors.add(callback);
|
|
||||||
return helper.waitWithTimeout<FileChooser>(promise, 'waiting for file chooser', timeout).catch(e => {
|
|
||||||
this._fileChooserInterceptors.delete(callback);
|
|
||||||
throw e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
browser(): BrowserInterface {
|
browser(): BrowserInterface {
|
||||||
return this._browserContext.browser();
|
return this._browserContext.browser();
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import { TargetSession } from './Connection';
|
import { TargetSession } from './Connection';
|
||||||
import { Page } from '../page';
|
import { Page } from '../page';
|
||||||
import { assert, helper, RegisteredListener } from '../helper';
|
import { helper, RegisteredListener } from '../helper';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import * as network from '../network';
|
import * as network from '../network';
|
||||||
import * as frames from '../frames';
|
import * as frames from '../frames';
|
||||||
|
@ -40,17 +40,25 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.waitForFileChooser', function() {
|
describe('Page.waitForFileChooser', function() {
|
||||||
|
it('should emit event', async({page, server}) => {
|
||||||
|
await page.setContent(`<input type=file>`);
|
||||||
|
const [chooser] = await Promise.all([
|
||||||
|
new Promise(f => page.once('filechooser', f)),
|
||||||
|
page.click('input'),
|
||||||
|
]);
|
||||||
|
expect(chooser).toBeTruthy();
|
||||||
|
});
|
||||||
it('should work when file input is attached to DOM', async({page, server}) => {
|
it('should work when file input is attached to DOM', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
const [chooser] = await Promise.all([
|
const [chooser] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
expect(chooser).toBeTruthy();
|
expect(chooser).toBeTruthy();
|
||||||
});
|
});
|
||||||
it('should work when file input is not attached to DOM', async({page, server}) => {
|
it('should work when file input is not attached to DOM', async({page, server}) => {
|
||||||
const [chooser] = await Promise.all([
|
const [chooser] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.evaluate(() => {
|
page.evaluate(() => {
|
||||||
const el = document.createElement('input');
|
const el = document.createElement('input');
|
||||||
el.type = 'file';
|
el.type = 'file';
|
||||||
@ -61,24 +69,24 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
});
|
});
|
||||||
it('should respect timeout', async({page, server}) => {
|
it('should respect timeout', async({page, server}) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
await page.waitForFileChooser({timeout: 1}).catch(e => error = e);
|
await page.waitForEvent('filechooser', {timeout: 1}).catch(e => error = e);
|
||||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
||||||
});
|
});
|
||||||
it('should respect default timeout when there is no custom timeout', async({page, server}) => {
|
it('should respect default timeout when there is no custom timeout', async({page, server}) => {
|
||||||
page.setDefaultTimeout(1);
|
page.setDefaultTimeout(1);
|
||||||
let error = null;
|
let error = null;
|
||||||
await page.waitForFileChooser().catch(e => error = e);
|
await page.waitForEvent('filechooser').catch(e => error = e);
|
||||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
||||||
});
|
});
|
||||||
it('should prioritize exact timeout over default timeout', async({page, server}) => {
|
it('should prioritize exact timeout over default timeout', async({page, server}) => {
|
||||||
page.setDefaultTimeout(0);
|
page.setDefaultTimeout(0);
|
||||||
let error = null;
|
let error = null;
|
||||||
await page.waitForFileChooser({timeout: 1}).catch(e => error = e);
|
await page.waitForEvent('filechooser', {timeout: 1}).catch(e => error = e);
|
||||||
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
expect(error).toBeInstanceOf(playwright.errors.TimeoutError);
|
||||||
});
|
});
|
||||||
it('should work with no timeout', async({page, server}) => {
|
it('should work with no timeout', async({page, server}) => {
|
||||||
const [chooser] = await Promise.all([
|
const [chooser] = await Promise.all([
|
||||||
page.waitForFileChooser({timeout: 0}),
|
page.waitForEvent('filechooser', {timeout: 0}),
|
||||||
page.evaluate(() => setTimeout(() => {
|
page.evaluate(() => setTimeout(() => {
|
||||||
const el = document.createElement('input');
|
const el = document.createElement('input');
|
||||||
el.type = 'file';
|
el.type = 'file';
|
||||||
@ -90,19 +98,16 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
it('should return the same file chooser when there are many watchdogs simultaneously', async({page, server}) => {
|
it('should return the same file chooser when there are many watchdogs simultaneously', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
const [fileChooser1, fileChooser2] = await Promise.all([
|
const [fileChooser1, fileChooser2] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.$eval('input', input => input.click()),
|
page.$eval('input', input => input.click()),
|
||||||
]);
|
]);
|
||||||
expect(fileChooser1 === fileChooser2).toBe(true);
|
expect(fileChooser1 === fileChooser2).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe('Page.waitForFileChooser', function() {
|
|
||||||
it('should accept single file', async({page, server}) => {
|
it('should accept single file', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file oninput='javascript:console.timeStamp()'>`);
|
await page.setContent(`<input type=file oninput='javascript:console.timeStamp()'>`);
|
||||||
const [{ element }] = await Promise.all([
|
const [{ element }] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
await element.setInputFiles(FILE_TO_UPLOAD);
|
await element.setInputFiles(FILE_TO_UPLOAD);
|
||||||
@ -111,7 +116,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
});
|
});
|
||||||
it('should be able to read selected file', async({page, server}) => {
|
it('should be able to read selected file', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
page.waitForFileChooser().then(({element}) => element.setInputFiles(FILE_TO_UPLOAD));
|
page.waitForEvent('filechooser').then(({element}) => element.setInputFiles(FILE_TO_UPLOAD));
|
||||||
expect(await page.$eval('input', async picker => {
|
expect(await page.$eval('input', async picker => {
|
||||||
picker.click();
|
picker.click();
|
||||||
await new Promise(x => picker.oninput = x);
|
await new Promise(x => picker.oninput = x);
|
||||||
@ -123,13 +128,13 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
});
|
});
|
||||||
it('should be able to reset selected files with empty file list', async({page, server}) => {
|
it('should be able to reset selected files with empty file list', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
page.waitForFileChooser().then(({element}) => element.setInputFiles(FILE_TO_UPLOAD));
|
page.waitForEvent('filechooser').then(({element}) => element.setInputFiles(FILE_TO_UPLOAD));
|
||||||
expect(await page.$eval('input', async picker => {
|
expect(await page.$eval('input', async picker => {
|
||||||
picker.click();
|
picker.click();
|
||||||
await new Promise(x => picker.oninput = x);
|
await new Promise(x => picker.oninput = x);
|
||||||
return picker.files.length;
|
return picker.files.length;
|
||||||
})).toBe(1);
|
})).toBe(1);
|
||||||
page.waitForFileChooser().then(({element}) => element.setInputFiles());
|
page.waitForEvent('filechooser').then(({element}) => element.setInputFiles());
|
||||||
expect(await page.$eval('input', async picker => {
|
expect(await page.$eval('input', async picker => {
|
||||||
picker.click();
|
picker.click();
|
||||||
await new Promise(x => picker.oninput = x);
|
await new Promise(x => picker.oninput = x);
|
||||||
@ -139,7 +144,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
it('should not accept multiple files for single-file input', async({page, server}) => {
|
it('should not accept multiple files for single-file input', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
const [{ element }] = await Promise.all([
|
const [{ element }] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
let error = null;
|
let error = null;
|
||||||
@ -154,7 +159,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
it('should work for single file pick', async({page, server}) => {
|
it('should work for single file pick', async({page, server}) => {
|
||||||
await page.setContent(`<input type=file>`);
|
await page.setContent(`<input type=file>`);
|
||||||
const [{ multiple }] = await Promise.all([
|
const [{ multiple }] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
expect(multiple).toBe(false);
|
expect(multiple).toBe(false);
|
||||||
@ -162,7 +167,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
it('should work for "multiple"', async({page, server}) => {
|
it('should work for "multiple"', async({page, server}) => {
|
||||||
await page.setContent(`<input multiple type=file>`);
|
await page.setContent(`<input multiple type=file>`);
|
||||||
const [{ multiple }] = await Promise.all([
|
const [{ multiple }] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
expect(multiple).toBe(true);
|
expect(multiple).toBe(true);
|
||||||
@ -170,7 +175,7 @@ module.exports.addTests = function({testRunner, expect, playwright, FFOX, CHROME
|
|||||||
it('should work for "webkitdirectory"', async({page, server}) => {
|
it('should work for "webkitdirectory"', async({page, server}) => {
|
||||||
await page.setContent(`<input multiple webkitdirectory type=file>`);
|
await page.setContent(`<input multiple webkitdirectory type=file>`);
|
||||||
const [{ multiple }] = await Promise.all([
|
const [{ multiple }] = await Promise.all([
|
||||||
page.waitForFileChooser(),
|
page.waitForEvent('filechooser'),
|
||||||
page.click('input'),
|
page.click('input'),
|
||||||
]);
|
]);
|
||||||
expect(multiple).toBe(true);
|
expect(multiple).toBe(true);
|
||||||
|
Loading…
Reference in New Issue
Block a user