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