From 23f29cea6491f3ecde8b885413f4c46989ab3bfc Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 23 Apr 2024 16:45:26 +0200 Subject: [PATCH] fix: always run `onTestFinished` in reverse order (#5598) --- docs/api/index.md | 4 ++++ docs/config/index.md | 4 ++++ packages/runner/src/run.ts | 18 ++++++++++++++++-- test/core/test/on-finished.test.ts | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/api/index.md b/docs/api/index.md index 46c204496e06..36817aea75b1 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -1010,6 +1010,10 @@ test('performs an organization query', async () => { }) ``` +::: tip +This hook is always called in reverse order and is not affected by [`sequence.hooks`](/config/#sequence-hooks) option. +::: + ### onTestFailed This hook is called only after the test has failed. It is called after `afterEach` hooks since they can influence the test result. It receives a `TaskResult` object with the current test result. This hook is useful for debugging. diff --git a/docs/config/index.md b/docs/config/index.md index 156db2bb69e2..a207e60958e9 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -1865,6 +1865,10 @@ Changes the order in which hooks are executed. - `list` will order all hooks in the order they are defined - `parallel` will run hooks in a single group in parallel (hooks in parent suites will still run before the current suite's hooks) +::: tip +This option doesn't affect [`onTestFinished`](/api/#ontestfinished). It is always called in reverse order. +::: + #### sequence.setupFiles 0.29.3+ {#sequence-setupfiles} - **Type**: `'list' | 'parallel'` diff --git a/packages/runner/src/run.ts b/packages/runner/src/run.ts index b0321fe6c06b..c0d55c414b21 100644 --- a/packages/runner/src/run.ts +++ b/packages/runner/src/run.ts @@ -1,4 +1,5 @@ import limit from 'p-limit' +import type { Awaitable } from '@vitest/utils' import { getSafeTimers, shuffle } from '@vitest/utils' import { processError } from '@vitest/utils/error' import type { DiffOptions } from '@vitest/utils/diff' @@ -33,6 +34,19 @@ function getSuiteHooks(suite: Suite, name: keyof SuiteHooks, sequence: SequenceH return hooks } +async function callTaskHooks(task: Task, hooks: ((result: TaskResult) => Awaitable)[], sequence: SequenceHooks) { + if (sequence === 'stack') + hooks = hooks.slice().reverse() + + if (sequence === 'parallel') { + await Promise.all(hooks.map(fn => fn(task.result!))) + } + else { + for (const fn of hooks) + await fn(task.result!) + } +} + export async function callSuiteHook( suite: Suite, currentTask: Task, @@ -211,7 +225,7 @@ export async function runTest(test: Test | Custom, runner: VitestRunner) { } try { - await Promise.all(test.onFinished?.map(fn => fn(test.result!)) || []) + await callTaskHooks(test, test.onFinished || [], 'stack') } catch (e) { failTask(test.result, e, runner.config.diffOptions) @@ -219,7 +233,7 @@ export async function runTest(test: Test | Custom, runner: VitestRunner) { if (test.result.state === 'fail') { try { - await Promise.all(test.onFailed?.map(fn => fn(test.result!)) || []) + await callTaskHooks(test, test.onFailed || [], runner.config.sequence.hooks) } catch (e) { failTask(test.result, e, runner.config.diffOptions) diff --git a/test/core/test/on-finished.test.ts b/test/core/test/on-finished.test.ts index 5f4f050d7534..83d049cf971f 100644 --- a/test/core/test/on-finished.test.ts +++ b/test/core/test/on-finished.test.ts @@ -1,6 +1,7 @@ import { expect, it, onTestFinished } from 'vitest' const collected: any[] = [] +const multiple: any[] = [] it('on-finished regular', () => { collected.push(1) @@ -38,6 +39,23 @@ it.fails('failed finish context', (t) => { collected.push(null) }) +it('multiple on-finished', () => { + onTestFinished(() => { + multiple.push(1) + }) + onTestFinished(() => { + multiple.push(2) + }) + onTestFinished(async () => { + await new Promise(r => setTimeout(r, 100)) + multiple.push(3) + }) + onTestFinished(() => { + multiple.push(4) + }) +}) + it('after', () => { expect(collected).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) + expect(multiple).toEqual([4, 3, 2, 1]) })