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': `