fix(test-runner): rely on test title paths instead of ordinal (#12414)

Fixes #11904
This commit is contained in:
Andrey Lushnikov 2022-02-28 16:40:23 -07:00 committed by GitHub
parent cb41e668fe
commit d744a87aee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 16 deletions

View File

@ -18,6 +18,7 @@ import type { FullProject, Fixtures, FixturesWithLocation } from './types';
import { Suite, TestCase } from './test';
import { FixturePool, isFixtureOption } from './fixtures';
import { TestTypeImpl } from './testType';
import { calculateSha1 } from 'playwright-core/lib/utils/utils';
export class ProjectImpl {
config: FullProject;
@ -64,19 +65,21 @@ export class ProjectImpl {
return this.testPools.get(test)!;
}
private _cloneEntries(from: Suite, to: Suite, repeatEachIndex: number, filter: (test: TestCase) => boolean): boolean {
private _cloneEntries(from: Suite, to: Suite, repeatEachIndex: number, filter: (test: TestCase) => boolean, relativeTitlePath: string): boolean {
for (const entry of from._entries) {
if (entry instanceof Suite) {
const suite = entry._clone();
to._addSuite(suite);
if (!this._cloneEntries(entry, suite, repeatEachIndex, filter)) {
if (!this._cloneEntries(entry, suite, repeatEachIndex, filter, relativeTitlePath + ' ' + suite.title)) {
to._entries.pop();
to.suites.pop();
}
} else {
const test = entry._clone();
test.retries = this.config.retries;
test._id = `${entry._ordinalInFile}@${entry._requireFile}#run${this.index}-repeat${repeatEachIndex}`;
// We rely upon relative paths being unique.
// See `getClashingTestsPerSuite()` in `runner.ts`.
test._id = `${calculateSha1(relativeTitlePath + ' ' + entry.title)}@${entry._requireFile}#run${this.index}-repeat${repeatEachIndex}`;
test.repeatEachIndex = repeatEachIndex;
test._projectIndex = this.index;
to._addTest(test);
@ -97,7 +100,7 @@ export class ProjectImpl {
cloneFileSuite(suite: Suite, repeatEachIndex: number, filter: (test: TestCase) => boolean): Suite | undefined {
const result = suite._clone();
return this._cloneEntries(suite, result, repeatEachIndex, filter) ? result : undefined;
return this._cloneEntries(suite, result, repeatEachIndex, filter, '') ? result : undefined;
}
private resolveFixtures(testType: TestTypeImpl, configUse: Fixtures): FixturesWithLocation[] {

View File

@ -128,17 +128,15 @@ export class TestCase extends Base implements reporterTypes.TestCase {
retries = 0;
repeatEachIndex = 0;
_ordinalInFile: number;
_testType: TestTypeImpl;
_id = '';
_workerHash = '';
_pool: FixturePool | undefined;
_projectIndex = 0;
constructor(title: string, fn: Function, ordinalInFile: number, testType: TestTypeImpl, location: Location) {
constructor(title: string, fn: Function, testType: TestTypeImpl, location: Location) {
super(title);
this.fn = fn;
this._ordinalInFile = ordinalInFile;
this._testType = testType;
this.location = location;
}
@ -166,7 +164,7 @@ export class TestCase extends Base implements reporterTypes.TestCase {
}
_clone(): TestCase {
const test = new TestCase(this.title, this.fn, this._ordinalInFile, this._testType, this.location);
const test = new TestCase(this.title, this.fn, this._testType, this.location);
test._only = this._only;
test._requireFile = this._requireFile;
test.expectedStatus = this.expectedStatus;

View File

@ -81,7 +81,7 @@ export class TestTypeImpl {
private _createTest(type: 'default' | 'only' | 'skip' | 'fixme', location: Location, title: string, fn: Function) {
throwIfRunningInsideJest();
const suite = this._ensureCurrentSuite(location, 'test()');
const test = new TestCase(title, fn, nextOrdinalInFile(suite._requireFile), this, location);
const test = new TestCase(title, fn, this, location);
test._requireFile = suite._requireFile;
suite._addTest(test);
@ -243,11 +243,4 @@ function throwIfRunningInsideJest() {
}
}
const countByFile = new Map<string, number>();
function nextOrdinalInFile(file: string) {
const ordinalInFile = countByFile.get(file) || 0;
countByFile.set(file, ordinalInFile + 1);
return ordinalInFile;
}
export const rootTestType = new TestTypeImpl([]);

View File

@ -407,3 +407,52 @@ test('should filter stack even without default Error.prepareStackTrace', async (
expect(stackLines.length).toBe(1);
});
test('should work with cross-imports - 1', async ({ runInlineTest }) => {
const result = await runInlineTest({
'test1.spec.ts': `
const { test } = pwt;
test('test 1', async ({}) => {
await new Promise(x => setTimeout(x, 500));
console.log('running TEST-1');
});
`,
'test2.spec.ts': `
import * as _ from './test1.spec';
const { test } = pwt;
test('test 2', async ({}) => {
await new Promise(x => setTimeout(x, 500));
console.log('running TEST-2');
});
`
}, { workers: 2 });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(2);
expect(result.failed).toBe(0);
expect(result.output).toContain('TEST-1');
expect(result.output).toContain('TEST-2');
});
test('should work with cross-imports - 2', async ({ runInlineTest }) => {
const result = await runInlineTest({
'test1.spec.ts': `
const { test } = pwt;
import * as _ from './test2.spec';
test('test 1', async ({}) => {
await new Promise(x => setTimeout(x, 500));
console.log('running TEST-1');
});
`,
'test2.spec.ts': `
const { test } = pwt;
test('test 2', async ({}) => {
await new Promise(x => setTimeout(x, 500));
console.log('running TEST-2');
});
`
}, { workers: 2, reporter: 'list' });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(2);
expect(result.failed).toBe(0);
expect(result.output).toContain('TEST-1');
expect(result.output).toContain('TEST-2');
});