mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: make handle beforeunload when reusing the context (#18357)
Fixes: https://github.com/microsoft/playwright/issues/17903
This commit is contained in:
parent
d4bab139b2
commit
1505a952fe
@ -180,10 +180,13 @@ export abstract class BrowserContext extends SdkObject {
|
|||||||
page = undefined;
|
page = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless I do this early, setting extra http headers below does not respond.
|
// Unless dialogs are dismissed, setting extra http headers below does not respond.
|
||||||
|
page?._frameManager.setCloseAllOpeningDialogs(true);
|
||||||
await page?._frameManager.closeOpenDialogs();
|
await page?._frameManager.closeOpenDialogs();
|
||||||
// Navigate to about:blank first to ensure no page scripts are running after this point.
|
// Navigate to about:blank first to ensure no page scripts are running after this point.
|
||||||
await page?.mainFrame().goto(metadata, 'about:blank', { timeout: 0 });
|
await page?.mainFrame().goto(metadata, 'about:blank', { timeout: 0 });
|
||||||
|
page?._frameManager.setCloseAllOpeningDialogs(false);
|
||||||
|
|
||||||
await this._resetStorage();
|
await this._resetStorage();
|
||||||
await this._removeExposedBindings();
|
await this._removeExposedBindings();
|
||||||
await this._removeInitScripts();
|
await this._removeInitScripts();
|
||||||
|
@ -25,13 +25,13 @@ export type DialogType = 'alert' | 'beforeunload' | 'confirm' | 'prompt';
|
|||||||
|
|
||||||
export class Dialog extends SdkObject {
|
export class Dialog extends SdkObject {
|
||||||
private _page: Page;
|
private _page: Page;
|
||||||
private _type: string;
|
private _type: DialogType;
|
||||||
private _message: string;
|
private _message: string;
|
||||||
private _onHandle: OnHandle;
|
private _onHandle: OnHandle;
|
||||||
private _handled = false;
|
private _handled = false;
|
||||||
private _defaultValue: string;
|
private _defaultValue: string;
|
||||||
|
|
||||||
constructor(page: Page, type: string, message: string, onHandle: OnHandle, defaultValue?: string) {
|
constructor(page: Page, type: DialogType, message: string, onHandle: OnHandle, defaultValue?: string) {
|
||||||
super(page, 'dialog');
|
super(page, 'dialog');
|
||||||
this._page = page;
|
this._page = page;
|
||||||
this._type = type;
|
this._type = type;
|
||||||
@ -53,7 +53,7 @@ export class Dialog extends SdkObject {
|
|||||||
return this._defaultValue;
|
return this._defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
async accept(promptText: string | undefined) {
|
async accept(promptText?: string) {
|
||||||
assert(!this._handled, 'Cannot accept dialog which is already handled!');
|
assert(!this._handled, 'Cannot accept dialog which is already handled!');
|
||||||
this._handled = true;
|
this._handled = true;
|
||||||
this._page._frameManager.dialogWillClose(this);
|
this._page._frameManager.dialogWillClose(this);
|
||||||
@ -66,4 +66,11 @@ export class Dialog extends SdkObject {
|
|||||||
this._page._frameManager.dialogWillClose(this);
|
this._page._frameManager.dialogWillClose(this);
|
||||||
await this._onHandle(false);
|
await this._onHandle(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
if (this._type === 'beforeunload')
|
||||||
|
await this.accept();
|
||||||
|
else
|
||||||
|
await this.dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,7 @@ export class FrameManager {
|
|||||||
readonly _signalBarriers = new Set<SignalBarrier>();
|
readonly _signalBarriers = new Set<SignalBarrier>();
|
||||||
private _webSockets = new Map<string, network.WebSocket>();
|
private _webSockets = new Map<string, network.WebSocket>();
|
||||||
_openedDialogs: Set<Dialog> = new Set();
|
_openedDialogs: Set<Dialog> = new Set();
|
||||||
|
private _closeAllOpeningDialogs = false;
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this._page = page;
|
this._page = page;
|
||||||
@ -352,6 +353,9 @@ export class FrameManager {
|
|||||||
// Any ongoing evaluations will be stalled until the dialog is closed.
|
// Any ongoing evaluations will be stalled until the dialog is closed.
|
||||||
for (const frame of this._frames.values())
|
for (const frame of this._frames.values())
|
||||||
frame._invalidateNonStallingEvaluations('JavaScript dialog interrupted evaluation');
|
frame._invalidateNonStallingEvaluations('JavaScript dialog interrupted evaluation');
|
||||||
|
if (this._closeAllOpeningDialogs)
|
||||||
|
dialog.close().then(() => {});
|
||||||
|
else
|
||||||
this._openedDialogs.add(dialog);
|
this._openedDialogs.add(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,10 +364,14 @@ export class FrameManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async closeOpenDialogs() {
|
async closeOpenDialogs() {
|
||||||
await Promise.all([...this._openedDialogs].map(dialog => dialog.dismiss())).catch(() => {});
|
await Promise.all([...this._openedDialogs].map(dialog => dialog.close())).catch(() => {});
|
||||||
this._openedDialogs.clear();
|
this._openedDialogs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setCloseAllOpeningDialogs(closeDialogs: boolean) {
|
||||||
|
this._closeAllOpeningDialogs = closeDialogs;
|
||||||
|
}
|
||||||
|
|
||||||
removeChildFramesRecursively(frame: Frame) {
|
removeChildFramesRecursively(frame: Frame) {
|
||||||
for (const child of frame.childFrames())
|
for (const child of frame.childFrames())
|
||||||
this._removeFramesRecursively(child);
|
this._removeFramesRecursively(child);
|
||||||
|
@ -349,3 +349,28 @@ test('should restore cookies', async ({ runInlineTest }) => {
|
|||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(3);
|
expect(result.passed).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should reuse context with beforeunload', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'src/reuse.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
let lastContextGuid;
|
||||||
|
test('one', async ({ page, context }) => {
|
||||||
|
lastContextGuid = context._guid;
|
||||||
|
await page.evaluate(() => {
|
||||||
|
window.addEventListener('beforeunload', event => {
|
||||||
|
event.preventDefault();
|
||||||
|
return event.returnValue = "Are you sure you want to exit?";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('two', async ({ context }) => {
|
||||||
|
expect(context._guid).toBe(lastContextGuid);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: '1' });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(2);
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user