|
| 1 | +import { createDefer } from '@vitest/utils' |
1 | 2 | import { getFixture } from './map'
|
2 | 3 | import type { TestContext } from './types'
|
3 | 4 |
|
@@ -78,49 +79,37 @@ export function withFixtures(fn: Function, testContext?: TestContext) {
|
78 | 79 | if (!pendingFixtures.length)
|
79 | 80 | return fn(context)
|
80 | 81 |
|
81 |
| - let cursor = 0 |
82 |
| - |
83 |
| - return new Promise((resolve, reject) => { |
84 |
| - async function use(fixtureValue: any) { |
85 |
| - const fixture = pendingFixtures[cursor++] |
86 |
| - context![fixture.prop] = fixtureValue |
87 |
| - |
88 |
| - if (!fixtureValueMap.has(fixture)) { |
89 |
| - fixtureValueMap.set(fixture, fixtureValue) |
90 |
| - cleanupFnArray.unshift(() => { |
91 |
| - fixtureValueMap.delete(fixture) |
92 |
| - }) |
93 |
| - } |
94 |
| - |
95 |
| - if (cursor < pendingFixtures.length) { |
96 |
| - await next() |
| 82 | + async function resolveFixtures() { |
| 83 | + for (const fixture of pendingFixtures) { |
| 84 | + // fixture could be already initialized during "before" hook |
| 85 | + if (fixtureValueMap.has(fixture)) |
| 86 | + continue |
| 87 | + |
| 88 | + let resolvedValue: unknown |
| 89 | + if (fixture.isFn) { |
| 90 | + // wait for `use` call to extract fixture value |
| 91 | + const useFnArgPromise = createDefer() |
| 92 | + fixture.value(context, async (useFnArg: unknown) => { |
| 93 | + useFnArgPromise.resolve(useFnArg) |
| 94 | + // suspend fixture teardown until cleanup |
| 95 | + const teardownPromise = createDefer<void>() |
| 96 | + cleanupFnArray.push(teardownPromise.resolve) |
| 97 | + await teardownPromise |
| 98 | + }).catch(useFnArgPromise.reject) // treat fixture function error (until `use` call) as test failure |
| 99 | + resolvedValue = await useFnArgPromise |
97 | 100 | }
|
98 | 101 | else {
|
99 |
| - // When all fixtures setup, call the test function |
100 |
| - try { |
101 |
| - resolve(await fn(context)) |
102 |
| - } |
103 |
| - catch (err) { |
104 |
| - reject(err) |
105 |
| - } |
106 |
| - return new Promise<void>((resolve) => { |
107 |
| - cleanupFnArray.push(resolve) |
108 |
| - }) |
| 102 | + resolvedValue = fixture.value |
109 | 103 | }
|
| 104 | + context![fixture.prop] = resolvedValue |
| 105 | + fixtureValueMap.set(fixture, resolvedValue) |
| 106 | + cleanupFnArray.unshift(() => { |
| 107 | + fixtureValueMap.delete(fixture) |
| 108 | + }) |
110 | 109 | }
|
| 110 | + } |
111 | 111 |
|
112 |
| - async function next() { |
113 |
| - const fixture = pendingFixtures[cursor] |
114 |
| - const { isFn, value } = fixture |
115 |
| - if (fixtureValueMap.has(fixture)) |
116 |
| - return use(fixtureValueMap.get(fixture)) |
117 |
| - else |
118 |
| - return isFn ? value(context, use) : use(value) |
119 |
| - } |
120 |
| - |
121 |
| - const setupFixturePromise = next().catch(reject) |
122 |
| - cleanupFnArray.unshift(() => setupFixturePromise) |
123 |
| - }) |
| 112 | + return resolveFixtures().then(() => fn(context)) |
124 | 113 | }
|
125 | 114 | }
|
126 | 115 |
|
|
0 commit comments