diff --git a/packages/playwright-core/src/cli/driver.ts b/packages/playwright-core/src/cli/driver.ts index 26fb476e13..b36d3fb330 100644 --- a/packages/playwright-core/src/cli/driver.ts +++ b/packages/playwright-core/src/cli/driver.ts @@ -143,6 +143,10 @@ class ProtocolHandler { recorder.setHighlightedSelector(params.selector); } + async hideHighlight() { + await this._playwright.hideHighlight(); + } + async kill() { selfDestruct(); } @@ -176,7 +180,7 @@ async function allRecorders(playwright: Playwright): Promise { const contexts = new Set(); for (const page of playwright.allPages()) contexts.add(page.context()); - const result = await Promise.all([...contexts].map(c => Recorder.show(c, {}, () => Promise.resolve(new InspectingRecorderApp())))); + const result = await Promise.all([...contexts].map(c => Recorder.show(c, { omitCallTracking: true }, () => Promise.resolve(new InspectingRecorderApp())))); return result.filter(Boolean) as Recorder[]; } diff --git a/packages/playwright-core/src/protocol/channels.ts b/packages/playwright-core/src/protocol/channels.ts index 9b22e629b5..571151db01 100644 --- a/packages/playwright-core/src/protocol/channels.ts +++ b/packages/playwright-core/src/protocol/channels.ts @@ -1424,6 +1424,7 @@ export type BrowserContextRecorderSupplementEnableParams = { saveStorage?: string, outputFile?: string, handleSIGINT?: boolean, + omitCallTracking?: boolean, }; export type BrowserContextRecorderSupplementEnableOptions = { language?: string, @@ -1435,6 +1436,7 @@ export type BrowserContextRecorderSupplementEnableOptions = { saveStorage?: string, outputFile?: string, handleSIGINT?: boolean, + omitCallTracking?: boolean, }; export type BrowserContextRecorderSupplementEnableResult = void; export type BrowserContextNewCDPSessionParams = { diff --git a/packages/playwright-core/src/protocol/protocol.yml b/packages/playwright-core/src/protocol/protocol.yml index 162f4d20b8..1791fd11a7 100644 --- a/packages/playwright-core/src/protocol/protocol.yml +++ b/packages/playwright-core/src/protocol/protocol.yml @@ -949,6 +949,7 @@ BrowserContext: saveStorage: string? outputFile: string? handleSIGINT: boolean? + omitCallTracking: boolean? newCDPSession: parameters: diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 962544d1cf..97d5d44002 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -773,6 +773,7 @@ scheme.BrowserContextRecorderSupplementEnableParams = tObject({ saveStorage: tOptional(tString), outputFile: tOptional(tString), handleSIGINT: tOptional(tBoolean), + omitCallTracking: tOptional(tBoolean), }); scheme.BrowserContextRecorderSupplementEnableResult = tOptional(tObject({})); scheme.BrowserContextNewCDPSessionParams = tObject({ diff --git a/packages/playwright-core/src/server/injected/highlight.ts b/packages/playwright-core/src/server/injected/highlight.ts index 25843e759f..55d00d6a86 100644 --- a/packages/playwright-core/src/server/injected/highlight.ts +++ b/packages/playwright-core/src/server/injected/highlight.ts @@ -14,6 +14,10 @@ * limitations under the License. */ +import { stringifySelector } from '../isomorphic/selectorParser'; +import type { ParsedSelector } from '../isomorphic/selectorParser'; +import type { InjectedScript } from './injectedScript'; + type HighlightEntry = { targetElement: Element, highlightElement: HTMLElement, @@ -29,9 +33,12 @@ export class Highlight { private _highlightEntries: HighlightEntry[] = []; private _actionPointElement: HTMLElement; private _isUnderTest: boolean; + private _injectedScript: InjectedScript; + private _rafRequest: number | undefined; - constructor(isUnderTest: boolean) { - this._isUnderTest = isUnderTest; + constructor(injectedScript: InjectedScript) { + this._injectedScript = injectedScript; + this._isUnderTest = injectedScript.isUnderTest; this._glassPaneElement = document.createElement('x-pw-glass'); this._glassPaneElement.style.position = 'fixed'; this._glassPaneElement.style.top = '0'; @@ -95,7 +102,16 @@ export class Highlight { document.documentElement.appendChild(this._glassPaneElement); } + runHighlightOnRaf(selector: ParsedSelector) { + if (this._rafRequest) + cancelAnimationFrame(this._rafRequest); + this.updateHighlight(this._injectedScript.querySelectorAll(selector, document.documentElement), stringifySelector(selector), false); + this._rafRequest = requestAnimationFrame(() => this.runHighlightOnRaf(selector)); + } + uninstall() { + if (this._rafRequest) + cancelAnimationFrame(this._rafRequest); this._glassPaneElement.remove(); } diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index ad016c5491..accc02bf45 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -956,7 +956,7 @@ export class InjectedScript { maskSelectors(selectors: ParsedSelector[]) { if (this._highlight) this.hideHighlight(); - this._highlight = new Highlight(this.isUnderTest); + this._highlight = new Highlight(this); this._highlight.install(); const elements = []; for (const selector of selectors) @@ -966,17 +966,10 @@ export class InjectedScript { highlight(selector: ParsedSelector) { if (!this._highlight) { - this._highlight = new Highlight(this.isUnderTest); + this._highlight = new Highlight(this); this._highlight.install(); } - this._runHighlightOnRaf(selector); - } - - _runHighlightOnRaf(selector: ParsedSelector) { - if (!this._highlight) - return; - this._highlight.updateHighlight(this.querySelectorAll(selector, document.documentElement), stringifySelector(selector), false); - requestAnimationFrame(() => this._runHighlightOnRaf(selector)); + this._highlight.runHighlightOnRaf(selector); } hideHighlight() { diff --git a/packages/playwright-core/src/server/injected/recorder.ts b/packages/playwright-core/src/server/injected/recorder.ts index 849b8425dc..4f1774cf47 100644 --- a/packages/playwright-core/src/server/injected/recorder.ts +++ b/packages/playwright-core/src/server/injected/recorder.ts @@ -46,7 +46,7 @@ class Recorder { constructor(injectedScript: InjectedScript) { this._injectedScript = injectedScript; - this._highlight = new Highlight(injectedScript.isUnderTest); + this._highlight = new Highlight(injectedScript); this._refreshListenersIfNeeded(); injectedScript.onGlobalListenersRemoved.add(() => this._refreshListenersIfNeeded()); diff --git a/packages/playwright-core/src/server/recorder.ts b/packages/playwright-core/src/server/recorder.ts index 243f8f343d..457c108dd1 100644 --- a/packages/playwright-core/src/server/recorder.ts +++ b/packages/playwright-core/src/server/recorder.ts @@ -54,11 +54,11 @@ export class Recorder implements InstrumentationListener { private _currentCallsMetadata = new Map(); private _recorderSources: Source[] = []; private _userSources = new Map(); - private _allMetadatas = new Map(); private _debugger: Debugger; private _contextRecorder: ContextRecorder; private _handleSIGINT: boolean | undefined; private _recorderAppFactory: (recorder: Recorder) => Promise; + private _omitCallTracking = false; static showInspector(context: BrowserContext) { Recorder.show(context, {}).catch(() => {}); @@ -79,6 +79,7 @@ export class Recorder implements InstrumentationListener { this._recorderAppFactory = recorderAppFactory; this._contextRecorder = new ContextRecorder(context, params); this._context = context; + this._omitCallTracking = !!params.omitCallTracking; this._debugger = Debugger.lookup(context)!; this._handleSIGINT = params.handleSIGINT; context.instrumentation.addListener(this, context); @@ -215,10 +216,9 @@ export class Recorder implements InstrumentationListener { } async onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata) { - if (this._mode === 'recording') + if (this._omitCallTracking || this._mode === 'recording') return; this._currentCallsMetadata.set(metadata, sdkObject); - this._allMetadatas.set(metadata.id, metadata); this._updateUserSources(); this.updateCallLog([metadata]); if (metadata.params && metadata.params.selector) { @@ -228,7 +228,7 @@ export class Recorder implements InstrumentationListener { } async onAfterCall(sdkObject: SdkObject, metadata: CallMetadata) { - if (this._mode === 'recording') + if (this._omitCallTracking || this._mode === 'recording') return; if (!metadata.error) this._currentCallsMetadata.delete(metadata);