Skip to content

Commit 0c2924b

Browse files
authored
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

Lines changed: 22 additions & 4 deletions
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

Lines changed: 7 additions & 2 deletions
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

Lines changed: 11 additions & 0 deletions
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

Lines changed: 5 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy