feat(rpc): make sure filechooser is only intercepted when needed (#3482)
So that user can choose a file manually in headful mode.
This commit is contained in:
parent
0c798f0572
commit
244c2f37b6
|
|
@ -536,6 +536,22 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addListener(event: string | symbol, listener: Listener): this {
|
||||||
|
if (event === Events.Page.FileChooser) {
|
||||||
|
if (!this.listenerCount(event))
|
||||||
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: true });
|
||||||
|
}
|
||||||
|
super.addListener(event, listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
off(event: string | symbol, listener: Listener): this {
|
||||||
|
super.off(event, listener);
|
||||||
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
||||||
|
this._channel.setFileChooserInterceptedNoReply({ intercepted: false });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
removeListener(event: string | symbol, listener: Listener): this {
|
removeListener(event: string | symbol, listener: Listener): this {
|
||||||
super.removeListener(event, listener);
|
super.removeListener(event, listener);
|
||||||
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
if (event === Events.Page.FileChooser && !this.listenerCount(event))
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import { CRCoverage } from '../../chromium/crCoverage';
|
||||||
|
|
||||||
export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements PageChannel {
|
export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements PageChannel {
|
||||||
private _page: Page;
|
private _page: Page;
|
||||||
|
private _onFileChooser: (fileChooser: FileChooser) => void;
|
||||||
|
|
||||||
constructor(scope: DispatcherScope, page: Page) {
|
constructor(scope: DispatcherScope, page: Page) {
|
||||||
// TODO: theoretically, there could be more than one frame already.
|
// TODO: theoretically, there could be more than one frame already.
|
||||||
|
|
@ -52,10 +53,11 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
||||||
page.on(Events.Page.DOMContentLoaded, () => this._dispatchEvent('domcontentloaded'));
|
page.on(Events.Page.DOMContentLoaded, () => this._dispatchEvent('domcontentloaded'));
|
||||||
page.on(Events.Page.Dialog, dialog => this._dispatchEvent('dialog', { dialog: new DialogDispatcher(this._scope, dialog) }));
|
page.on(Events.Page.Dialog, dialog => this._dispatchEvent('dialog', { dialog: new DialogDispatcher(this._scope, dialog) }));
|
||||||
page.on(Events.Page.Download, dialog => this._dispatchEvent('download', { download: new DownloadDispatcher(this._scope, dialog) }));
|
page.on(Events.Page.Download, dialog => this._dispatchEvent('download', { download: new DownloadDispatcher(this._scope, dialog) }));
|
||||||
page.on(Events.Page.FileChooser, (fileChooser: FileChooser) => this._dispatchEvent('fileChooser', {
|
// We add this listener lazily, to avoid intercepting file chooser when noone listens.
|
||||||
|
this._onFileChooser = fileChooser => this._dispatchEvent('fileChooser', {
|
||||||
element: new ElementHandleDispatcher(this._scope, fileChooser.element()),
|
element: new ElementHandleDispatcher(this._scope, fileChooser.element()),
|
||||||
isMultiple: fileChooser.isMultiple()
|
isMultiple: fileChooser.isMultiple()
|
||||||
}));
|
});
|
||||||
page.on(Events.Page.FrameAttached, frame => this._onFrameAttached(frame));
|
page.on(Events.Page.FrameAttached, frame => this._onFrameAttached(frame));
|
||||||
page.on(Events.Page.FrameDetached, frame => this._onFrameDetached(frame));
|
page.on(Events.Page.FrameDetached, frame => this._onFrameDetached(frame));
|
||||||
page.on(Events.Page.Load, () => this._dispatchEvent('load'));
|
page.on(Events.Page.Load, () => this._dispatchEvent('load'));
|
||||||
|
|
@ -141,6 +143,10 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
async setFileChooserInterceptedNoReply(params: { intercepted: boolean }) {
|
async setFileChooserInterceptedNoReply(params: { intercepted: boolean }) {
|
||||||
|
if (params.intercepted)
|
||||||
|
this._page.on(Events.Page.FileChooser, this._onFileChooser);
|
||||||
|
else
|
||||||
|
this._page.removeListener(Events.Page.FileChooser, this._onFileChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
async title() {
|
async title() {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ it('should set from memory', async({page}) => {
|
||||||
expect(await page.$eval('input', input => input.files[0].name)).toBe('test.txt');
|
expect(await page.$eval('input', input => input.files[0].name)).toBe('test.txt');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit event', async({page, server}) => {
|
it('should emit event once', 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([
|
||||||
new Promise(f => page.once('filechooser', f)),
|
new Promise(f => page.once('filechooser', f)),
|
||||||
|
|
@ -63,6 +63,36 @@ it('should emit event', async({page, server}) => {
|
||||||
expect(chooser).toBeTruthy();
|
expect(chooser).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should emit event on/off', async({page, server}) => {
|
||||||
|
await page.setContent(`<input type=file>`);
|
||||||
|
const [chooser] = await Promise.all([
|
||||||
|
new Promise(f => {
|
||||||
|
const listener = chooser => {
|
||||||
|
page.off('filechooser', listener);
|
||||||
|
f(chooser);
|
||||||
|
}
|
||||||
|
page.on('filechooser', listener);
|
||||||
|
}),
|
||||||
|
page.click('input'),
|
||||||
|
]);
|
||||||
|
expect(chooser).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit event addListener/removeListener', async({page, server}) => {
|
||||||
|
await page.setContent(`<input type=file>`);
|
||||||
|
const [chooser] = await Promise.all([
|
||||||
|
new Promise(f => {
|
||||||
|
const listener = chooser => {
|
||||||
|
page.removeListener('filechooser', listener);
|
||||||
|
f(chooser);
|
||||||
|
}
|
||||||
|
page.addListener('filechooser', listener);
|
||||||
|
}),
|
||||||
|
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([
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue