mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(test runner): do not show TimeoutError for unhandled rejection (#21971)
Unhandled error/rejection interrupts current test and produces a TimeoutError for it that should be ignored.
This commit is contained in:
parent
97d2c4a635
commit
120aaa777e
@ -53,6 +53,7 @@ export class TestInfoImpl implements TestInfo {
|
||||
readonly _traceEvents: trace.TraceEvent[] = [];
|
||||
readonly _onTestFailureImmediateCallbacks = new Map<() => Promise<void>, string>(); // fn -> title
|
||||
_didTimeout = false;
|
||||
_wasInterrupted = false;
|
||||
_lastStepId = 0;
|
||||
|
||||
// ------------ TestInfo fields ------------
|
||||
@ -184,7 +185,7 @@ export class TestInfoImpl implements TestInfo {
|
||||
const timeoutError = await this._timeoutManager.runWithTimeout(cb);
|
||||
// When interrupting, we arrive here with a timeoutError, but we should not
|
||||
// consider it a timeout.
|
||||
if (this.status !== 'interrupted' && timeoutError && !this._didTimeout) {
|
||||
if (!this._wasInterrupted && timeoutError && !this._didTimeout) {
|
||||
this._didTimeout = true;
|
||||
this.errors.push(timeoutError);
|
||||
// Do not overwrite existing failure upon hook/teardown timeout.
|
||||
@ -254,6 +255,15 @@ export class TestInfoImpl implements TestInfo {
|
||||
return step;
|
||||
}
|
||||
|
||||
_interrupt() {
|
||||
// Mark as interrupted so we can ignore TimeoutError thrown by interrupt() call.
|
||||
this._wasInterrupted = true;
|
||||
this._timeoutManager.interrupt();
|
||||
// Do not overwrite existing failure (for example, unhandled rejection) with "interrupted".
|
||||
if (this.status === 'passed')
|
||||
this.status = 'interrupted';
|
||||
}
|
||||
|
||||
_failWithError(error: TestInfoError, isHardError: boolean) {
|
||||
// Do not overwrite any previous hard errors.
|
||||
// Some (but not all) scenarios include:
|
||||
|
||||
@ -99,12 +99,7 @@ export class WorkerMain extends ProcessRunner {
|
||||
private _stop(): Promise<void> {
|
||||
if (!this._isStopped) {
|
||||
this._isStopped = true;
|
||||
|
||||
// Interrupt current action.
|
||||
this._currentTest?._timeoutManager.interrupt();
|
||||
|
||||
if (this._currentTest && this._currentTest.status === 'passed')
|
||||
this._currentTest.status = 'interrupted';
|
||||
this._currentTest?._interrupt();
|
||||
}
|
||||
return this._runFinished;
|
||||
}
|
||||
|
||||
@ -394,6 +394,24 @@ test('test.{skip,fixme} should define a skipped test', async ({ runInlineTest })
|
||||
expect(result.output).not.toContain('%%dontseethis');
|
||||
});
|
||||
|
||||
test('should report unhandled error during test and not report timeout', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('unhandled rejection', async () => {
|
||||
setTimeout(() => {
|
||||
throw new Error('Unhandled');
|
||||
}, 0);
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
});
|
||||
`,
|
||||
});
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.output).toContain('Error: Unhandled');
|
||||
expect(result.output).not.toContain('Test timeout of 30000ms exceeded');
|
||||
});
|
||||
|
||||
test('should report unhandled rejection during worker shutdown', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user