Skip to content

Commit 1fee63f

Browse files
authoredJan 3, 2024
fix(runner): fix fixture cleanup for concurrent tests (#4827)
1 parent 58d3657 commit 1fee63f

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed
 

‎packages/runner/src/fixture.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,13 @@ export function mergeContextFixtures(fixtures: Record<string, any>, context: { f
4646
}
4747

4848
const fixtureValueMaps = new Map<TestContext, Map<FixtureItem, any>>()
49-
let cleanupFnArray = new Array<() => void | Promise<void>>()
49+
const cleanupFnArrayMap = new Map<TestContext, Array<() => void | Promise<void>>>()
5050

51-
export async function callFixtureCleanup() {
51+
export async function callFixtureCleanup(context: TestContext) {
52+
const cleanupFnArray = cleanupFnArrayMap.get(context) ?? []
5253
for (const cleanup of cleanupFnArray.reverse())
5354
await cleanup()
54-
cleanupFnArray = []
55+
cleanupFnArrayMap.delete(context)
5556
}
5657

5758
export function withFixtures(fn: Function, testContext?: TestContext) {
@@ -73,6 +74,10 @@ export function withFixtures(fn: Function, testContext?: TestContext) {
7374
fixtureValueMaps.set(context, new Map<FixtureItem, any>())
7475
const fixtureValueMap: Map<FixtureItem, any> = fixtureValueMaps.get(context)!
7576

77+
if (!cleanupFnArrayMap.has(context))
78+
cleanupFnArrayMap.set(context, [])
79+
const cleanupFnArray = cleanupFnArrayMap.get(context)!
80+
7681
const usedFixtures = fixtures.filter(({ prop }) => usedProps.includes(prop))
7782
const pendingFixtures = resolveDeps(usedFixtures)
7883

‎packages/runner/src/run.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ export async function runTest(test: Test | Custom, runner: VitestRunner) {
190190
try {
191191
await callSuiteHook(test.suite, test, 'afterEach', runner, [test.context, test.suite])
192192
await callCleanupHooks(beforeEachCleanups)
193-
await callFixtureCleanup()
193+
await callFixtureCleanup(test.context)
194194
}
195195
catch (e) {
196196
failTask(test.result, e, runner.config.diffOptions)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { afterAll, beforeEach, expect, test } from 'vitest'
2+
3+
// this test case might look exotic, but a few conditions were required to reproduce the reported bug.
4+
// such particular conditions are marked with "[repro]" in the comments.
5+
6+
let globalA = 0
7+
let globalB = 0
8+
9+
interface MyFixtures {
10+
a: number
11+
b: number
12+
}
13+
14+
export const myTest = test.extend<MyFixtures>({
15+
// [repro] fixture order must be { a, b } and not { b, a }
16+
a: async ({}, use) => {
17+
globalA++
18+
await new Promise<void>(resolve => setTimeout(resolve, 200)) // [repro] async fixture
19+
await use(globalA)
20+
},
21+
b: async ({}, use) => {
22+
globalB++
23+
await use(globalB)
24+
},
25+
})
26+
27+
// [repro] beforeEach uses only "b"
28+
beforeEach<MyFixtures>(({ b }) => {
29+
expect(b).toBeTypeOf('number')
30+
})
31+
32+
afterAll(() => {
33+
expect([globalA, globalB]).toEqual([2, 2])
34+
})
35+
36+
// [repro] concurrent test uses both "a" and "b"
37+
myTest.concurrent('test1', async ({ a, b }) => {
38+
expect(a).toBeTypeOf('number')
39+
expect(b).toBeTypeOf('number')
40+
})
41+
42+
myTest.concurrent('test2', async ({ a, b }) => {
43+
expect(a).toBeTypeOf('number')
44+
expect(b).toBeTypeOf('number')
45+
})

0 commit comments

Comments
 (0)
Please sign in to comment.