diff --git a/packages/playwright-test/src/workerRunner.ts b/packages/playwright-test/src/workerRunner.ts index 70841081f0..b227324536 100644 --- a/packages/playwright-test/src/workerRunner.ts +++ b/packages/playwright-test/src/workerRunner.ts @@ -393,8 +393,11 @@ export class WorkerRunner extends EventEmitter { // Run "afterAll" hooks for suites that are not shared with the next test. const nextSuites = new Set(getSuites(nextTest)); + // In case of failure the worker will be stopped and we have to make sure that afterAll + // hooks run before test fixtures teardown. + const isFailure = testInfo.status !== 'skipped' && testInfo.status !== testInfo.expectedStatus; for (const suite of reversedSuites) { - if (!nextSuites.has(suite)) { + if (!nextSuites.has(suite) || isFailure) { const afterAllError = await this._runAfterAllHooksForSuite(suite, testInfo); firstAfterHooksError = firstAfterHooksError || afterAllError; } diff --git a/tests/playwright-test/playwright.trace.spec.ts b/tests/playwright-test/playwright.trace.spec.ts index 5ccf498254..adcc69deb3 100644 --- a/tests/playwright-test/playwright.trace.spec.ts +++ b/tests/playwright-test/playwright.trace.spec.ts @@ -211,6 +211,37 @@ test('should work in serial mode', async ({ runInlineTest }, testInfo) => { expect(fs.existsSync(testInfo.outputPath('test-results', 'a-serial-fails', 'trace.zip'))).toBeTruthy(); }); +test('should not override trace file in afterAll', async ({ runInlineTest, server }, testInfo) => { + const result = await runInlineTest({ + 'playwright.config.ts': ` + module.exports = { use: { trace: 'retain-on-failure' } }; + `, + 'a.spec.ts': ` + const { test } = pwt; + + test('test 1', async ({ page }) => { + await page.goto('about:blank'); + throw 'oh no!'; + }); + + // Another test in the same file to affect after hooks order. + test('test 2', async ({}) => { + }); + + test.afterAll(async ({ request }) => { + await request.get('${server.EMPTY_PAGE}'); + }); + `, + }, { workers: 1 }); + + expect(result.exitCode).toBe(1); + expect(result.passed).toBe(1); + expect(result.failed).toBe(1); + expect(fs.existsSync(testInfo.outputPath('test-results', 'a-test-1', 'trace.zip'))).toBeTruthy(); + expect(fs.existsSync(testInfo.outputPath('test-results', 'a-test-1', 'trace-1.zip'))).toBeTruthy(); +}); + + async function parseTrace(file: string): Promise> { const zipFS = new ZipFileSystem(file); const resources = new Map();