diff --git a/packages/playwright-core/src/remote/playwrightConnection.ts b/packages/playwright-core/src/remote/playwrightConnection.ts index 64300e91f9a39..f223362b44b4c 100644 --- a/packages/playwright-core/src/remote/playwrightConnection.ts +++ b/packages/playwright-core/src/remote/playwrightConnection.ts @@ -208,6 +208,8 @@ export class PlaywrightConnection { for (const context of browser.contexts()) { if (!context.pages().length) await context.close(serverSideCallMetadata()); + else + await context.stopPendingOperations(); } if (!browser.contexts()) await browser.close(); diff --git a/packages/playwright-core/src/server/browser.ts b/packages/playwright-core/src/server/browser.ts index 1efeee2b3361b..39fc0e4640486 100644 --- a/packages/playwright-core/src/server/browser.ts +++ b/packages/playwright-core/src/server/browser.ts @@ -107,6 +107,7 @@ export abstract class Browser extends SdkObject { this._contextForReuse = { context: await this.newContext(metadata, params), hash }; return { context: this._contextForReuse.context, needsReset: false }; } + await this._contextForReuse.context.stopPendingOperations(); return { context: this._contextForReuse.context, needsReset: true }; } diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index a5cd5f9e0c429..39bfd909c185a 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -26,7 +26,7 @@ import { helper } from './helper'; import * as network from './network'; import type { PageDelegate } from './page'; import { Page, PageBinding } from './page'; -import type { Progress } from './progress'; +import type { Progress, ProgressController } from './progress'; import type { Selectors } from './selectors'; import type * as types from './types'; import type * as channels from '@protocol/channels'; @@ -56,6 +56,7 @@ export abstract class BrowserContext extends SdkObject { readonly _timeoutSettings = new TimeoutSettings(); readonly _pageBindings = new Map(); + readonly _activeProgressControllers = new Set(); readonly _options: channels.BrowserNewContextParams; _requestInterceptor?: network.RouteHandler; private _isPersistentContext: boolean; @@ -150,6 +151,11 @@ export abstract class BrowserContext extends SdkObject { return true; } + async stopPendingOperations() { + for (const controller of this._activeProgressControllers) + controller.abort(new Error(`Context was reset for reuse.`)); + } + static reusableContextHash(params: channels.BrowserNewContextForReuseParams): string { const paramsCopy = { ...params }; diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index 44df8f6a5dae7..45ec599ead607 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -78,6 +78,7 @@ export abstract class APIRequestContext extends SdkObject { readonly fetchResponses: Map = new Map(); readonly fetchLog: Map = new Map(); protected static allInstances: Set = new Set(); + readonly _activeProgressControllers = new Set(); static findResponseBody(guid: string): Buffer | undefined { for (const request of APIRequestContext.allInstances) { diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index 6ae335f079a33..06df262ab35cf 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -63,6 +63,10 @@ export class ProgressController { return this._lastIntermediateResult; } + abort(error: Error) { + this._forceAbortPromise.reject(error); + } + async run(task: (progress: Progress) => Promise, timeout?: number): Promise { if (timeout) { this._timeout = timeout; @@ -71,6 +75,7 @@ export class ProgressController { assert(this._state === 'before'); this._state = 'running'; + this.sdkObject.attribution.context?._activeProgressControllers.add(this); const progress: Progress = { log: message => { @@ -117,6 +122,7 @@ export class ProgressController { await Promise.all(this._cleanups.splice(0).map(runCleanup)); throw e; } finally { + this.sdkObject.attribution.context?._activeProgressControllers.delete(this); clearTimeout(timer); } }