fix(runner): fail if worker cannot find some of the tests (#13666)

This commit is contained in:
Yury Semikhatsky 2022-04-25 09:05:40 -07:00 committed by GitHub
parent 3b159b45ff
commit 2e6ef8f622
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 1 deletions

View File

@ -279,7 +279,7 @@ export class Dispatcher {
// - there are no remaining
// - we are here not because something failed
// - no unrecoverable worker error
if (!remaining.length && !failedTestIds.size && !params.fatalErrors.length && !params.skipTestsDueToSetupFailure.length) {
if (!remaining.length && !failedTestIds.size && !params.fatalErrors.length && !params.skipTestsDueToSetupFailure.length && !params.fatalUnknownTestIds) {
if (this._isWorkerRedundant(worker))
worker.stop();
doneWithJob();
@ -322,6 +322,13 @@ export class Dispatcher {
}
};
if (params.fatalUnknownTestIds) {
const titles = params.fatalUnknownTestIds.map(testId => {
const test = this._testById.get(testId)!.test;
return test.titlePath().slice(1).join(' > ');
});
massSkipTestsFromRemaining(new Set(params.fatalUnknownTestIds), [{ message: `Unknown test(s) in worker:\n${titles.join('\n')}` }]);
}
if (params.fatalErrors.length) {
// In case of fatal errors, report first remaining test as failing with these errors,
// and all others as skipped.

View File

@ -78,6 +78,7 @@ export type RunPayload = {
export type DonePayload = {
fatalErrors: TestError[];
skipTestsDueToSetupFailure: string[]; // test ids
fatalUnknownTestIds?: string[];
};
export type TestOutputPayload = {

View File

@ -157,6 +157,7 @@ export class WorkerRunner extends EventEmitter {
async runTestGroup(runPayload: RunPayload) {
this._runFinished = new ManualPromise<void>();
const entries = new Map(runPayload.entries.map(e => [ e.testId, e ]));
let fatalUnknownTestIds;
try {
await this._loadIfNeeded();
const fileSuite = await this._loader.loadTestFile(runPayload.file, 'worker');
@ -178,6 +179,9 @@ export class WorkerRunner extends EventEmitter {
entries.delete(tests[i]._id);
await this._runTest(tests[i], entry.retry, tests[i + 1]);
}
} else {
fatalUnknownTestIds = runPayload.entries.map(e => e.testId);
this.stop();
}
} catch (e) {
// In theory, we should run above code without any errors.
@ -188,6 +192,7 @@ export class WorkerRunner extends EventEmitter {
const donePayload: DonePayload = {
fatalErrors: this._fatalErrors,
skipTestsDueToSetupFailure: [],
fatalUnknownTestIds
};
for (const test of this._skipRemainingTestsInSuite?.allTests() || []) {
if (entries.has(test._id))

View File

@ -248,3 +248,37 @@ test('should teardown workers that are redundant', async ({ runInlineTest }) =>
'%%worker teardown',
]);
});
test('should not hang if test suites in worker are inconsistent with runner', async ({ runInlineTest }) => {
const oldValue = process.env.TEST_WORKER_INDEX;
delete process.env.TEST_WORKER_INDEX;
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { name: 'project-name' };
`,
'names.js': `
exports.getNames = () => {
const inWorker = process.env.TEST_WORKER_INDEX !== undefined;
if (inWorker)
return ['foo'];
return ['foo', 'bar', 'baz'];
};
`,
'a.spec.js': `
const { test } = pwt;
const { getNames } = require('./names');
const names = getNames();
for (const index in names) {
test('Test ' + index + ' - ' + names[index], async () => {
});
}
`,
}, { 'workers': 1 });
process.env.TEST_WORKER_INDEX = oldValue;
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(1);
expect(result.failed).toBe(1);
expect(result.skipped).toBe(1);
expect(result.report.suites[0].specs[1].tests[0].results[0].error.message).toBe('Unknown test(s) in worker:\nproject-name > a.spec.js > Test 1 - bar\nproject-name > a.spec.js > Test 2 - baz');
});