Skip to content

Commit c90c943

Browse files
authored
fix(test.fail): expect() failure should not skip future tests (microsoft#26663)
We used to stop the worker that would skip future tests. Regressed in microsoft#11850. Fixes microsoft#26435.
1 parent 0406e45 commit c90c943

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

packages/playwright-test/src/worker/workerMain.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,28 +164,41 @@ export class WorkerMain extends ProcessRunner {
164164
}
165165

166166
unhandledError(error: Error | any) {
167+
const failWithFatalErrorAndStop = () => {
168+
if (!this._fatalErrors.length)
169+
this._fatalErrors.push(serializeError(error));
170+
void this._stop();
171+
};
172+
173+
// No current test - fatal error.
174+
if (!this._currentTest)
175+
return failWithFatalErrorAndStop();
176+
167177
// Usually, we do not differentiate between errors in the control flow
168178
// and unhandled errors - both lead to the test failing. This is good for regular tests,
169179
// so that you can, e.g. expect() from inside an event handler. The test fails,
170180
// and we restart the worker.
171-
//
181+
if (this._currentTest.expectedStatus !== 'failed') {
182+
this._currentTest._failWithError(serializeError(error), true /* isHardError */);
183+
void this._stop();
184+
return;
185+
}
186+
172187
// However, for tests marked with test.fail(), this is a problem. Unhandled error
173188
// could come either from the user test code (legit failure), or from a fixture or
174189
// a test runner. In the latter case, the worker state could be messed up,
175190
// and continuing to run tests in the same worker is problematic. Therefore,
176191
// we turn this into a fatal error and restart the worker anyway.
192+
//
177193
// The only exception is the expect() error that we still consider ok.
178194
const isExpectError = (error instanceof Error) && !!(error as any).matcherResult;
179-
const isCurrentTestExpectedToFail = this._currentTest?.expectedStatus === 'failed';
180-
const shouldConsiderAsTestError = isExpectError || !isCurrentTestExpectedToFail;
181-
if (this._currentTest && shouldConsiderAsTestError) {
195+
if (isExpectError) {
196+
// Note: do not stop the worker, because test marked with test.fail() that fails an assertion
197+
// is perfectly fine.
182198
this._currentTest._failWithError(serializeError(error), true /* isHardError */);
183199
} else {
184-
// No current test - fatal error.
185-
if (!this._fatalErrors.length)
186-
this._fatalErrors.push(serializeError(error));
200+
failWithFatalErrorAndStop();
187201
}
188-
void this._stop();
189202
}
190203

191204
private async _loadIfNeeded() {

tests/playwright-test/basic.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,35 @@ test('should allow unhandled expects in test.fail', async ({ runInlineTest }) =>
470470
expect(result.output).not.toContain(`Error: expect`);
471471
});
472472

473+
test('should not skip tests after test.fail', async ({ runInlineTest, server }) => {
474+
const result = await runInlineTest({
475+
'a.spec.ts': `
476+
import { test, expect } from '@playwright/test';
477+
test('failing', async ({}) => {
478+
test.fail();
479+
expect(Promise.resolve('a')).resolves.toBe('b');
480+
await new Promise(f => setTimeout(f, 1000));
481+
});
482+
`,
483+
'b.spec.ts': `
484+
import { test, expect } from '@playwright/test';
485+
test('passing', async ({}) => {
486+
console.log('b-passing');
487+
});
488+
`,
489+
'c.spec.ts': `
490+
import { test, expect } from '@playwright/test';
491+
test('passing', async ({}) => {
492+
console.log('c-passing');
493+
});
494+
`,
495+
}, { workers: '1' });
496+
expect(result.exitCode).toBe(0);
497+
expect(result.passed).toBe(3);
498+
expect(result.output).toContain('b-passing');
499+
expect(result.output).toContain('c-passing');
500+
});
501+
473502
test('should support describe.skip', async ({ runInlineTest }) => {
474503
const result = await runInlineTest({
475504
'nested-skip.spec.ts': `

0 commit comments

Comments
 (0)