diff --git a/packages/playwright/src/reporters/html.ts b/packages/playwright/src/reporters/html.ts index 8cad4e0eb21b9..2879d4ddf5d4f 100644 --- a/packages/playwright/src/reporters/html.ts +++ b/packages/playwright/src/reporters/html.ts @@ -87,7 +87,7 @@ class HtmlReporter extends EmptyReporter { this._attachmentsBaseURL = attachmentsBaseURL; const reportedWarnings = new Set(); for (const project of this.config.projects) { - if (outputFolder.startsWith(project.outputDir) || project.outputDir.startsWith(outputFolder)) { + if (this._isSubdirectory(outputFolder, project.outputDir) || this._isSubdirectory(project.outputDir, outputFolder)) { const key = outputFolder + '|' + project.outputDir; if (reportedWarnings.has(key)) continue; @@ -113,6 +113,11 @@ class HtmlReporter extends EmptyReporter { }; } + _isSubdirectory(parentDir: string, dir: string): boolean { + const relativePath = path.relative(parentDir, dir); + return !!relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath); + } + override onError(error: TestError): void { this._topLevelErrors.push(error); } diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 0f8505889e39a..beee86eebf79a 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -1094,6 +1094,26 @@ for (const useIntermediateMergeReport of [false] as const) { expect(output).toContain('html-report'); }); + test('it should only identify exact matches as clashing folders', async ({ runInlineTest, useIntermediateMergeReport }) => { + test.skip(useIntermediateMergeReport); + const result = await runInlineTest({ + 'playwright.config.ts': ` + module.exports = { + reporter: [['html', { outputFolder: 'test-results-html' }]] + } + `, + 'a.test.js': ` + import { test, expect } from '@playwright/test'; + test('passes', async ({}) => { + }); + `, + }); + expect(result.exitCode).toBe(0); + const output = result.output; + expect(output).not.toContain('Configuration Error'); + expect(output).toContain('test-results-html'); + }); + test.describe('report location', () => { test('with config should create report relative to config', async ({ runInlineTest, useIntermediateMergeReport }, testInfo) => { test.skip(useIntermediateMergeReport);