fix(trace): don't replace unknown braces in action title (#36920)

This commit is contained in:
Simon Knott 2025-08-06 09:44:25 +02:00 committed by GitHub
parent 0385672ba6
commit ff3199a4ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 40 deletions

View File

@ -16,44 +16,51 @@
import { methodMetainfo } from './protocolMetainfo'; import { methodMetainfo } from './protocolMetainfo';
export function formatProtocolParam(params: Record<string, string> | undefined, name: string): string { export function formatProtocolParam(params: Record<string, string> | undefined, alternatives: string): string | undefined {
if (!params) if (!params)
return ''; return undefined;
if (name === 'url') {
try { for (const name of alternatives.split('|')) {
const urlObject = new URL(params[name]); if (name === 'url') {
if (urlObject.protocol === 'data:') try {
return urlObject.protocol; const urlObject = new URL(params[name]);
if (urlObject.protocol === 'about:') if (urlObject.protocol === 'data:')
return params[name]; return urlObject.protocol;
return urlObject.pathname + urlObject.search; if (urlObject.protocol === 'about:')
} catch (error) { return params[name];
return params[name]; return urlObject.pathname + urlObject.search;
} catch (error) {
if (params[name] !== undefined)
return params[name];
}
} }
if (name === 'timeNumber' && params[name] !== undefined) {
// eslint-disable-next-line no-restricted-globals
return new Date(params[name]).toString();
}
const value = deepParam(params, name);
if (value !== undefined)
return value;
} }
if (name === 'timeNumber') {
// eslint-disable-next-line no-restricted-globals
return new Date(params[name]).toString();
}
return deepParam(params, name);
} }
function deepParam(params: Record<string, any>, name: string): string { function deepParam(params: Record<string, any>, name: string): string | undefined {
const tokens = name.split('.'); const tokens = name.split('.');
let current = params; let current = params;
for (const token of tokens) { for (const token of tokens) {
if (typeof current !== 'object' || current === null) if (typeof current !== 'object' || current === null)
return ''; return undefined;
current = current[token]; current = current[token];
} }
if (current === undefined) if (current === undefined)
return ''; return undefined;
return String(current); return String(current);
} }
export function renderTitleForCall(metadata: { title?: string, type: string, method: string, params: Record<string, string> | undefined }) { export function renderTitleForCall(metadata: { title?: string, type: string, method: string, params: Record<string, string> | undefined }) {
const titleFormat = metadata.title ?? methodMetainfo.get(metadata.type + '.' + metadata.method)?.title ?? metadata.method; const titleFormat = metadata.title ?? methodMetainfo.get(metadata.type + '.' + metadata.method)?.title ?? metadata.method;
return titleFormat.replace(/\{([^}]+)\}/g, (_, p1) => { return titleFormat.replace(/\{([^}]+)\}/g, (fullMatch, p1) => {
return formatProtocolParam(metadata.params, p1); return formatProtocolParam(metadata.params, p1) ?? fullMatch;
}); });
} }

View File

