Skip to content

Commit 3c00c87

Browse files
authored
fix(runner): correctly call test hooks and teardown functions (#7775)
1 parent 033ccc7 commit 3c00c87

File tree

3 files changed

+120
-19
lines changed

3 files changed

+120
-19
lines changed

packages/runner/src/run.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,31 @@ export function updateTask(event: TaskUpdateEvent, task: Task, runner: VitestRun
221221
sendTasksUpdateThrottled(runner)
222222
}
223223

224-
async function callCleanupHooks(cleanups: unknown[]) {
225-
await Promise.all(
226-
cleanups.map(async (fn) => {
224+
async function callCleanupHooks(runner: VitestRunner, cleanups: unknown[]) {
225+
const sequence = runner.config.sequence.hooks
226+
227+
if (sequence === 'stack') {
228+
cleanups = cleanups.slice().reverse()
229+
}
230+
231+
if (sequence === 'parallel') {
232+
await Promise.all(
233+
cleanups.map(async (fn) => {
234+
if (typeof fn !== 'function') {
235+
return
236+
}
237+
await fn()
238+
}),
239+
)
240+
}
241+
else {
242+
for (const fn of cleanups) {
227243
if (typeof fn !== 'function') {
228-
return
244+
continue
229245
}
230246
await fn()
231-
}),
232-
)
247+
}
248+
}
233249
}
234250

235251
export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
@@ -314,15 +330,6 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
314330
failTask(test.result, e, runner.config.diffOptions)
315331
}
316332

317-
// skipped with new PendingError
318-
if (test.result?.pending || test.result?.state === 'skip') {
319-
test.mode = 'skip'
320-
test.result = { state: 'skip', note: test.result?.note, pending: true }
321-
updateTask('test-finished', test, runner)
322-
setCurrentTest(undefined)
323-
return
324-
}
325-
326333
try {
327334
await runner.onTaskFinished?.(test)
328335
}
@@ -335,7 +342,7 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
335342
test.context,
336343
suite,
337344
])
338-
await callCleanupHooks(beforeEachCleanups)
345+
await callCleanupHooks(runner, beforeEachCleanups)
339346
await callFixtureCleanup(test.context)
340347
}
341348
catch (e) {
@@ -356,6 +363,20 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
356363
test.onFailed = undefined
357364
test.onFinished = undefined
358365

366+
// skipped with new PendingError
367+
if (test.result?.pending || test.result?.state === 'skip') {
368+
test.mode = 'skip'
369+
test.result = {
370+
state: 'skip',
371+
note: test.result?.note,
372+
pending: true,
373+
duration: now() - start,
374+
}
375+
updateTask('test-finished', test, runner)
376+
setCurrentTest(undefined)
377+
return
378+
}
379+
359380
if (test.result.state === 'pass') {
360381
break
361382
}
@@ -504,7 +525,7 @@ export async function runSuite(suite: Suite, runner: VitestRunner): Promise<void
504525

505526
try {
506527
await callSuiteHook(suite, suite, 'afterAll', runner, [suite])
507-
await callCleanupHooks(beforeAllCleanups)
528+
await callCleanupHooks(runner, beforeAllCleanups)
508529
}
509530
catch (e) {
510531
failTask(suite.result, e, runner.config.diffOptions)

test/cli/test/skip-note.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ test.for([
1717
})
1818

1919
expect(stderr).toBe('')
20-
expect(stdout).toContain('my skipped test [custom message]')
20+
expect(stdout).toMatch(/my skipped test (?:\d+ms )?\[custom message\]/)
2121

2222
expect(ctx).toBeDefined()
2323
const testTask = ctx!.state.getFiles()[0].tasks[0]

test/core/test/hooks.test.ts

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { afterAll, afterEach, beforeAll, beforeEach, expect, it, suite } from 'vitest'
1+
import { afterAll, afterEach, beforeAll, beforeEach, expect, it, onTestFinished, suite } from 'vitest'
22

33
let count = -1
44

@@ -103,3 +103,83 @@ suite('hooks cleanup', () => {
103103
expect(cleanUpCount).toBe(0)
104104
})
105105
})
106+
107+
suite('hooks cleanup order', () => {
108+
const order: string[] = []
109+
110+
beforeEach(() => {
111+
order.push('[a] beforeEach')
112+
return () => {
113+
order.push('[a] cleanup')
114+
}
115+
})
116+
117+
beforeEach(() => {
118+
order.push('[b] beforeEach')
119+
return () => {
120+
order.push('[b] cleanup')
121+
}
122+
})
123+
124+
it('one', () => {
125+
expect(order).toEqual([
126+
'[a] beforeEach',
127+
'[b] beforeEach',
128+
])
129+
})
130+
131+
afterAll(() => {
132+
expect(order).toEqual([
133+
'[a] beforeEach',
134+
'[b] beforeEach',
135+
'[b] cleanup',
136+
'[a] cleanup',
137+
])
138+
})
139+
})
140+
141+
suite('hooks are called for dynamically skipped tests', () => {
142+
const order: string[] = []
143+
144+
suite('tests', () => {
145+
beforeEach(() => {
146+
order.push('beforeEach')
147+
return () => {
148+
order.push('beforeEach cleanup')
149+
}
150+
})
151+
afterEach(() => {
152+
order.push('afterEach')
153+
})
154+
155+
beforeAll(() => {
156+
order.push('beforeAll')
157+
return () => {
158+
order.push('beforeAll cleanup')
159+
}
160+
})
161+
162+
afterAll(() => {
163+
order.push('afterAll')
164+
})
165+
166+
it('skipped', (ctx) => {
167+
onTestFinished(() => {
168+
order.push('onTestFinished')
169+
})
170+
ctx.skip()
171+
})
172+
})
173+
174+
it('order is correct', () => {
175+
expect(order).toEqual([
176+
'beforeAll',
177+
'beforeEach',
178+
'afterEach',
179+
'beforeEach cleanup',
180+
'onTestFinished',
181+
'afterAll',
182+
'beforeAll cleanup',
183+
])
184+
})
185+
})

0 commit comments

Comments
 (0)