fix: filechooser interception in OOPIFs (#14432)

This commit is contained in:
Yury Semikhatsky 2022-05-27 13:04:58 -07:00 committed by GitHub
parent 962d933c78
commit abced7223c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 10 deletions

View File

@ -219,8 +219,8 @@ export class CRPage implements PageDelegate {
await this._forAllFrameSessions(frame => frame._updateRequestInterception()); await this._forAllFrameSessions(frame => frame._updateRequestInterception());
} }
async setFileChooserIntercepted(enabled: boolean) { async updateFileChooserInterception() {
await this._forAllFrameSessions(frame => frame.setFileChooserIntercepted(enabled)); await this._forAllFrameSessions(frame => frame._updateFileChooserInterception(false));
} }
async reload(): Promise<void> { async reload(): Promise<void> {
@ -559,6 +559,7 @@ class FrameSession {
promises.push(this._updateOffline(true)); promises.push(this._updateOffline(true));
promises.push(this._updateHttpCredentials(true)); promises.push(this._updateHttpCredentials(true));
promises.push(this._updateEmulateMedia(true)); promises.push(this._updateEmulateMedia(true));
promises.push(this._updateFileChooserInterception(true));
for (const binding of this._crPage._page.allBindings()) for (const binding of this._crPage._page.allBindings())
promises.push(this._initBinding(binding)); promises.push(this._initBinding(binding));
for (const source of this._crPage._browserContext.initScripts) for (const source of this._crPage._browserContext.initScripts)
@ -1082,7 +1083,10 @@ class FrameSession {
await this._networkManager.setRequestInterception(this._page._needsRequestInterception()); await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
} }
async setFileChooserIntercepted(enabled: boolean) { async _updateFileChooserInterception(initial: boolean) {
const enabled = this._page._state.interceptFileChooser;
if (initial && !enabled)
return;
await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed. await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
} }

View File

@ -386,7 +386,7 @@ export class FFPage implements PageDelegate {
await this._networkManager.setRequestInterception(this._page._needsRequestInterception()); await this._networkManager.setRequestInterception(this._page._needsRequestInterception());
} }
async setFileChooserIntercepted(enabled: boolean) { async updateFileChooserInterception(enabled: boolean) {
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed. await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
} }

View File

@ -67,7 +67,7 @@ export interface PageDelegate {
setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void>; setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void>;
updateEmulateMedia(): Promise<void>; updateEmulateMedia(): Promise<void>;
updateRequestInterception(): Promise<void>; updateRequestInterception(): Promise<void>;
setFileChooserIntercepted(enabled: boolean): Promise<void>; updateFileChooserInterception(enabled: boolean): Promise<void>;
bringToFront(): Promise<void>; bringToFront(): Promise<void>;
setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise<void>; setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise<void>;
@ -104,6 +104,7 @@ type PageState = {
reducedMotion: types.ReducedMotion | null; reducedMotion: types.ReducedMotion | null;
forcedColors: types.ForcedColors | null; forcedColors: types.ForcedColors | null;
extraHTTPHeaders: types.HeadersArray | null; extraHTTPHeaders: types.HeadersArray | null;
interceptFileChooser: boolean;
}; };
type ExpectScreenshotOptions = { type ExpectScreenshotOptions = {
@ -183,6 +184,7 @@ export class Page extends SdkObject {
reducedMotion: browserContext._options.reducedMotion !== undefined ? browserContext._options.reducedMotion : 'no-preference', reducedMotion: browserContext._options.reducedMotion !== undefined ? browserContext._options.reducedMotion : 'no-preference',
forcedColors: browserContext._options.forcedColors !== undefined ? browserContext._options.forcedColors : 'none', forcedColors: browserContext._options.forcedColors !== undefined ? browserContext._options.forcedColors : 'none',
extraHTTPHeaders: null, extraHTTPHeaders: null,
interceptFileChooser: false,
}; };
this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate)); this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate));
this.keyboard = new input.Keyboard(delegate.rawKeyboard, this); this.keyboard = new input.Keyboard(delegate.rawKeyboard, this);
@ -620,7 +622,8 @@ export class Page extends SdkObject {
} }
async setFileChooserIntercepted(enabled: boolean): Promise<void> { async setFileChooserIntercepted(enabled: boolean): Promise<void> {
await this._delegate.setFileChooserIntercepted(enabled); this._state.interceptFileChooser = enabled;
await this._delegate.updateFileChooserInterception(enabled);
} }
frameNavigatedToNewDocument(frame: frames.Frame) { frameNavigatedToNewDocument(frame: frames.Frame) {

View File

@ -77,7 +77,6 @@ export class WKPage implements PageDelegate {
private _nextWindowOpenPopupFeatures?: string[]; private _nextWindowOpenPopupFeatures?: string[];
private _recordingVideoFile: string | null = null; private _recordingVideoFile: string | null = null;
private _screencastGeneration: number = 0; private _screencastGeneration: number = 0;
private _interceptingFileChooser = false;
constructor(browserContext: WKBrowserContext, pageProxySession: WKSession, opener: WKPage | null) { constructor(browserContext: WKBrowserContext, pageProxySession: WKSession, opener: WKPage | null) {
this._pageProxySession = pageProxySession; this._pageProxySession = pageProxySession;
@ -218,7 +217,7 @@ export class WKPage implements PageDelegate {
promises.push(session.send('Page.setTimeZone', { timeZone: contextOptions.timezoneId }). promises.push(session.send('Page.setTimeZone', { timeZone: contextOptions.timezoneId }).
catch(e => { throw new Error(`Invalid timezone ID: ${contextOptions.timezoneId}`); })); catch(e => { throw new Error(`Invalid timezone ID: ${contextOptions.timezoneId}`); }));
} }
if (this._interceptingFileChooser) if (this._page._state.interceptFileChooser)
promises.push(session.send('Page.setInterceptFileChooserDialog', { enabled: true })); promises.push(session.send('Page.setInterceptFileChooserDialog', { enabled: true }));
promises.push(session.send('Page.overrideSetting', { setting: 'DeviceOrientationEventEnabled' as any, value: contextOptions.isMobile })); promises.push(session.send('Page.overrideSetting', { setting: 'DeviceOrientationEventEnabled' as any, value: contextOptions.isMobile }));
promises.push(session.send('Page.overrideSetting', { setting: 'FullScreenEnabled' as any, value: !contextOptions.isMobile })); promises.push(session.send('Page.overrideSetting', { setting: 'FullScreenEnabled' as any, value: !contextOptions.isMobile }));
@ -725,8 +724,8 @@ export class WKPage implements PageDelegate {
await this._pageProxySession.send('Emulation.setAuthCredentials', { username: credentials.username, password: credentials.password }); await this._pageProxySession.send('Emulation.setAuthCredentials', { username: credentials.username, password: credentials.password });
} }
async setFileChooserIntercepted(enabled: boolean) { async updateFileChooserInterception() {
this._interceptingFileChooser = enabled; const enabled = this._page._state.interceptFileChooser;
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed. await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
} }

View File

@ -311,6 +311,21 @@ it('should allow cdp sessions on oopifs', async function({ page, browser, server
expect(JSON.stringify(oopif)).toContain('./digits/1.png'); expect(JSON.stringify(oopif)).toContain('./digits/1.png');
}); });
it('should emit filechooser event for iframe', async ({ page, server, browser }) => {
// Add listener before OOPIF is created.
const chooserPromise = page.waitForEvent('filechooser');
await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(await countOOPIFs(browser)).toBe(1);
expect(page.frames().length).toBe(2);
const frame = page.frames()[1];
await frame.setContent(`<input type=file>`);
const [chooser] = await Promise.all([
chooserPromise,
frame.click('input'),
]);
expect(chooser).toBeTruthy();
});
async function countOOPIFs(browser) { async function countOOPIFs(browser) {
const browserSession = await browser.newBrowserCDPSession(); const browserSession = await browser.newBrowserCDPSession();
const oopifs = []; const oopifs = [];

View File

@ -517,3 +517,17 @@ it('should emit event after navigation', async ({ page, server, browserName, bro
]); ]);
expect(logs).toEqual(['filechooser', 'filechooser']); expect(logs).toEqual(['filechooser', 'filechooser']);
}); });
it('should trigger listener added before navigation', async ({ page, server }) => {
// Add listener before cross process navigation.
const chooserPromise = new Promise(f => page.once('filechooser', f));
await page.goto(server.PREFIX + '/empty.html');
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
await page.setContent(`<input type=file>`);
const [chooser] = await Promise.all([
chooserPromise,
page.click('input'),
]);
expect(chooser).toBeTruthy();
});