mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-13 07:35:33 +03:00
fix(tracing): do not stall while capturing snapshot with an open dialog (#8328)
This commit is contained in:
parent
80dded6ccf
commit
9c96468b9e
@ -38,6 +38,7 @@ export class Dialog extends SdkObject {
|
||||
this._message = message;
|
||||
this._onHandle = onHandle;
|
||||
this._defaultValue = defaultValue || '';
|
||||
this._page._frameManager.dialogDidOpen();
|
||||
}
|
||||
|
||||
type(): string {
|
||||
@ -55,12 +56,14 @@ export class Dialog extends SdkObject {
|
||||
async accept(promptText: string | undefined) {
|
||||
assert(!this._handled, 'Cannot accept dialog which is already handled!');
|
||||
this._handled = true;
|
||||
this._page._frameManager.dialogWillClose();
|
||||
await this._onHandle(true, promptText);
|
||||
}
|
||||
|
||||
async dismiss() {
|
||||
assert(!this._handled, 'Cannot dismiss dialog which is already handled!');
|
||||
this._handled = true;
|
||||
this._page._frameManager.dialogWillClose();
|
||||
await this._onHandle(false);
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ export class FrameManager {
|
||||
readonly _signalBarriers = new Set<SignalBarrier>();
|
||||
private _webSockets = new Map<string, network.WebSocket>();
|
||||
readonly _responses: network.Response[] = [];
|
||||
_dialogCounter = 0;
|
||||
|
||||
constructor(page: Page) {
|
||||
this._page = page;
|
||||
@ -297,6 +298,17 @@ export class FrameManager {
|
||||
this._page._browserContext.emit(BrowserContext.Events.RequestFailed, request);
|
||||
}
|
||||
|
||||
dialogDidOpen() {
|
||||
// Any ongoing evaluations will be stalled until the dialog is closed.
|
||||
for (const frame of this._frames.values())
|
||||
frame._invalidateNonStallingEvaluations('JavaScript dialog interrupted evaluation');
|
||||
this._dialogCounter++;
|
||||
}
|
||||
|
||||
dialogWillClose() {
|
||||
this._dialogCounter--;
|
||||
}
|
||||
|
||||
removeChildFramesRecursively(frame: Frame) {
|
||||
for (const child of frame.childFrames())
|
||||
this._removeFramesRecursively(child);
|
||||
@ -461,17 +473,17 @@ export class Frame extends SdkObject {
|
||||
setPendingDocument(documentInfo: DocumentInfo | undefined) {
|
||||
this._pendingDocument = documentInfo;
|
||||
if (documentInfo)
|
||||
this._invalidateNonStallingEvaluations();
|
||||
this._invalidateNonStallingEvaluations('Navigation interrupted the evaluation');
|
||||
}
|
||||
|
||||
pendingDocument(): DocumentInfo | undefined {
|
||||
return this._pendingDocument;
|
||||
}
|
||||
|
||||
private async _invalidateNonStallingEvaluations() {
|
||||
_invalidateNonStallingEvaluations(message: string) {
|
||||
if (!this._nonStallingEvaluations)
|
||||
return;
|
||||
const error = new Error('Navigation interrupted the evaluation');
|
||||
const error = new Error(message);
|
||||
for (const callback of this._nonStallingEvaluations)
|
||||
callback(error);
|
||||
}
|
||||
@ -479,6 +491,8 @@ export class Frame extends SdkObject {
|
||||
async nonStallingRawEvaluateInExistingMainContext(expression: string): Promise<any> {
|
||||
if (this._pendingDocument)
|
||||
throw new Error('Frame is currently attempting a navigation');
|
||||
if (this._page._frameManager._dialogCounter)
|
||||
throw new Error('Open JavaScript dialog prevents evaluation');
|
||||
const context = this._existingMainContext();
|
||||
if (!context)
|
||||
throw new Error('Frame does not yet have a main execution context');
|
||||
|
@ -264,6 +264,16 @@ test('should export trace concurrently to second navigation', async ({ context,
|
||||
}
|
||||
});
|
||||
|
||||
test('should not hang for clicks that open dialogs', async ({ context, page }) => {
|
||||
await context.tracing.start({ screenshots: true, snapshots: true });
|
||||
const dialogPromise = page.waitForEvent('dialog');
|
||||
await page.setContent(`<div onclick='window.alert(123)'>Click me</div>`);
|
||||
await page.click('div', { timeout: 2000 }).catch(() => {});
|
||||
const dialog = await dialogPromise;
|
||||
await dialog.dismiss();
|
||||
await context.tracing.stop();
|
||||
});
|
||||
|
||||
async function parseTrace(file: string): Promise<{ events: any[], resources: Map<string, Buffer> }> {
|
||||
const entries = await new Promise<any[]>(f => {
|
||||
const entries: Promise<any>[] = [];
|
||||
|
Loading…
Reference in New Issue
Block a user