chore: reuse context in the innerloop mode (#15719)

This commit is contained in:
Pavel Feldman 2022-07-15 09:36:36 -08:00 committed by GitHub
parent a198b6d753
commit 55cd3928b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 19 deletions

View File

@ -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/*"

View File

@ -69,6 +69,7 @@ export abstract class Browser extends SdkObject {
_defaultContext: BrowserContext | null = null;
private _startedClosing = false;
readonly _idToVideo = new Map<string, { context: BrowserContext, artifact: Artifact }>();
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);

View File

@ -30,7 +30,6 @@ import { Selectors } from '../selectors';
export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserChannel> 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<Browser, channels.BrowserChann
return { context: new BrowserContextDispatcher(this._scope, context) };
}
/**
* Used for inner loop scenarios where user would like to preserve the browser window, opened page and devtools instance.
*/
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
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<BrowserContextDispatcher>(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<void> {
@ -118,8 +103,8 @@ export class ConnectedBrowserDispatcher extends Dispatcher<Browser, channels.Bro
return { context: new BrowserContextDispatcher(this._scope, context) };
}
newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata?: channels.Metadata | undefined): Promise<channels.BrowserNewContextForReuseResult> {
throw new Error('Method not implemented.');
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
return newContextForReuse(this._object, this._scope, params, metadata);
}
async close(): Promise<void> {
@ -155,3 +140,14 @@ export class ConnectedBrowserDispatcher extends Dispatcher<Browser, channels.Bro
await Promise.all(Array.from(this._contexts).map(context => context.close(serverSideCallMetadata())));
}
}
async function newContextForReuse(browser: Browser, scope: DispatcherScope, params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
const { context, needsReset } = await browser.newContextForReuse(params, metadata);
if (needsReset) {
const oldContextDispatcher = existingDispatcher<BrowserContextDispatcher>(context);
oldContextDispatcher._dispose();
await context.resetForReuse(metadata, params);
}
const contextDispatcher = new BrowserContextDispatcher(scope, context);
return { context: contextDispatcher };
}

View File

@ -0,0 +1,5 @@
{
"port": 3333,
"wsPath": "/",
"headless": false
}