Skip to content

Commit bb2b296

Browse files
authored
feat(inspector): pause on page/context close (#5319)
1 parent 8a9048c commit bb2b296

File tree

13 files changed

+85
-40
lines changed

13 files changed

+85
-40
lines changed

src/browserServerImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ class ConnectedBrowser extends BrowserDispatcher {
171171

172172
async close(): Promise<void> {
173173
// Only close our own contexts.
174-
await Promise.all(this._contexts.map(context => context.close()));
174+
await Promise.all(this._contexts.map(context => context.close({}, internalCallMetadata())));
175175
this._didClose();
176176
}
177177

src/dispatchers/browserContextDispatcher.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
6565
});
6666
}
6767

68-
async newPage(): Promise<channels.BrowserContextNewPageResult> {
69-
return { page: lookupDispatcher<PageDispatcher>(await this._context.newPage()) };
68+
async newPage(params: channels.BrowserContextNewPageParams, metadata: CallMetadata): Promise<channels.BrowserContextNewPageResult> {
69+
return { page: lookupDispatcher<PageDispatcher>(await this._context.newPage(metadata)) };
7070
}
7171

7272
async cookies(params: channels.BrowserContextCookiesParams): Promise<channels.BrowserContextCookiesResult> {
@@ -123,8 +123,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
123123
return await this._context.storageState(metadata);
124124
}
125125

126-
async close(): Promise<void> {
127-
await this._context.close();
126+
async close(params: channels.BrowserContextCloseParams, metadata: CallMetadata): Promise<void> {
127+
await this._context.close(metadata);
128128
}
129129

130130
async recorderSupplementEnable(params: channels.BrowserContextRecorderSupplementEnableParams): Promise<void> {

src/dispatchers/pageDispatcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageInitializer> i
146146
}
147147

148148
async close(params: channels.PageCloseParams, metadata: CallMetadata): Promise<void> {
149-
await this._page.close(params);
149+
await this._page.close(metadata, params);
150150
}
151151

152152
async setFileChooserInterceptedNoReply(params: channels.PageSetFileChooserInterceptedNoReplyParams, metadata: CallMetadata): Promise<void> {

src/protocol/channels.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ export type BrowserContextPauseResult = void;
738738
export type BrowserContextRecorderSupplementEnableParams = {
739739
language?: string,
740740
startRecording?: boolean,
741+
pauseOnNextStatement?: boolean,
741742
launchOptions?: any,
742743
contextOptions?: any,
743744
device?: string,
@@ -747,6 +748,7 @@ export type BrowserContextRecorderSupplementEnableParams = {
747748
export type BrowserContextRecorderSupplementEnableOptions = {
748749
language?: string,
749750
startRecording?: boolean,
751+
pauseOnNextStatement?: boolean,
750752
launchOptions?: any,
751753
contextOptions?: any,
752754
device?: string,

src/protocol/protocol.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ BrowserContext:
648648
parameters:
649649
language: string?
650650
startRecording: boolean?
651+
pauseOnNextStatement: boolean?
651652
launchOptions: json?
652653
contextOptions: json?
653654
device: string?

src/protocol/validator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
363363
scheme.BrowserContextRecorderSupplementEnableParams = tObject({
364364
language: tOptional(tString),
365365
startRecording: tOptional(tBoolean),
366+
pauseOnNextStatement: tOptional(tBoolean),
366367
launchOptions: tOptional(tAny),
367368
contextOptions: tOptional(tAny),
368369
device: tOptional(tString),

src/server/browser.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,6 @@ export abstract class Browser extends SdkObject {
7272
abstract isConnected(): boolean;
7373
abstract version(): string;
7474

75-
async newPage(options: types.BrowserContextOptions): Promise<Page> {
76-
const context = await this.newContext(options);
77-
const page = await context.newPage();
78-
page._ownedContext = context;
79-
return page;
80-
}
81-
8275
_downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string) {
8376
const download = new Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename);
8477
this._downloads.set(uuid, download);

src/server/browserContext.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { Progress } from './progress';
2727
import { Selectors, serverSelectors } from './selectors';
2828
import * as types from './types';
2929
import path from 'path';
30-
import { CallMetadata, SdkObject } from './instrumentation';
30+
import { CallMetadata, internalCallMetadata, SdkObject } from './instrumentation';
3131

3232
export class Video {
3333
readonly _videoId: string;
@@ -209,8 +209,8 @@ export abstract class BrowserContext extends SdkObject {
209209
// - chromium fails to change isMobile for existing page;
210210
// - webkit fails to change locale for existing page.
211211
const oldPage = pages[0];
212-
await this.newPage();
213-
await oldPage.close();
212+
await this.newPage(progress.metadata);
213+
await oldPage.close(progress.metadata);
214214
}
215215
}
216216

@@ -245,7 +245,7 @@ export abstract class BrowserContext extends SdkObject {
245245
return this._closedStatus !== 'open';
246246
}
247247

248-
async close() {
248+
async close(metadata: CallMetadata) {
249249
if (this._closedStatus === 'open') {
250250
this.emit(BrowserContext.Events.BeforeClose);
251251
this._closedStatus = 'closing';
@@ -255,7 +255,7 @@ export abstract class BrowserContext extends SdkObject {
255255
if (this._isPersistentContext) {
256256
// Close all the pages instead of the context,
257257
// because we cannot close the default context.
258-
await Promise.all(this.pages().map(page => page.close()));
258+
await Promise.all(this.pages().map(page => page.close(metadata)));
259259
} else {
260260
// Close the context.
261261
await this._doClose();
@@ -286,7 +286,7 @@ export abstract class BrowserContext extends SdkObject {
286286
await this._closePromise;
287287
}
288288

289-
async newPage(): Promise<Page> {
289+
async newPage(metadata: CallMetadata): Promise<Page> {
290290
const pageDelegate = await this.newPageDelegate();
291291
const pageOrError = await pageDelegate.pageOrError();
292292
if (pageOrError instanceof Page) {
@@ -307,21 +307,22 @@ export abstract class BrowserContext extends SdkObject {
307307
origins: []
308308
};
309309
if (this._origins.size) {
310-
const page = await this.newPage();
310+
const internalMetadata = internalCallMetadata();
311+
const page = await this.newPage(internalMetadata);
311312
await page._setServerRequestInterceptor(handler => {
312313
handler.fulfill({ body: '<html></html>' }).catch(() => {});
313314
});
314315
for (const origin of this._origins) {
315316
const originStorage: types.OriginStorage = { origin, localStorage: [] };
316317
result.origins.push(originStorage);
317318
const frame = page.mainFrame();
318-
await frame.goto(metadata, origin);
319+
await frame.goto(internalMetadata, origin);
319320
const storage = await frame._evaluateExpression(`({
320321
localStorage: Object.keys(localStorage).map(name => ({ name, value: localStorage.getItem(name) })),
321322
})`, false, undefined, 'utility');
322323
originStorage.localStorage = storage.localStorage;
323324
}
324-
await page.close();
325+
await page.close(internalMetadata);
325326
}
326327
return result;
327328
}
@@ -330,7 +331,8 @@ export abstract class BrowserContext extends SdkObject {
330331
if (state.cookies)
331332
await this.addCookies(state.cookies);
332333
if (state.origins && state.origins.length) {
333-
const page = await this.newPage();
334+
const internalMetadata = internalCallMetadata();
335+
const page = await this.newPage(internalMetadata);
334336
await page._setServerRequestInterceptor(handler => {
335337
handler.fulfill({ body: '<html></html>' }).catch(() => {});
336338
});
@@ -343,7 +345,7 @@ export abstract class BrowserContext extends SdkObject {
343345
localStorage.setItem(name, value);
344346
}`, true, originState, 'utility');
345347
}
346-
await page.close();
348+
await page.close(internalMetadata);
347349
}
348350
}
349351

src/server/page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ export class Page extends SdkObject {
428428
this._timeoutSettings.timeout(options));
429429
}
430430

431-
async close(options?: { runBeforeUnload?: boolean }) {
431+
async close(metadata: CallMetadata, options?: { runBeforeUnload?: boolean }) {
432432
if (this._closedState === 'closed')
433433
return;
434434
const runBeforeUnload = !!options && !!options.runBeforeUnload;
@@ -442,7 +442,7 @@ export class Page extends SdkObject {
442442
if (!runBeforeUnload)
443443
await this._closedPromise;
444444
if (this._ownedContext)
445-
await this._ownedContext.close();
445+
await this._ownedContext.close(metadata);
446446
}
447447

448448
private _setIsError() {

src/server/supplements/inspectorController.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class InspectorController implements InstrumentationListener {
2525

2626
async onContextCreated(context: BrowserContext): Promise<void> {
2727
if (isDebugMode())
28-
RecorderSupplement.getOrCreate(context);
28+
RecorderSupplement.getOrCreate(context, { pauseOnNextStatement: true });
2929
}
3030

3131
async onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata): Promise<void> {
@@ -52,12 +52,8 @@ export class InspectorController implements InstrumentationListener {
5252
}
5353
}
5454

55-
if (metadata.method === 'pause') {
56-
// Force create recorder on pause.
57-
if (!context._browser.options.headful && !isUnderTest())
58-
return;
59-
RecorderSupplement.getOrCreate(context);
60-
}
55+
if (shouldOpenInspector(sdkObject, metadata))
56+
RecorderSupplement.getOrCreate(context, { pauseOnNextStatement: true });
6157

6258
const recorder = await RecorderSupplement.getNoCreate(context);
6359
await recorder?.onBeforeCall(sdkObject, metadata);
@@ -104,3 +100,9 @@ export class InspectorController implements InstrumentationListener {
104100
await recorder?.updateCallLog([metadata]);
105101
}
106102
}
103+
104+
function shouldOpenInspector(sdkObject: SdkObject, metadata: CallMetadata): boolean {
105+
if (!sdkObject.attribution.browser?.options.headful && !isUnderTest())
106+
return false;
107+
return metadata.method === 'pause';
108+
}

0 commit comments

Comments
 (0)