From 55cd3928b78c3b49af109147eac17da2579820c9 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Fri, 15 Jul 2022 09:36:36 -0800 Subject: [PATCH] chore: reuse context in the innerloop mode (#15719) --- package.json | 3 +- .../playwright-core/src/server/browser.ts | 12 +++++++ .../server/dispatchers/browserDispatcher.ts | 32 ++++++++----------- utils/innerloop-server.config.json | 5 +++ 4 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 utils/innerloop-server.config.json diff --git a/package.json b/package.json index efc3f39a0b..0e489de17c 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "test-types": "node utils/generate_types/ && npx -p typescript@3.7.5 tsc -p utils/generate_types/test/tsconfig.json && tsc -p ./tests/", "roll": "node utils/roll_browser.js", "check-deps": "node utils/check_deps.js", - "build-android-driver": "./utils/build_android_driver.sh" + "build-android-driver": "./utils/build_android_driver.sh", + "innerloop": "playwright launch-server --browser=chromium --config=utils/innerloop-server.config.json" }, "workspaces": [ "packages/*" diff --git a/packages/playwright-core/src/server/browser.ts b/packages/playwright-core/src/server/browser.ts index 1e5858f666..de78bdf3ae 100644 --- a/packages/playwright-core/src/server/browser.ts +++ b/packages/playwright-core/src/server/browser.ts @@ -69,6 +69,7 @@ export abstract class Browser extends SdkObject { _defaultContext: BrowserContext | null = null; private _startedClosing = false; readonly _idToVideo = new Map(); + private _contextForReuse: { context: BrowserContext, hash: string } | undefined; constructor(options: BrowserOptions) { super(options.rootSdkObject, 'browser'); @@ -90,6 +91,17 @@ export abstract class Browser extends SdkObject { return context; } + async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<{ context: BrowserContext, needsReset: boolean }> { + const hash = BrowserContext.reusableContextHash(params); + if (!this._contextForReuse || hash !== this._contextForReuse.hash || !this._contextForReuse.context.canResetForReuse()) { + if (this._contextForReuse) + await this._contextForReuse.context.close(metadata); + this._contextForReuse = { context: await this.newContext(metadata, params), hash }; + return { context: this._contextForReuse.context, needsReset: false }; + } + return { context: this._contextForReuse.context, needsReset: true }; + } + _downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string) { const download = new Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename); this._downloads.set(uuid, download); diff --git a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts index 86b80fcd4e..d2d851dd4c 100644 --- a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts @@ -30,7 +30,6 @@ import { Selectors } from '../selectors'; export class BrowserDispatcher extends Dispatcher implements channels.BrowserChannel { _type_Browser = true; - private _contextForReuse: { context: BrowserContext, hash: string } | undefined; constructor(scope: DispatcherScope, browser: Browser) { super(scope, browser, 'Browser', { version: browser.version(), name: browser.options.name }, true); @@ -47,22 +46,8 @@ export class BrowserDispatcher extends Dispatcher { - const hash = BrowserContext.reusableContextHash(params); - if (!this._contextForReuse || hash !== this._contextForReuse.hash || !this._contextForReuse.context.canResetForReuse()) { - if (this._contextForReuse) - await this._contextForReuse.context.close(metadata); - this._contextForReuse = { context: await this._object.newContext(metadata, params), hash }; - } else { - const oldContextDispatcher = existingDispatcher(this._contextForReuse.context); - oldContextDispatcher._dispose(); - await this._contextForReuse.context.resetForReuse(metadata, params); - } - const context = new BrowserContextDispatcher(this._scope, this._contextForReuse.context); - return { context }; + return newContextForReuse(this._object, this._scope, params, metadata); } async close(): Promise { @@ -118,8 +103,8 @@ export class ConnectedBrowserDispatcher extends Dispatcher { - throw new Error('Method not implemented.'); + async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise { + return newContextForReuse(this._object, this._scope, params, metadata); } async close(): Promise { @@ -155,3 +140,14 @@ export class ConnectedBrowserDispatcher extends Dispatcher context.close(serverSideCallMetadata()))); } } + +async function newContextForReuse(browser: Browser, scope: DispatcherScope, params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise { + const { context, needsReset } = await browser.newContextForReuse(params, metadata); + if (needsReset) { + const oldContextDispatcher = existingDispatcher(context); + oldContextDispatcher._dispose(); + await context.resetForReuse(metadata, params); + } + const contextDispatcher = new BrowserContextDispatcher(scope, context); + return { context: contextDispatcher }; +} diff --git a/utils/innerloop-server.config.json b/utils/innerloop-server.config.json new file mode 100644 index 0000000000..aadb799b72 --- /dev/null +++ b/utils/innerloop-server.config.json @@ -0,0 +1,5 @@ +{ + "port": 3333, + "wsPath": "/", + "headless": false +}