Skip to content

Commit 0c2924b

Browse files
authoredMar 3, 2025··
fix(runner): fix beforeEach/All cleanup callback timeout (#7500)
1 parent 264feb6 commit 0c2924b

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed
 

‎packages/runner/src/hooks.ts

+22-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ function getDefaultHookTimeout() {
1818
return getRunner().config.hookTimeout
1919
}
2020

21+
const CLEANUP_TIMEOUT_KEY = Symbol.for('VITEST_CLEANUP_TIMEOUT')
22+
23+
export function getBeforeHookCleanupCallback(hook: Function, result: any): Function | undefined {
24+
if (typeof result === 'function') {
25+
const timeout
26+
= CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === 'number'
27+
? hook[CLEANUP_TIMEOUT_KEY]
28+
: getDefaultHookTimeout()
29+
return withTimeout(result, timeout, true)
30+
}
31+
}
32+
2133
/**
2234
* Registers a callback function to be executed once before all tests within the current suite.
2335
* This hook is useful for scenarios where you need to perform setup operations that are common to all tests in a suite, such as initializing a database connection or setting up a test environment.
@@ -35,11 +47,14 @@ function getDefaultHookTimeout() {
3547
* });
3648
* ```
3749
*/
38-
export function beforeAll(fn: BeforeAllListener, timeout?: number): void {
50+
export function beforeAll(
51+
fn: BeforeAllListener,
52+
timeout: number = getDefaultHookTimeout(),
53+
): void {
3954
assertTypes(fn, '"beforeAll" callback', ['function'])
4055
return getCurrentSuite().on(
4156
'beforeAll',
42-
withTimeout(fn, timeout ?? getDefaultHookTimeout(), true),
57+
Object.assign(withTimeout(fn, timeout, true), { [CLEANUP_TIMEOUT_KEY]: timeout }),
4358
)
4459
}
4560

@@ -87,12 +102,15 @@ export function afterAll(fn: AfterAllListener, timeout?: number): void {
87102
*/
88103
export function beforeEach<ExtraContext = object>(
89104
fn: BeforeEachListener<ExtraContext>,
90-
timeout?: number,
105+
timeout: number = getDefaultHookTimeout(),
91106
): void {
92107
assertTypes(fn, '"beforeEach" callback', ['function'])
93108
return getCurrentSuite<ExtraContext>().on(
94109
'beforeEach',
95-
withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true),
110+
Object.assign(
111+
withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true),
112+
{ [CLEANUP_TIMEOUT_KEY]: timeout },
113+
),
96114
)
97115
}
98116

‎packages/runner/src/run.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { processError } from '@vitest/utils/error'
2121
import { collectTests } from './collect'
2222
import { PendingError } from './errors'
2323
import { callFixtureCleanup } from './fixture'
24+
import { getBeforeHookCleanupCallback } from './hooks'
2425
import { getFn, getHooks } from './map'
2526
import { setCurrentTest } from './test-state'
2627
import { limitConcurrency } from './utils/limit-concurrency'
@@ -143,14 +144,18 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
143144
updateSuiteHookState(currentTask, name, 'run', runner)
144145
}
145146

147+
async function runHook(hook: Function) {
148+
return getBeforeHookCleanupCallback(hook, await hook(...args))
149+
}
150+
146151
if (sequence === 'parallel') {
147152
callbacks.push(
148-
...(await Promise.all(hooks.map(hook => (hook as any)(...args)))),
153+
...(await Promise.all(hooks.map(hook => runHook(hook)))),
149154
)
150155
}
151156
else {
152157
for (const hook of hooks) {
153-
callbacks.push(await (hook as any)(...args))
158+
callbacks.push(await runHook(hook))
154159
}
155160
}
156161

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { beforeEach, beforeAll, describe, test } from 'vitest';
2+
3+
describe('beforeEach cleanup timeout', () => {
4+
beforeEach(() => new Promise(() => {}), 101)
5+
test("ok", () => {})
6+
})
7+
8+
describe('beforeAll cleanup timeout', () => {
9+
beforeAll(() => new Promise(() => {}), 102)
10+
test("ok", () => {})
11+
})

‎test/cli/test/__snapshots__/fails.test.ts.snap

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ exports[`should fail hooks-fail-beforeAll.test.ts 1`] = `"TypeError: "beforeAll"
4242
4343
exports[`should fail hooks-fail-beforeEach.test.ts 1`] = `"TypeError: "beforeEach" callback value must be function, received "string""`;
4444
45+
exports[`should fail hooks-timeout-before-hook-cleanup-callback.test.ts 1`] = `
46+
"Error: Hook timed out in 101ms.
47+
Error: Hook timed out in 102ms."
48+
`;
49+
4550
exports[`should fail inline-snapshop-inside-each.test.ts 1`] = `
4651
"Error: InlineSnapshot cannot be used inside of test.each or describe.each
4752
Error: InlineSnapshot cannot be used inside of test.each or describe.each

0 commit comments

Comments
 (0)
Please sign in to comment.