From f8fbfe28fab91045b96826fd3c19099d8906a834 Mon Sep 17 00:00:00 2001 From: Dominik Deren Date: Thu, 28 Jan 2021 19:50:57 +0100 Subject: [PATCH] feat(trace viewer): Adds _debugName BrowserContextOption to let users define a name for their contexts (#5205) This change is adding a new property on the BrowserContextOptions class called `_debugName`. This property allows defining a user-friendly name for the browser context, and currently it is being used in one place, the Trace Viewer. When user provides the new value in the following way: ```typescript const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const context = await browser.newContext({ _traceDir: __dirname, _debugName: 'My custom testcase name' }); await context.close(); await browser.close(); })(); ``` The `_debugName` will be saved in the `*.trace` file for this browser context, on the `context-created` event, under the key `debugName`. Later, when such a trace is displayed using Trace Viewer, the `debugName` will be displayed in the dropdown in the top right part of the app instead of the actual trace filename. Fixes #5157. --- src/cli/traceViewer/traceModel.ts | 2 +- src/protocol/channels.ts | 6 ++++++ src/protocol/protocol.yml | 3 +++ src/protocol/validator.ts | 3 +++ src/server/types.ts | 1 + src/trace/traceTypes.ts | 1 + src/trace/tracer.ts | 1 + test/trace.spec.ts | 18 ++++++++++++++++++ 8 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/cli/traceViewer/traceModel.ts b/src/cli/traceViewer/traceModel.ts index 10c3046f7d340..9a6b10ef077f1 100644 --- a/src/cli/traceViewer/traceModel.ts +++ b/src/cli/traceViewer/traceModel.ts @@ -73,7 +73,7 @@ export function readTraceFile(events: trace.TraceEvent[], traceModel: TraceModel case 'context-created': { contextEntries.set(event.contextId, { filePath, - name: filePath.substring(filePath.lastIndexOf('/') + 1), + name: event.debugName || filePath.substring(filePath.lastIndexOf('/') + 1), startTime: Number.MAX_VALUE, endTime: Number.MIN_VALUE, created: event, diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index fb597d57eba55..4d65e25224203 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -298,6 +298,7 @@ export type BrowserTypeLaunchPersistentContextParams = { colorScheme?: 'light' | 'dark' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { @@ -360,6 +361,7 @@ export type BrowserTypeLaunchPersistentContextOptions = { colorScheme?: 'light' | 'dark' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { @@ -423,6 +425,7 @@ export type BrowserNewContextParams = { colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { @@ -475,6 +478,7 @@ export type BrowserNewContextOptions = { colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { @@ -2795,6 +2799,7 @@ export type AndroidDeviceLaunchBrowserParams = { colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { @@ -2839,6 +2844,7 @@ export type AndroidDeviceLaunchBrowserOptions = { colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, _traceDir?: string, + _debugName?: string, recordVideo?: { dir: string, size?: { diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index 0ed6b0e1f17ce..1ab915ce76cc3 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -373,6 +373,7 @@ BrowserType: - no-preference acceptDownloads: boolean? _traceDir: string? + _debugName: string? recordVideo: type: object? properties: @@ -445,6 +446,7 @@ Browser: - no-preference acceptDownloads: boolean? _traceDir: string? + _debugName: string? recordVideo: type: object? properties: @@ -2352,6 +2354,7 @@ AndroidDevice: - no-preference acceptDownloads: boolean? _traceDir: string? + _debugName: string? recordVideo: type: object? properties: diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 3759bcb5226ca..b7a70a113ff60 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -212,6 +212,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { colorScheme: tOptional(tEnum(['light', 'dark', 'no-preference'])), acceptDownloads: tOptional(tBoolean), _traceDir: tOptional(tString), + _debugName: tOptional(tString), recordVideo: tOptional(tObject({ dir: tString, size: tOptional(tObject({ @@ -255,6 +256,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), acceptDownloads: tOptional(tBoolean), _traceDir: tOptional(tString), + _debugName: tOptional(tString), recordVideo: tOptional(tObject({ dir: tString, size: tOptional(tObject({ @@ -1046,6 +1048,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), acceptDownloads: tOptional(tBoolean), _traceDir: tOptional(tString), + _debugName: tOptional(tString), recordVideo: tOptional(tObject({ dir: tString, size: tOptional(tObject({ diff --git a/src/server/types.ts b/src/server/types.ts index ccf7c5338cafd..e0970e79ff424 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -249,6 +249,7 @@ export type BrowserContextOptions = { }, proxy?: ProxySettings, _traceDir?: string, + _debugName?: string, }; export type EnvArray = { name: string, value: string }[]; diff --git a/src/trace/traceTypes.ts b/src/trace/traceTypes.ts index cfea1ba4275e5..5bd46a5d1d9eb 100644 --- a/src/trace/traceTypes.ts +++ b/src/trace/traceTypes.ts @@ -22,6 +22,7 @@ export type ContextCreatedTraceEvent = { deviceScaleFactor: number, isMobile: boolean, viewportSize?: { width: number, height: number }, + debugName?: string, }; export type ContextDestroyedTraceEvent = { diff --git a/src/trace/tracer.ts b/src/trace/tracer.ts index f476817702d8c..e72db046446c3 100644 --- a/src/trace/tracer.ts +++ b/src/trace/tracer.ts @@ -97,6 +97,7 @@ class ContextTracer implements SnapshotterDelegate, ActionListener { isMobile: !!context._options.isMobile, deviceScaleFactor: context._options.deviceScaleFactor || 1, viewportSize: context._options.viewport || undefined, + debugName: context._options._debugName, }; this._appendTraceEvent(event); this._snapshotter = new Snapshotter(context, this); diff --git a/test/trace.spec.ts b/test/trace.spec.ts index 07273acc4afa9..50fe81db8ba3e 100644 --- a/test/trace.spec.ts +++ b/test/trace.spec.ts @@ -35,6 +35,7 @@ it('should record trace', (test, { browserName, platform }) => { const contextEvent = traceEvents.find(event => event.type === 'context-created') as trace.ContextCreatedTraceEvent; expect(contextEvent).toBeTruthy(); + expect(contextEvent.debugName).toBeUndefined(); const contextId = contextEvent.contextId; const pageEvent = traceEvents.find(event => event.type === 'page-created') as trace.PageCreatedTraceEvent; @@ -84,6 +85,7 @@ it('should record trace with POST', (test, { browserName, platform }) => { const contextEvent = traceEvents.find(event => event.type === 'context-created') as trace.ContextCreatedTraceEvent; expect(contextEvent).toBeTruthy(); + expect(contextEvent.debugName).toBeUndefined(); const contextId = contextEvent.contextId; const pageEvent = traceEvents.find(event => event.type === 'page-created') as trace.PageCreatedTraceEvent; @@ -111,3 +113,19 @@ it('should record trace with POST', (test, { browserName, platform }) => { expect(fs.existsSync(path.join(traceDir, 'resources', resourceEvent.requestSha1))).toBe(true); expect(fs.existsSync(path.join(traceDir, 'resources', resourceEvent.responseSha1))).toBe(true); }); + +it('should record trace with a debugName', (test, { browserName, platform }) => { + test.fixme(); +}, async ({browser, testInfo, server}) => { + const traceDir = testInfo.outputPath('trace'); + const debugName = 'Custom testcase name'; + const context = await browser.newContext({ _traceDir: traceDir, _debugName: debugName } as any); + await context.close(); + const tracePath = path.join(traceDir, fs.readdirSync(traceDir).find(n => n.endsWith('.trace'))); + const traceFileContent = await fs.promises.readFile(tracePath, 'utf8'); + const traceEvents = traceFileContent.split('\n').filter(line => !!line).map(line => JSON.parse(line)) as trace.TraceEvent[]; + + const contextEvent = traceEvents.find(event => event.type === 'context-created') as trace.ContextCreatedTraceEvent; + expect(contextEvent).toBeTruthy(); + expect(contextEvent.debugName).toBe(debugName); +}); \ No newline at end of file