Skip to content

Commit 23f29ce

Browse files
authored
fix: always run onTestFinished in reverse order (#5598)
1 parent 780b187 commit 23f29ce

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

docs/api/index.md

+4
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,10 @@ test('performs an organization query', async () => {
10101010
})
10111011
```
10121012

1013+
::: tip
1014+
This hook is always called in reverse order and is not affected by [`sequence.hooks`](/config/#sequence-hooks) option.
1015+
:::
1016+
10131017
### onTestFailed
10141018

10151019
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.

docs/config/index.md

+4
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,10 @@ Changes the order in which hooks are executed.
18651865
- `list` will order all hooks in the order they are defined
18661866
- `parallel` will run hooks in a single group in parallel (hooks in parent suites will still run before the current suite's hooks)
18671867

1868+
::: tip
1869+
This option doesn't affect [`onTestFinished`](/api/#ontestfinished). It is always called in reverse order.
1870+
:::
1871+
18681872
#### sequence.setupFiles <Badge type="info">0.29.3+</Badge> {#sequence-setupfiles}
18691873

18701874
- **Type**: `'list' | 'parallel'`

packages/runner/src/run.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import limit from 'p-limit'
2+
import type { Awaitable } from '@vitest/utils'
23
import { getSafeTimers, shuffle } from '@vitest/utils'
34
import { processError } from '@vitest/utils/error'
45
import type { DiffOptions } from '@vitest/utils/diff'
@@ -33,6 +34,19 @@ function getSuiteHooks(suite: Suite, name: keyof SuiteHooks, sequence: SequenceH
3334
return hooks
3435
}
3536

37+
async function callTaskHooks(task: Task, hooks: ((result: TaskResult) => Awaitable<void>)[], sequence: SequenceHooks) {
38+
if (sequence === 'stack')
39+
hooks = hooks.slice().reverse()
40+
41+
if (sequence === 'parallel') {
42+
await Promise.all(hooks.map(fn => fn(task.result!)))
43+
}
44+
else {
45+
for (const fn of hooks)
46+
await fn(task.result!)
47+
}
48+
}
49+
3650
export async function callSuiteHook<T extends keyof SuiteHooks>(
3751
suite: Suite,
3852
currentTask: Task,
@@ -211,15 +225,15 @@ export async function runTest(test: Test | Custom, runner: VitestRunner) {
211225
}
212226

213227
try {
214-
await Promise.all(test.onFinished?.map(fn => fn(test.result!)) || [])
228+
await callTaskHooks(test, test.onFinished || [], 'stack')
215229
}
216230
catch (e) {
217231
failTask(test.result, e, runner.config.diffOptions)
218232
}
219233

220234
if (test.result.state === 'fail') {
221235
try {
222-
await Promise.all(test.onFailed?.map(fn => fn(test.result!)) || [])
236+
await callTaskHooks(test, test.onFailed || [], runner.config.sequence.hooks)
223237
}
224238
catch (e) {
225239
failTask(test.result, e, runner.config.diffOptions)

test/core/test/on-finished.test.ts

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expect, it, onTestFinished } from 'vitest'
22

33
const collected: any[] = []
4+
const multiple: any[] = []
45

56
it('on-finished regular', () => {
67
collected.push(1)
@@ -38,6 +39,23 @@ it.fails('failed finish context', (t) => {
3839
collected.push(null)
3940
})
4041

42+
it('multiple on-finished', () => {
43+
onTestFinished(() => {
44+
multiple.push(1)
45+
})
46+
onTestFinished(() => {
47+
multiple.push(2)
48+
})
49+
onTestFinished(async () => {
50+
await new Promise(r => setTimeout(r, 100))
51+
multiple.push(3)
52+
})
53+
onTestFinished(() => {
54+
multiple.push(4)
55+
})
56+
})
57+
4158
it('after', () => {
4259
expect(collected).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
60+
expect(multiple).toEqual([4, 3, 2, 1])
4361
})

0 commit comments

Comments
 (0)