diff --git a/src/test/worker.ts b/src/test/worker.ts index ab639c7144..9d0e20d6be 100644 --- a/src/test/worker.ts +++ b/src/test/worker.ts @@ -74,7 +74,7 @@ process.on('message', async message => { workerIndex = initParams.workerIndex; startProfiling(); workerRunner = new WorkerRunner(initParams); - for (const event of ['testBegin', 'testEnd', 'stepBegin', 'stepEnd', 'done']) + for (const event of ['testBegin', 'testEnd', 'stepBegin', 'stepEnd', 'done', 'teardownError']) workerRunner.on(event, sendMessageToParent.bind(null, event)); return; } diff --git a/src/test/workerRunner.ts b/src/test/workerRunner.ts index 421dba9654..54df37d327 100644 --- a/src/test/workerRunner.ts +++ b/src/test/workerRunner.ts @@ -76,8 +76,10 @@ export class WorkerRunner extends EventEmitter { await this._fixtureRunner.teardownScope('test'); await this._fixtureRunner.teardownScope('worker'); })(), this._deadline()); - if (result.timedOut) - throw new Error(`Timeout of ${this._project.config.timeout}ms exceeded while shutting down environment`); + if (result.timedOut && !this._fatalError) + this._fatalError = { message: colors.red(`Timeout of ${this._project.config.timeout}ms exceeded while shutting down environment`) }; + if (this._fatalError) + this.emit('teardownError', { error: this._fatalError }); } unhandledError(error: Error | any) { @@ -502,6 +504,7 @@ export class WorkerRunner extends EventEmitter { fatalError: this._fatalError, }; this.emit('done', donePayload); + this._fatalError = undefined; } } diff --git a/tests/playwright-test/basic.spec.ts b/tests/playwright-test/basic.spec.ts index 8a206a2d46..dcab594d77 100644 --- a/tests/playwright-test/basic.spec.ts +++ b/tests/playwright-test/basic.spec.ts @@ -382,3 +382,18 @@ test('test.skip should define a skipped test', async ({ runInlineTest }) => { expect(result.skipped).toBe(1); expect(result.output).not.toContain('%%dontseethis'); }); + +test('should report unhandled rejection during worker shutdown', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.test.ts': ` + const { test } = pwt; + test('unhandled rejection', async () => { + new Promise((f, r) => r(new Error('Unhandled'))); + }); + `, + }); + expect(result.exitCode).toBe(1); + expect(result.passed).toBe(1); + expect(result.output).toContain('Error: Unhandled'); + expect(result.output).toContain('a.test.ts:7:33'); +});