mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(test runner): properly keep track of requireFile to support helpers/wrappers (#7243)
This fixes an issue where we incorrectly labeled and assigned ids for tests that declared tests in require'd files or used test wrappers. See new tests for examples.
This commit is contained in:
parent
b9c619206f
commit
6118d16edd
@ -82,7 +82,7 @@ export class Dispatcher {
|
|||||||
_filesSortedByWorkerHash(): DispatcherEntry[] {
|
_filesSortedByWorkerHash(): DispatcherEntry[] {
|
||||||
const entriesByWorkerHashAndFile = new Map<string, Map<string, DispatcherEntry>>();
|
const entriesByWorkerHashAndFile = new Map<string, Map<string, DispatcherEntry>>();
|
||||||
for (const fileSuite of this._suite.suites) {
|
for (const fileSuite of this._suite.suites) {
|
||||||
const file = fileSuite.file;
|
const file = fileSuite._requireFile;
|
||||||
for (const spec of fileSuite._allSpecs()) {
|
for (const spec of fileSuite._allSpecs()) {
|
||||||
for (const test of spec.tests) {
|
for (const test of spec.tests) {
|
||||||
let entriesByFile = entriesByWorkerHashAndFile.get(test._workerHash);
|
let entriesByFile = entriesByWorkerHashAndFile.get(test._workerHash);
|
||||||
|
@ -117,6 +117,7 @@ export class Loader {
|
|||||||
const revertBabelRequire = installTransform();
|
const revertBabelRequire = installTransform();
|
||||||
try {
|
try {
|
||||||
const suite = new Suite('');
|
const suite = new Suite('');
|
||||||
|
suite._requireFile = file;
|
||||||
suite.file = file;
|
suite.file = file;
|
||||||
setCurrentlyLoadingFileSuite(suite);
|
setCurrentlyLoadingFileSuite(suite);
|
||||||
require(file);
|
require(file);
|
||||||
|
@ -90,7 +90,7 @@ export class ProjectImpl {
|
|||||||
test._repeatEachIndex = i;
|
test._repeatEachIndex = i;
|
||||||
test._projectIndex = this.index;
|
test._projectIndex = this.index;
|
||||||
test._workerHash = `run${this.index}-${digest}-repeat${i}`;
|
test._workerHash = `run${this.index}-${digest}-repeat${i}`;
|
||||||
test._id = `${spec._ordinalInFile}@${spec.file}#run${this.index}-repeat${i}`;
|
test._id = `${spec._ordinalInFile}@${spec._requireFile}#run${this.index}-repeat${i}`;
|
||||||
spec.tests.push(test);
|
spec.tests.push(test);
|
||||||
tests.push(test);
|
tests.push(test);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ export class Runner {
|
|||||||
|
|
||||||
const fileSuites = new Map<string, Suite>();
|
const fileSuites = new Map<string, Suite>();
|
||||||
for (const fileSuite of rootSuite.suites)
|
for (const fileSuite of rootSuite.suites)
|
||||||
fileSuites.set(fileSuite.file, fileSuite);
|
fileSuites.set(fileSuite._requireFile, fileSuite);
|
||||||
|
|
||||||
const outputDirs = new Set<string>();
|
const outputDirs = new Set<string>();
|
||||||
const grepMatcher = createMatcher(config.grep);
|
const grepMatcher = createMatcher(config.grep);
|
||||||
@ -209,7 +209,7 @@ export class Runner {
|
|||||||
if (process.stdout.isTTY) {
|
if (process.stdout.isTTY) {
|
||||||
const workers = new Set();
|
const workers = new Set();
|
||||||
rootSuite.findTest(test => {
|
rootSuite.findTest(test => {
|
||||||
workers.add(test.spec.file + test._workerHash);
|
workers.add(test.spec._requireFile + test._workerHash);
|
||||||
});
|
});
|
||||||
console.log();
|
console.log();
|
||||||
const jobs = Math.min(config.workers, workers.size);
|
const jobs = Math.min(config.workers, workers.size);
|
||||||
|
@ -26,6 +26,7 @@ class Base {
|
|||||||
parent?: Suite;
|
parent?: Suite;
|
||||||
|
|
||||||
_only = false;
|
_only = false;
|
||||||
|
_requireFile: string = '';
|
||||||
|
|
||||||
constructor(title: string) {
|
constructor(title: string) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
@ -63,10 +63,11 @@ export class TestTypeImpl {
|
|||||||
throw errorWithCallLocation(`test() can only be called in a test file`);
|
throw errorWithCallLocation(`test() can only be called in a test file`);
|
||||||
const location = callLocation(suite.file);
|
const location = callLocation(suite.file);
|
||||||
|
|
||||||
const ordinalInFile = countByFile.get(suite.file) || 0;
|
const ordinalInFile = countByFile.get(suite._requireFile) || 0;
|
||||||
countByFile.set(location.file, ordinalInFile + 1);
|
countByFile.set(suite._requireFile, ordinalInFile + 1);
|
||||||
|
|
||||||
const spec = new Spec(title, fn, ordinalInFile, this);
|
const spec = new Spec(title, fn, ordinalInFile, this);
|
||||||
|
spec._requireFile = suite._requireFile;
|
||||||
spec.file = location.file;
|
spec.file = location.file;
|
||||||
spec.line = location.line;
|
spec.line = location.line;
|
||||||
spec.column = location.column;
|
spec.column = location.column;
|
||||||
@ -83,7 +84,8 @@ export class TestTypeImpl {
|
|||||||
const location = callLocation(suite.file);
|
const location = callLocation(suite.file);
|
||||||
|
|
||||||
const child = new Suite(title);
|
const child = new Suite(title);
|
||||||
child.file = suite.file;
|
child._requireFile = suite._requireFile;
|
||||||
|
child.file = location.file;
|
||||||
child.line = location.line;
|
child.line = location.line;
|
||||||
child.column = location.column;
|
child.column = location.column;
|
||||||
suite._addSuite(child);
|
suite._addSuite(child);
|
||||||
|
@ -184,7 +184,7 @@ export class WorkerRunner extends EventEmitter {
|
|||||||
const testId = test._id;
|
const testId = test._id;
|
||||||
|
|
||||||
const baseOutputDir = (() => {
|
const baseOutputDir = (() => {
|
||||||
const relativeTestFilePath = path.relative(this._project.config.testDir, spec.file.replace(/\.(spec|test)\.(js|ts)/, ''));
|
const relativeTestFilePath = path.relative(this._project.config.testDir, spec._requireFile.replace(/\.(spec|test)\.(js|ts)/, ''));
|
||||||
const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
|
const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
|
||||||
let testOutputDir = sanitizedRelativePath + '-' + sanitizeForFilePath(spec.title);
|
let testOutputDir = sanitizedRelativePath + '-' + sanitizeForFilePath(spec.title);
|
||||||
if (this._uniqueProjectNamePathSegment)
|
if (this._uniqueProjectNamePathSegment)
|
||||||
@ -231,7 +231,7 @@ export class WorkerRunner extends EventEmitter {
|
|||||||
else
|
else
|
||||||
snapshotName += suffix;
|
snapshotName += suffix;
|
||||||
}
|
}
|
||||||
return path.join(spec.file + '-snapshots', snapshotName);
|
return path.join(spec._requireFile + '-snapshots', snapshotName);
|
||||||
},
|
},
|
||||||
skip: (...args: [arg?: any, description?: string]) => modifier(testInfo, 'skip', args),
|
skip: (...args: [arg?: any, description?: string]) => modifier(testInfo, 'skip', args),
|
||||||
fixme: (...args: [arg?: any, description?: string]) => modifier(testInfo, 'fixme', args),
|
fixme: (...args: [arg?: any, description?: string]) => modifier(testInfo, 'fixme', args),
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { test, expect } from './playwright-test-fixtures';
|
import { test, expect, stripAscii } from './playwright-test-fixtures';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
test('should fail', async ({ runInlineTest }) => {
|
test('should fail', async ({ runInlineTest }) => {
|
||||||
@ -210,7 +210,7 @@ test('skip should take priority over fail', async ({ runInlineTest }) => {
|
|||||||
expect(failed).toBe(1);
|
expect(failed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should focus test from one runTests', async ({ runInlineTest }) => {
|
test('should focus test from one project', async ({ runInlineTest }) => {
|
||||||
const { exitCode, passed, skipped, failed } = await runInlineTest({
|
const { exitCode, passed, skipped, failed } = await runInlineTest({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@ -251,3 +251,103 @@ test('should work with default export', async ({ runInlineTest }) => {
|
|||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
expect(result.failed).toBe(0);
|
expect(result.failed).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should work with test wrapper', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'helper.js': `
|
||||||
|
console.log('%%helper');
|
||||||
|
exports.wrap = (title, fn) => {
|
||||||
|
pwt.test(title, fn);
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'a.spec.js': `
|
||||||
|
console.log('%%a.spec');
|
||||||
|
const { wrap } = require('./helper');
|
||||||
|
wrap('test1', () => {
|
||||||
|
console.log('%%test1');
|
||||||
|
});
|
||||||
|
pwt.test.describe('suite1', () => {
|
||||||
|
wrap('suite1.test1', () => {
|
||||||
|
console.log('%%suite1.test1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'b.spec.js': `
|
||||||
|
console.log('%%b.spec');
|
||||||
|
const { wrap } = require('./helper');
|
||||||
|
wrap('test2', () => {
|
||||||
|
console.log('%%test2');
|
||||||
|
});
|
||||||
|
pwt.test.describe('suite2', () => {
|
||||||
|
wrap('suite2.test2', () => {
|
||||||
|
console.log('%%suite2.test2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1, reporter: 'line' });
|
||||||
|
expect(result.passed).toBe(4);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(stripAscii(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||||
|
'%%a.spec',
|
||||||
|
'%%helper',
|
||||||
|
'%%b.spec',
|
||||||
|
'%%a.spec',
|
||||||
|
'%%helper',
|
||||||
|
'%%test1',
|
||||||
|
'%%suite1.test1',
|
||||||
|
'%%b.spec',
|
||||||
|
'%%test2',
|
||||||
|
'%%suite2.test2',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should work with test helper', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'helper-a.js': `
|
||||||
|
console.log('%%helper-a');
|
||||||
|
pwt.test('test1', () => {
|
||||||
|
console.log('%%test1');
|
||||||
|
});
|
||||||
|
pwt.test.describe('suite1', () => {
|
||||||
|
pwt.test('suite1.test1', () => {
|
||||||
|
console.log('%%suite1.test1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'a.spec.js': `
|
||||||
|
console.log('%%a.spec');
|
||||||
|
require('./helper-a');
|
||||||
|
`,
|
||||||
|
'helper-b.js': `
|
||||||
|
console.log('%%helper-b');
|
||||||
|
pwt.test('test1', () => {
|
||||||
|
console.log('%%test2');
|
||||||
|
});
|
||||||
|
pwt.test.describe('suite2', () => {
|
||||||
|
pwt.test('suite2.test2', () => {
|
||||||
|
console.log('%%suite2.test2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'b.spec.js': `
|
||||||
|
console.log('%%b.spec');
|
||||||
|
require('./helper-b');
|
||||||
|
`,
|
||||||
|
}, { workers: 1, reporter: 'line' });
|
||||||
|
expect(result.passed).toBe(4);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(stripAscii(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||||
|
'%%a.spec',
|
||||||
|
'%%helper-a',
|
||||||
|
'%%b.spec',
|
||||||
|
'%%helper-b',
|
||||||
|
'%%a.spec',
|
||||||
|
'%%helper-a',
|
||||||
|
'%%test1',
|
||||||
|
'%%suite1.test1',
|
||||||
|
'%%b.spec',
|
||||||
|
'%%helper-b',
|
||||||
|
'%%test2',
|
||||||
|
'%%suite2.test2',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user