From 19ba4abbf4aca463e9dac225ae598d1722a0ba11 Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Fri, 22 May 2026 05:14:36 -0700 Subject: [PATCH] fix(html-reporter): drop tag badge that duplicates the project chip When a test tag (e.g. @ad2) matches the active project name (e.g. project "ad2"), the HTML report rendered two identical badges side by side because ProjectAndTagLabelsView always rendered the full tag list next to the project chip. Strip any tag whose name equals the active project name (ignoring the leading @) before rendering the click view. Fixes: https://github.com/microsoft/playwright/issues/40938 --- packages/html-reporter/src/labels.tsx | 12 ++++++++-- tests/playwright-test/reporter-html.spec.ts | 25 +++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/html-reporter/src/labels.tsx b/packages/html-reporter/src/labels.tsx index 044e9ea074d9d..41b340a7d3ce0 100644 --- a/packages/html-reporter/src/labels.tsx +++ b/packages/html-reporter/src/labels.tsx @@ -46,12 +46,20 @@ export const ProjectAndTagLabelsView: React.FC<{ // We can have an empty project name if we have no projects specified in the config const hasProjectNames = projectNames.length > 0 && !!activeProjectName; - return (hasProjectNames || otherLabels.length > 0) && + // Drop tag labels that render identically to the project chip already shown next to them + // (e.g. project "ad2" plus tag "@ad2") to avoid a confusing duplicate badge. + const dedupedLabels = hasProjectNames ? otherLabels.filter(label => stripLeadingAt(label) !== activeProjectName) : otherLabels; + + return (hasProjectNames || dedupedLabels.length > 0) && {hasProjectNames && } - + ; }; +function stripLeadingAt(label: string): string { + return label.startsWith('@') ? label.slice(1) : label; +} + const LabelsClickView: React.FC<{ labels: string[], }> = ({ labels }) => { diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 5f84bdaabe10f..e4e2f2958636e 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -1843,6 +1843,31 @@ for (const useIntermediateMergeReport of [true, false] as const) { await expect(page.locator('.label')).toHaveText('webkit'); }); + test('tag matching project name should not duplicate the project badge', async ({ runInlineTest, showReport, page }) => { + const result = await runInlineTest({ + 'playwright.config.js': ` + module.exports = { + projects: [ + { name: 'ad2', use: { browserName: 'chromium' } }, + ], + }; + `, + 'a.test.js': ` + const { expect, test } = require('@playwright/test'); + test('pass', { tag: ['@ad2', '@smoke'] }, async ({}) => { + expect(1).toBe(1); + }); + `, + }, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' }); + + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + + await showReport(); + + await expect(page.locator('.test-file-test', { has: page.getByText('pass', { exact: true }) }).locator('.label')).toHaveText(['ad2', 'smoke']); + }); + test('project label should not show if there are no explicit projects', async ({ runInlineTest, showReport, page }) => { const result = await runInlineTest({ 'a.test.js': `