@ -91,13 +91,13 @@ export const methodMetainfo = new Map<string, { internal?: boolean, title?: stri
['BrowserContext.harExport', { internal: true, }], ['BrowserContext.harExport', { internal: true, }],
['BrowserContext.createTempFiles', { internal: true, }], ['BrowserContext.createTempFiles', { internal: true, }],
['BrowserContext.updateSubscription', { internal: true, }], ['BrowserContext.updateSubscription', { internal: true, }],
['BrowserContext.clockFastForward', { title: 'Fast forward clock "{ticksNumber}{ticksString}"', }], ['BrowserContext.clockFastForward', { title: 'Fast forward clock "{ticksNumber|ticksString}"', }],
['BrowserContext.clockInstall', { title: 'Install clock "{timeNumber}{timeString}"', }], ['BrowserContext.clockInstall', { title: 'Install clock "{timeNumber|timeString}"', }],
['BrowserContext.clockPauseAt', { title: 'Pause clock "{timeNumber}{timeString}"', }], ['BrowserContext.clockPauseAt', { title: 'Pause clock "{timeNumber|timeString}"', }],
['BrowserContext.clockResume', { title: 'Resume clock', }], ['BrowserContext.clockResume', { title: 'Resume clock', }],
['BrowserContext.clockRunFor', { title: 'Run clock "{ticksNumber}{ticksString}"', }], ['BrowserContext.clockRunFor', { title: 'Run clock "{ticksNumber|ticksString}"', }],
['BrowserContext.clockSetFixedTime', { title: 'Set fixed time "{timeNumber}{timeString}"', }], ['BrowserContext.clockSetFixedTime', { title: 'Set fixed time "{timeNumber|timeString}"', }],
['BrowserContext.clockSetSystemTime', { title: 'Set system time "{timeNumber}{timeString}"', }], ['BrowserContext.clockSetSystemTime', { title: 'Set system time "{timeNumber|timeString}"', }],
['BrowserContext.clockUninstall', { title: 'Uninstall clock', }], ['BrowserContext.clockUninstall', { title: 'Uninstall clock', }],
['Page.addInitScript', { }], ['Page.addInitScript', { }],
['Page.close', { title: 'Close page', }], ['Page.close', { title: 'Close page', }],

View File

@ -1425,19 +1425,19 @@ BrowserContext:
enabled: boolean enabled: boolean
clockFastForward: clockFastForward:
title: Fast forward clock "{ticksNumber}{ticksString}" title: Fast forward clock "{ticksNumber|ticksString}"
parameters: parameters:
ticksNumber: float? ticksNumber: float?
ticksString: string? ticksString: string?
clockInstall: clockInstall:
title: Install clock "{timeNumber}{timeString}" title: Install clock "{timeNumber|timeString}"
parameters: parameters:
timeNumber: float? timeNumber: float?
timeString: string? timeString: string?
clockPauseAt: clockPauseAt:
title: Pause clock "{timeNumber}{timeString}" title: Pause clock "{timeNumber|timeString}"
parameters: parameters:
timeNumber: float? timeNumber: float?
timeString: string? timeString: string?
@ -1446,19 +1446,19 @@ BrowserContext:
title: Resume clock title: Resume clock
clockRunFor: clockRunFor:
title: Run clock "{ticksNumber}{ticksString}" title: Run clock "{ticksNumber|ticksString}"
parameters: parameters:
ticksNumber: float? ticksNumber: float?
ticksString: string? ticksString: string?
clockSetFixedTime: clockSetFixedTime:
title: Set fixed time "{timeNumber}{timeString}" title: Set fixed time "{timeNumber|timeString}"
parameters: parameters:
timeNumber: float? timeNumber: float?
timeString: string? timeString: string?
clockSetSystemTime: clockSetSystemTime:
title: Set system time "{timeNumber}{timeString}" title: Set system time "{timeNumber|timeString}"
parameters: parameters:
timeNumber: float? timeNumber: float?
timeString: string? timeString: string?

View File

@ -164,11 +164,16 @@ export function renderTitleForCall(action: ActionTraceEvent): { elements: React.
title.push(chunk); title.push(chunk);
const param = formatProtocolParam(action.params, quotedText); const param = formatProtocolParam(action.params, quotedText);
if (match.index === 0) if (param === undefined) {
elements.push(fullMatch);
title.push(fullMatch);
} else if (match.index === 0) {
elements.push(param); elements.push(param);
else title.push(param);
} else {
elements.push(<span className='action-title-param'>{param}</span>); elements.push(<span className='action-title-param'>{param}</span>);
title.push(param); title.push(param);
}
currentIndex = match.index + fullMatch.length; currentIndex = match.index + fullMatch.length;
} }

View File

@ -110,12 +110,14 @@ 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('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' });
const traceViewer = await test.step('create trace with groups', async () => { const traceViewer = await test.step('create trace with groups', async () => {
await page.context().tracing.group('ignored group'); await page.context().tracing.group('ignored group');
return await runAndTrace(async () => { return await runAndTrace(async () => {
await context.tracing.group('outer group'); await context.tracing.group('outer group');
await page.goto(`data:text/html,<!DOCTYPE html><body><div>Hello world</div></body>`); await page.goto(`data:text/html,<!DOCTYPE html><body><div>Hello world</div></body>`);
await context.tracing.group('inner group 1', { location: { file: __filename, line: 17, column: 1 } }); await context.tracing.group('inner group 1 {{ eager_beaver }}', { location: { file: __filename, line: 17, column: 1 } });
await page.locator('body').click(); await page.locator('body').click();
await context.tracing.groupEnd(); await context.tracing.groupEnd();
await context.tracing.group('inner group 2'); await context.tracing.group('inner group 2');
@ -128,7 +130,7 @@ test('should show tracing.group in the action list with location', async ({ runA
await expect(traceViewer.actionTitles).toHaveText([ await expect(traceViewer.actionTitles).toHaveText([
/outer group/, /outer group/,
/Navigate/, /Navigate/,
/inner group 1/, /inner group 1 {{ eager_beaver }}/,
/inner group 2/, /inner group 2/,
/toBeVisible/, /toBeVisible/,
]); ]);
@ -138,7 +140,7 @@ test('should show tracing.group in the action list with location', async ({ runA
await expect(traceViewer.actionTitles).toHaveText([ await expect(traceViewer.actionTitles).toHaveText([
/outer group/, /outer group/,
/Navigate/, /Navigate/,
/inner group 1/, /inner group 1 {{ eager_beaver }}/,
/Click.*locator/, /Click.*locator/,
/inner group 2/, /inner group 2/,
]); ]);