fix(test runner): make obtainWorker() resolve with null when stopping (#8018)

This ensures that we properly exit from `Dispatcher.run()`, print
epilogue and set the right exit code.
This commit is contained in:
Dmitry Gozman 2021-08-05 15:00:00 -07:00 committed by GitHub
parent 7da669bcc4
commit d846c05619
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 4 deletions

View file

@ -71,11 +71,11 @@ export class Dispatcher {
const testGroup = this._queue.shift()!;
const requiredHash = testGroup.workerHash;
let worker = await this._obtainWorker(testGroup);
while (!this._isStopped && worker.hash && worker.hash !== requiredHash) {
while (worker && worker.hash && worker.hash !== requiredHash) {
worker.stop();
worker = await this._obtainWorker(testGroup);
}
if (this._isStopped)
if (this._isStopped || !worker)
break;
jobs.push(this._runJob(worker, testGroup));
}
@ -182,6 +182,8 @@ export class Dispatcher {
async _obtainWorker(testGroup: TestGroup) {
const claimWorker = (): Promise<Worker> | null => {
if (this._isStopped)
return null;
// Use available worker.
if (this._freeWorkers.length)
return Promise.resolve(this._freeWorkers.pop()!);
@ -199,7 +201,7 @@ export class Dispatcher {
await new Promise<void>(f => this._workerClaimers.push(f));
worker = claimWorker();
}
return worker!;
return worker;
}
async _notifyWorkerClaimer() {
@ -294,6 +296,8 @@ export class Dispatcher {
worker.stop();
await result;
}
while (this._workerClaimers.length)
this._workerClaimers.shift()!();
}
private _hasReachedMaxFailures() {

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect } from './playwright-test-fixtures';
import { test, expect, stripAscii } from './playwright-test-fixtures';
test('max-failures should work', async ({ runInlineTest }) => {
const result = await runInlineTest({
@ -112,3 +112,34 @@ test('max-failures should stop workers', async ({ runInlineTest }) => {
expect(result.output).toContain('%%interrupted');
expect(result.output).not.toContain('%%skipped');
});
test('max-failures should properly shutdown', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
const config = {
testDir: './',
maxFailures: 1,
};
export default config;
`,
'test1.spec.ts': `
const { test } = pwt;
test.describe('spec 1', () => {
test('test 1', async () => {
expect(false).toBeTruthy()
})
});
`,
'test2.spec.ts': `
const { test } = pwt;
test.describe('spec 2', () => {
test('test 2', () => {
expect(true).toBeTruthy()
})
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(stripAscii(result.output)).toContain('expect(false).toBeTruthy()');
});