From 8933de48b091a7e71325fd1b4c8391cb2570faba Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 18 Feb 2026 10:47:57 +0100 Subject: [PATCH 1/3] fix(tracing): include source fo tracing.group(location) --- packages/playwright-core/src/client/tracing.ts | 6 +++++- tests/library/trace-viewer.spec.ts | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/playwright-core/src/client/tracing.ts b/packages/playwright-core/src/client/tracing.ts index a3c7bd53a3e0e..5e0d0bc16227e 100644 --- a/packages/playwright-core/src/client/tracing.ts +++ b/packages/playwright-core/src/client/tracing.ts @@ -58,7 +58,11 @@ export class Tracing extends ChannelOwner implements ap } async group(name: string, options: { location?: { file: string, line?: number, column?: number } } = {}) { - await this._channel.tracingGroup({ name, location: options.location }); + await this._wrapApiCall(async zone => { + if (options.location) + zone.frames.push({ file: options.location.file, line: options.location.line ?? 0, column: options.location.column ?? 0 }); + await this._channel.tracingGroup({ name, location: options.location }); + }); } async groupEnd() { diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index fdb1b0aff3925..656c0fa702d32 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -113,6 +113,10 @@ test('should open trace viewer on specific host', async ({ showTraceViewer }, te test('should show tracing.group in the action list with location', async ({ runAndTrace, page, context }) => { test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36483' }); + test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/39302' }); + + const sourceFile = test.info().outputPath('source.js'); + await fs.promises.writeFile(sourceFile, 'buddy beaver'); const traceViewer = await test.step('create trace with groups', async () => { await page.context().tracing.group('ignored group'); @@ -125,15 +129,21 @@ test('should show tracing.group in the action list with location', async ({ runA await context.tracing.group('inner group 2'); await expect(page.getByText('Hello')).toBeVisible(); await context.tracing.groupEnd(); + await context.tracing.group('inner group 3', { location: { file: sourceFile, line: 1, column: 1 } }); + await expect(page.getByText('Hello')).toBeVisible(); + await context.tracing.groupEnd(); await context.tracing.groupEnd(); }); }); + await fs.promises.rm(sourceFile); + await expect(traceViewer.actionTitles).toHaveText([ /outer group/, /Navigate/, /inner group 1 {{ eager_beaver }}/, /inner group 2/, + /inner group 3/, /toBeVisible/, ]); @@ -145,12 +155,16 @@ test('should show tracing.group in the action list with location', async ({ runA /inner group 1 {{ eager_beaver }}/, /Click.*locator/, /inner group 2/, + /inner group 3/, ]); await traceViewer.showSourceTab(); await expect(traceViewer.sourceCodeTab.locator('.source-line-running')).toHaveText(/DO NOT TOUCH THIS LINE/); await traceViewer.selectAction('inner group 2'); await expect(traceViewer.sourceCodeTab.locator('.source-line-running')).toContainText("await context.tracing.group('inner group 2');"); + + await traceViewer.selectAction('inner group 3'); + await expect(traceViewer.sourceCodeTab.locator('.source-line-running')).toContainText('buddy beaver'); }); test('should open simple trace viewer', async ({ showTraceViewer }) => { From 755f04467ee4de0701b44c8d9c8c6768edf83a37 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 23 Feb 2026 14:13:41 +0100 Subject: [PATCH 2/3] send array of additional sources --- packages/playwright-core/src/client/tracing.ts | 13 ++++++------- packages/playwright-core/src/protocol/validator.ts | 1 + packages/playwright-core/src/server/localUtils.ts | 4 ++-- packages/protocol/src/channels.d.ts | 1 + packages/protocol/src/protocol.yml | 3 +++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/playwright-core/src/client/tracing.ts b/packages/playwright-core/src/client/tracing.ts index 5e0d0bc16227e..83348fe727c84 100644 --- a/packages/playwright-core/src/client/tracing.ts +++ b/packages/playwright-core/src/client/tracing.ts @@ -22,6 +22,7 @@ import type * as channels from '@protocol/channels'; export class Tracing extends ChannelOwner implements api.Tracing { private _includeSources = false; + private _additionalSources = new Set(); private _isLive = false; _tracesDir: string | undefined; private _stacksId: string | undefined; @@ -58,11 +59,9 @@ export class Tracing extends ChannelOwner implements ap } async group(name: string, options: { location?: { file: string, line?: number, column?: number } } = {}) { - await this._wrapApiCall(async zone => { - if (options.location) - zone.frames.push({ file: options.location.file, line: options.location.line ?? 0, column: options.location.column ?? 0 }); - await this._channel.tracingGroup({ name, location: options.location }); - }); + if (options.location) + this._additionalSources.add(options.location.file); + await this._channel.tracingGroup({ name, location: options.location }); } async groupEnd() { @@ -110,7 +109,7 @@ export class Tracing extends ChannelOwner implements ap if (isLocal) { const result = await this._channel.tracingStopChunk({ mode: 'entries' }); - await localUtils.zip({ zipFile: filePath, entries: result.entries!, mode: 'write', stacksId: this._stacksId, includeSources: this._includeSources }); + await localUtils.zip({ zipFile: filePath, entries: result.entries!, mode: 'write', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources: [...this._additionalSources] }); return; } @@ -128,7 +127,7 @@ export class Tracing extends ChannelOwner implements ap await artifact.saveAs(filePath); await artifact.delete(); - await localUtils.zip({ zipFile: filePath, entries: [], mode: 'append', stacksId: this._stacksId, includeSources: this._includeSources }); + await localUtils.zip({ zipFile: filePath, entries: [], mode: 'append', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources: [...this._additionalSources] }); } _resetStackCounter() { diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 06622ef91f8a3..f40c09568780f 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -278,6 +278,7 @@ scheme.LocalUtilsZipParams = tObject({ stacksId: tOptional(tString), mode: tEnum(['write', 'append']), includeSources: tBoolean, + additionalSources: tArray(tString), }); scheme.LocalUtilsZipResult = tOptional(tObject({})); scheme.LocalUtilsHarOpenParams = tObject({ diff --git a/packages/playwright-core/src/server/localUtils.ts b/packages/playwright-core/src/server/localUtils.ts index 685a0f64f0f10..2a1cf62d5b1fd 100644 --- a/packages/playwright-core/src/server/localUtils.ts +++ b/packages/playwright-core/src/server/localUtils.ts @@ -67,7 +67,7 @@ export async function zip(progress: Progress, stackSessions: Map(); + const sourceFiles = new Set(params.additionalSources); for (const { stack } of stackSession?.callStacks || []) { if (!stack) continue; @@ -75,7 +75,7 @@ export async function zip(progress: Progress, stackSessions: Map Date: Wed, 25 Feb 2026 15:25:03 +0100 Subject: [PATCH 3/3] address --- packages/playwright-core/src/client/tracing.ts | 7 +++++-- packages/playwright-core/src/protocol/validator.ts | 2 +- packages/protocol/src/channels.d.ts | 3 ++- packages/protocol/src/protocol.yml | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/playwright-core/src/client/tracing.ts b/packages/playwright-core/src/client/tracing.ts index 83348fe727c84..f6f02a6fc7b8b 100644 --- a/packages/playwright-core/src/client/tracing.ts +++ b/packages/playwright-core/src/client/tracing.ts @@ -93,6 +93,9 @@ export class Tracing extends ChannelOwner implements ap private async _doStopChunk(filePath: string | undefined) { this._resetStackCounter(); + const additionalSources = [...this._additionalSources]; + this._additionalSources.clear(); + if (!filePath) { // Not interested in artifacts. await this._channel.tracingStopChunk({ mode: 'discard' }); @@ -109,7 +112,7 @@ export class Tracing extends ChannelOwner implements ap if (isLocal) { const result = await this._channel.tracingStopChunk({ mode: 'entries' }); - await localUtils.zip({ zipFile: filePath, entries: result.entries!, mode: 'write', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources: [...this._additionalSources] }); + await localUtils.zip({ zipFile: filePath, entries: result.entries!, mode: 'write', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources }); return; } @@ -127,7 +130,7 @@ export class Tracing extends ChannelOwner implements ap await artifact.saveAs(filePath); await artifact.delete(); - await localUtils.zip({ zipFile: filePath, entries: [], mode: 'append', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources: [...this._additionalSources] }); + await localUtils.zip({ zipFile: filePath, entries: [], mode: 'append', stacksId: this._stacksId, includeSources: this._includeSources, additionalSources }); } _resetStackCounter() { diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index f40c09568780f..b395a6cad7e99 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -278,7 +278,7 @@ scheme.LocalUtilsZipParams = tObject({ stacksId: tOptional(tString), mode: tEnum(['write', 'append']), includeSources: tBoolean, - additionalSources: tArray(tString), + additionalSources: tOptional(tArray(tString)), }); scheme.LocalUtilsZipResult = tOptional(tObject({})); scheme.LocalUtilsHarOpenParams = tObject({ diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index 610fc7b0c22e7..d401ed56544fa 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -477,10 +477,11 @@ export type LocalUtilsZipParams = { stacksId?: string, mode: 'write' | 'append', includeSources: boolean, - additionalSources: string[], + additionalSources?: string[], }; export type LocalUtilsZipOptions = { stacksId?: string, + additionalSources?: string[], }; export type LocalUtilsZipResult = void; export type LocalUtilsHarOpenParams = { diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index d6b1847300319..24880fc5947db 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -653,7 +653,7 @@ LocalUtils: - append includeSources: boolean additionalSources: - type: array + type: array? items: string harOpen: