fix(test runner): make TestCase.id not depend on the path separator (#29010)

Fixes #28991.
This commit is contained in:
Dmitry Gozman 2024-01-16 13:32:47 -08:00 committed by GitHub
parent ab7d1b5e53
commit 775ef30e43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 13 deletions

View File

@ -52,3 +52,7 @@ export async function copyFileAndMakeWritable(from: string, to: string) {
export function sanitizeForFilePath(s: string) {
return s.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, '-');
}
export function toPosixPath(aPath: string): string {
return aPath.split(path.sep).join(path.posix.sep);
}

View File

@ -15,7 +15,7 @@
*/
import path from 'path';
import { calculateSha1 } from 'playwright-core/lib/utils';
import { calculateSha1, toPosixPath } from 'playwright-core/lib/utils';
import type { Suite, TestCase } from './test';
import type { FullProjectInternal } from './config';
import type { Matcher, TestFileFilter } from '../util';
@ -39,9 +39,10 @@ export function filterTestsRemoveEmptySuites(suite: Suite, filter: (test: TestCa
suite._entries = suite._entries.filter(e => entries.has(e)); // Preserve the order.
return !!suite._entries.length;
}
export function bindFileSuiteToProject(project: FullProjectInternal, suite: Suite): Suite {
const relativeFile = path.relative(project.project.testDir, suite.location!.file).split(path.sep).join('/');
const fileId = calculateSha1(relativeFile).slice(0, 20);
const relativeFile = path.relative(project.project.testDir, suite.location!.file);
const fileId = calculateSha1(toPosixPath(relativeFile)).slice(0, 20);
// Clone suite.
const result = suite._deepClone();
@ -51,7 +52,8 @@ export function bindFileSuiteToProject(project: FullProjectInternal, suite: Suit
result.forEachTest((test, suite) => {
suite._fileId = fileId;
// At the point of the query, suite is not yet attached to the project, so we only get file, describe and test titles.
const testIdExpression = `[project=${project.id}]${test.titlePath().join('\x1e')}`;
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${project.id}]${toPosixPath(file)}\x1e${titles.join('\x1e')}`;
const testId = fileId + '-' + calculateSha1(testIdExpression).slice(0, 20);
test.id = testId;
test._projectId = project.id;

View File

@ -20,11 +20,10 @@ import fs from 'fs';
import path from 'path';
import type { TransformCallback } from 'stream';
import { Transform } from 'stream';
import { toPosixPath } from './json';
import { codeFrameColumns } from '../transform/babelBundle';
import type { FullResult, FullConfig, Location, Suite, TestCase as TestCasePublic, TestResult as TestResultPublic, TestStep as TestStepPublic, TestError } from '../../types/testReporter';
import type { SuitePrivate } from '../../types/reporterPrivate';
import { HttpServer, assert, calculateSha1, copyFileAndMakeWritable, gracefullyProcessExitDoNotHang, removeFolders, sanitizeForFilePath } from 'playwright-core/lib/utils';
import { HttpServer, assert, calculateSha1, copyFileAndMakeWritable, gracefullyProcessExitDoNotHang, removeFolders, sanitizeForFilePath, toPosixPath } from 'playwright-core/lib/utils';
import { colors, formatError, formatResultFailure, stripAnsiEscapes } from './base';
import { resolveReporterOutputPath } from '../util';
import type { Metadata } from '../../types/test';

View File

@ -18,15 +18,10 @@ import fs from 'fs';
import path from 'path';
import type { FullConfig, TestCase, Suite, TestResult, TestError, TestStep, FullResult, Location, JSONReport, JSONReportSuite, JSONReportSpec, JSONReportTest, JSONReportTestResult, JSONReportTestStep, JSONReportError } from '../../types/testReporter';
import { formatError, prepareErrorStack } from './base';
import { MultiMap } from 'playwright-core/lib/utils';
import { assert } from 'playwright-core/lib/utils';
import { MultiMap, assert, toPosixPath } from 'playwright-core/lib/utils';
import { getProjectId } from '../common/config';
import EmptyReporter from './empty';
export function toPosixPath(aPath: string): string {
return aPath.split(path.sep).join(path.posix.sep);
}
class JSONReporter extends EmptyReporter {
config!: FullConfig;
suite!: Suite;

View File

@ -798,3 +798,29 @@ var import_test = __toModule(require("@playwright/test"));
});
});
}
test('should report a stable test.id', async ({ runInlineTest }) => {
const result = await runInlineTest({
'reporter.ts': `
class Reporter {
onTestBegin(test) {
console.log('\\n%%testbegin-' + test.id);
}
}
export default Reporter;
`,
'playwright.config.ts': `
module.exports = { reporter: [[ './reporter.ts' ]] };
`,
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('example test', async ({}) => {
});
`
}, { reporter: '', workers: 1 });
expect(result.exitCode).toBe(0);
expect(result.outputLines).toEqual([
'testbegin-20289bcdad95a5e18c38-8b63c3695b9c8bd62d98',
]);
});