Skip to content

Commit 1621cc6

Browse files
authoredJul 3, 2023
feat: support accessing other fixtures in fixture function (#3651)
1 parent d77f712 commit 1621cc6

16 files changed

+395
-94
lines changed
 

‎docs/api/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ In Jest, `TestFunction` can also be of type `(done: DoneCallback) => void`. If t
7070
const archive = []
7171

7272
const myTest = test.extend({
73-
todos: async (use) => {
73+
todos: async ({ task }, use) => {
7474
todos.push(1, 2, 3)
7575
await use(todos)
7676
todos.length = 0

‎docs/guide/test-context.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const todos = []
5151
const archive = []
5252

5353
export const myTest = test.extend({
54-
todos: async (use) => {
54+
todos: async ({ task }, use) => {
5555
// setup the fixture before each test function
5656
todos.push(1, 2, 3)
5757

@@ -105,7 +105,7 @@ Vitest runner will smartly initialize your fixtures and inject them into the tes
105105
```ts
106106
import { test } from 'vitest'
107107

108-
async function todosFn(use) {
108+
async function todosFn({ task }, use) {
109109
await use([1, 2, 3])
110110
}
111111

@@ -115,15 +115,17 @@ const myTest = test.extend({
115115
})
116116

117117
// todosFn will not run
118-
myTest('', () => {}) // no fixture is available
119-
myTets('', ({ archive }) => {}) // only archive is available
118+
myTest('', () => {})
119+
myTets('', ({ archive }) => {})
120120

121121
// todosFn will run
122-
myTest('', ({ todos }) => {}) // only todos is available
123-
myTest('', (context) => {}) // both are available
124-
myTest('', ({ archive, ...rest }) => {}) // both are available
122+
myTest('', ({ todos }) => {})
125123
```
126124

125+
::: warning
126+
When using `test.extend()` with fixtures, you should always use the object destructuring pattern `{ todos }` to access context both in fixture function and test function.
127+
:::
128+
127129
#### TypeScript
128130

129131
To provide fixture types for all your custom contexts, you can pass the fixtures type as a generic.

‎packages/runner/src/fixture.ts

+114-39
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,141 @@
1-
import type { Fixtures, Test } from './types'
1+
import type { TestContext } from './types'
2+
3+
export interface FixtureItem {
4+
prop: string
5+
value: any
6+
index: number
7+
/**
8+
* Indicates whether the fixture is a function
9+
*/
10+
isFn: boolean
11+
/**
12+
* The dependencies(fixtures) of current fixture function.
13+
*/
14+
deps?: FixtureItem[]
15+
}
16+
17+
export function mergeContextFixtures(fixtures: Record<string, any>, context: { fixtures?: FixtureItem[] } = {}) {
18+
const fixtureArray: FixtureItem[] = Object.entries(fixtures)
19+
.map(([prop, value], index) => {
20+
const isFn = typeof value === 'function'
21+
return {
22+
prop,
23+
value,
24+
index,
25+
isFn,
26+
}
27+
})
28+
29+
if (Array.isArray(context.fixtures))
30+
context.fixtures = context.fixtures.concat(fixtureArray)
31+
else
32+
context.fixtures = fixtureArray
33+
34+
// Update dependencies of fixture functions
35+
fixtureArray.forEach((fixture) => {
36+
if (fixture.isFn) {
37+
const usedProps = getUsedProps(fixture.value)
38+
if (usedProps.length)
39+
fixture.deps = context.fixtures!.filter(({ index, prop }) => index !== fixture.index && usedProps.includes(prop))
40+
}
41+
})
242

3-
export function withFixtures(fn: Function, fixtures: Fixtures<Record<string, any>>, context: Test<Record<string, any>>['context']) {
4-
const props = getUsedFixtureProps(fn, Object.keys(fixtures))
43+
return context
44+
}
545

6-
if (props.length === 0)
46+
export function withFixtures(fn: Function, fixtures: FixtureItem[], context: TestContext & Record<string, any>) {
47+
if (!fixtures.length)
748
return () => fn(context)
849

50+
const usedProps = getUsedProps(fn)
51+
if (!usedProps.length)
52+
return () => fn(context)
53+
54+
const usedFixtures = fixtures.filter(({ prop }) => usedProps.includes(prop))
55+
const pendingFixtures = resolveDeps(usedFixtures)
956
let cursor = 0
1057

1158
async function use(fixtureValue: any) {
12-
context[props[cursor++]] = fixtureValue
13-
14-
if (cursor < props.length)
59+
const { prop } = pendingFixtures[cursor++]
60+
context[prop] = fixtureValue
61+
if (cursor < pendingFixtures.length)
1562
await next()
1663
else await fn(context)
1764
}
1865

1966
async function next() {
20-
const fixtureValue = fixtures[props[cursor]]
21-
typeof fixtureValue === 'function'
22-
? await fixtureValue(use)
23-
: await use(fixtureValue)
67+
const { value } = pendingFixtures[cursor]
68+
typeof value === 'function' ? await value(context, use) : await use(value)
2469
}
2570

2671
return () => next()
2772
}
2873

29-
function getUsedFixtureProps(fn: Function, fixtureProps: string[]) {
30-
if (!fixtureProps.length || !fn.length)
31-
return []
74+
function resolveDeps(fixtures: FixtureItem[], depSet = new Set<FixtureItem>(), pendingFixtures: FixtureItem[] = []) {
75+
fixtures.forEach((fixture) => {
76+
if (pendingFixtures.includes(fixture))
77+
return
78+
if (!fixture.isFn || !fixture.deps) {
79+
pendingFixtures.push(fixture)
80+
return
81+
}
82+
if (depSet.has(fixture))
83+
throw new Error('circular fixture dependency')
3284

33-
const paramsStr = fn.toString().match(/[^(]*\(([^)]*)/)![1]
85+
depSet.add(fixture)
86+
resolveDeps(fixture.deps, depSet, pendingFixtures)
87+
pendingFixtures.push(fixture)
88+
depSet.clear()
89+
})
3490

35-
if (paramsStr[0] === '{' && paramsStr.at(-1) === '}') {
36-
// ({...}) => {}
37-
const props = paramsStr.slice(1, -1).split(',')
38-
const filteredProps = []
91+
return pendingFixtures
92+
}
3993

40-
for (const prop of props) {
41-
if (!prop)
42-
continue
94+
function getUsedProps(fn: Function) {
95+
const match = fn.toString().match(/[^(]*\(([^)]*)/)
96+
if (!match)
97+
return []
4398

44-
let _prop = prop.trim()
99+
const args = splitByComma(match[1])
100+
if (!args.length)
101+
return []
45102

46-
if (_prop.startsWith('...')) {
47-
// ({ a, b, ...rest }) => {}
48-
return fixtureProps
49-
}
103+
const first = args[0]
104+
if (!(first.startsWith('{') && first.endsWith('}')))
105+
throw new Error('the first argument must use object destructuring pattern')
50106

51-
const colonIndex = _prop.indexOf(':')
52-
if (colonIndex > 0)
53-
_prop = _prop.slice(0, colonIndex).trim()
107+
const _first = first.slice(1, -1).replace(/\s/g, '')
108+
const props = splitByComma(_first).map((prop) => {
109+
return prop.replace(/\:.*|\=.*/g, '')
110+
})
54111

55-
if (fixtureProps.includes(_prop))
56-
filteredProps.push(_prop)
57-
}
112+
const last = props.at(-1)
113+
if (last && last.startsWith('...'))
114+
throw new Error('Rest parameters are not supported')
58115

59-
// ({}) => {}
60-
// ({ a, b, c}) => {}
61-
return filteredProps
62-
}
116+
return props
117+
}
63118

64-
// (ctx) => {}
65-
return fixtureProps
119+
function splitByComma(s: string) {
120+
const result = []
121+
const stack = []
122+
let start = 0
123+
for (let i = 0; i < s.length; i++) {
124+
if (s[i] === '{' || s[i] === '[') {
125+
stack.push(s[i] === '{' ? '}' : ']')
126+
}
127+
else if (s[i] === stack[stack.length - 1]) {
128+
stack.pop()
129+
}
130+
else if (!stack.length && s[i] === ',') {
131+
const token = s.substring(start, i).trim()
132+
if (token)
133+
result.push(token)
134+
start = i + 1
135+
}
136+
}
137+
const lastToken = s.substring(start).trim()
138+
if (lastToken)
139+
result.push(lastToken)
140+
return result
66141
}

‎packages/runner/src/suite.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import type { VitestRunner } from './types/runner'
44
import { createChainable } from './utils/chain'
55
import { collectTask, collectorContext, createTestContext, runWithSuite, withTimeout } from './context'
66
import { getHooks, setFn, setHooks } from './map'
7-
import { withFixtures } from './fixture'
7+
import type { FixtureItem } from './fixture'
8+
import { mergeContextFixtures, withFixtures } from './fixture'
89

910
// apis
1011
export const suite = createSuite()
@@ -232,7 +233,7 @@ function createSuite() {
232233

233234
function createTest(fn: (
234235
(
235-
this: Record<'concurrent' | 'skip' | 'only' | 'todo' | 'fails' | 'each', boolean | undefined> & { fixtures?: Fixtures<Record<string, any>> },
236+
this: Record<'concurrent' | 'skip' | 'only' | 'todo' | 'fails' | 'each', boolean | undefined> & { fixtures?: FixtureItem[] },
236237
title: string,
237238
fn?: TestFunction,
238239
options?: number | TestOptions
@@ -266,20 +267,22 @@ function createTest(fn: (
266267
testFn.runIf = (condition: any) => (condition ? test : test.skip) as TestAPI
267268

268269
testFn.extend = function (fixtures: Fixtures<Record<string, any>>) {
269-
const _context = context
270-
? { ...context, fixtures: { ...context.fixtures, ...fixtures } }
271-
: { fixtures }
270+
const _context = mergeContextFixtures(fixtures, context)
272271

273272
return createTest(function fn(name: string | Function, fn?: TestFunction, options?: number | TestOptions) {
274273
getCurrentSuite().test.fn.call(this, formatName(name), fn, options)
275274
}, _context)
276275
}
277276

278-
return createChainable(
277+
const _test = createChainable(
279278
['concurrent', 'skip', 'only', 'todo', 'fails'],
280279
testFn,
281-
context,
282280
) as TestAPI
281+
282+
if (context)
283+
(_test as any).mergeContext(context)
284+
285+
return _test
283286
}
284287

285288
function formatName(name: string | Function) {

‎packages/runner/src/types/tasks.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,20 @@ export type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & {
182182
each: TestEachFunction
183183
skipIf(condition: any): ChainableTestAPI<ExtraContext>
184184
runIf(condition: any): ChainableTestAPI<ExtraContext>
185-
extend<T extends Record<string, any>>(fixtures: Fixtures<T>): TestAPI<ExtraContext & T>
185+
extend<T extends Record<string, any> = {}>(fixtures: Fixtures<T, ExtraContext>): TestAPI<{
186+
[K in keyof T | keyof ExtraContext]:
187+
K extends keyof T ? T[K] :
188+
K extends keyof ExtraContext ? ExtraContext[K] : never }>
186189
}
187190

188-
export type Fixtures<T extends Record<string, any>> = {
189-
[K in keyof T]: T[K] | ((use: (fixture: T[K]) => Promise<void>) => Promise<void>)
191+
export type Fixtures<T extends Record<string, any>, ExtraContext = {}> = {
192+
[K in keyof T]: T[K] | ((context: {
193+
[P in keyof T | keyof ExtraContext as P extends K ?
194+
P extends keyof ExtraContext ? P : never : P
195+
]:
196+
K extends P ? K extends keyof ExtraContext ? ExtraContext[K] : never :
197+
P extends keyof T ? T[P] : never
198+
} & TestContext, use: (fixture: T[K]) => Promise<void>) => Promise<void>)
190199
}
191200

192201
type ChainableSuiteAPI<ExtraContext = {}> = ChainableFunction<

‎packages/runner/src/utils/chain.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export type ChainableFunction<T extends string, Args extends any[], R = any, E =
99
export function createChainable<T extends string, Args extends any[], R = any, E = {}>(
1010
keys: T[],
1111
fn: (this: Record<T, any>, ...args: Args) => R,
12-
initialContext?: Record<T, any>,
1312
): ChainableFunction<T, Args, R, E> {
1413
function create(context: Record<T, any>) {
1514
const chain = function (this: any, ...args: Args) {
@@ -20,6 +19,9 @@ export function createChainable<T extends string, Args extends any[], R = any, E
2019
chain.setContext = (key: T, value: any) => {
2120
context[key] = value
2221
}
22+
chain.mergeContext = (ctx: Record<T, any>) => {
23+
Object.assign(context, ctx)
24+
}
2325
for (const key of keys) {
2426
Object.defineProperty(chain, key, {
2527
get() {
@@ -30,7 +32,7 @@ export function createChainable<T extends string, Args extends any[], R = any, E
3032
return chain
3133
}
3234

33-
const chain = create(initialContext || {} as any) as any
35+
const chain = create({} as any) as any
3436
chain.fn = fn
3537
return chain
3638
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { describe, expect, expectTypeOf, test, vi } from 'vitest'
2+
3+
interface Fixtures {
4+
a: number
5+
b: number
6+
c: number
7+
d: number
8+
}
9+
10+
const fnB = vi.fn()
11+
const myTest = test.extend<Pick<Fixtures, 'a' | 'b'>>({
12+
a: 1,
13+
b: async ({ a }, use) => {
14+
fnB()
15+
await use (a * 2) // 2
16+
fnB.mockClear()
17+
},
18+
})
19+
20+
const fnA = vi.fn()
21+
const fnB2 = vi.fn()
22+
const fnC = vi.fn()
23+
const fnD = vi.fn()
24+
const myTest2 = myTest.extend<Pick<Fixtures, 'c' | 'd'> & { a: string; b: string }>({
25+
// override origin a
26+
a: async ({ a: originA }, use) => {
27+
expectTypeOf(originA).toEqualTypeOf<number>()
28+
fnA()
29+
await use(String(originA)) // '1'
30+
fnA.mockClear()
31+
},
32+
b: async ({ a }, use) => {
33+
expectTypeOf(a).toEqualTypeOf<string>()
34+
fnB2()
35+
await use(String(Number(a) * 2)) // '2'
36+
fnB2.mockClear()
37+
},
38+
c: async ({ a, b }, use) => {
39+
expectTypeOf(b).toEqualTypeOf<string>()
40+
fnC()
41+
await use(Number(a) + Number(b)) // 3
42+
fnC.mockClear()
43+
},
44+
d: async ({ a, b, c }, use) => {
45+
fnD()
46+
await use(Number(a) + Number(b) + c) // 6
47+
fnD.mockClear()
48+
},
49+
})
50+
51+
describe('fixture initialization', () => {
52+
describe('fixture override', () => {
53+
myTest('origin a and b', ({ a, b }) => {
54+
expect(a).toBe(1)
55+
expect(b).toBe(2)
56+
57+
expectTypeOf(a).toEqualTypeOf<number>()
58+
expectTypeOf(b).toEqualTypeOf<number>()
59+
60+
expect(fnB).toBeCalledTimes(1)
61+
62+
expect(fnB2).not.toBeCalled()
63+
expect(fnA).not.toBeCalled()
64+
expect(fnC).not.toBeCalled()
65+
expect(fnD).not.toBeCalled()
66+
})
67+
68+
myTest2('overriding a and b', ({ a, b }) => {
69+
expect(a).toBe('1')
70+
expect(b).toBe('2')
71+
72+
expectTypeOf(a).toEqualTypeOf<string>()
73+
expectTypeOf(b).toEqualTypeOf<string>()
74+
75+
expect(fnA).toBeCalledTimes(1)
76+
expect(fnB).toBeCalledTimes(1)
77+
expect(fnB2).toBeCalledTimes(1)
78+
79+
expect(fnC).not.toBeCalled()
80+
expect(fnD).not.toBeCalled()
81+
})
82+
})
83+
84+
describe('fixture dependency', () => {
85+
myTest2('b => a', ({ b }) => {
86+
expect(b).toBe('2')
87+
88+
expect(fnA).toBeCalledTimes(1)
89+
expect(fnB).toBeCalledTimes(1)
90+
expect(fnB2).toBeCalledTimes(1)
91+
92+
expect(fnC).not.toBeCalled()
93+
expect(fnD).not.toBeCalled()
94+
})
95+
96+
myTest2('c => [a, b]', ({ c }) => {
97+
expect(c).toBe(3)
98+
99+
expect(fnA).toBeCalledTimes(1)
100+
expect(fnB).toBeCalledTimes(1)
101+
expect(fnB2).toBeCalledTimes(1)
102+
expect(fnC).toBeCalledTimes(1)
103+
104+
expect(fnD).not.toBeCalled()
105+
})
106+
107+
myTest2('d => c', ({ d }) => {
108+
expect(d).toBe(6)
109+
110+
expect(fnA).toBeCalledTimes(1)
111+
expect(fnB).toBeCalledTimes(1)
112+
expect(fnB2).toBeCalledTimes(1)
113+
expect(fnC).toBeCalledTimes(1)
114+
expect(fnD).toBeCalledTimes(1)
115+
})
116+
117+
myTest2('should only call once for each fixture fn', ({ a, b, c, d }) => {
118+
expect(a).toBe('1')
119+
expect(b).toBe('2')
120+
expect(c).toBe(3)
121+
expect(d).toBe(6)
122+
123+
expect(fnA).toBeCalledTimes(1)
124+
expect(fnB).toBeCalledTimes(1)
125+
expect(fnB2).toBeCalledTimes(1)
126+
expect(fnC).toBeCalledTimes(1)
127+
expect(fnD).toBeCalledTimes(1)
128+
})
129+
})
130+
})

‎test/core/test/test-extend.test.ts

+45-35
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
1-
/* eslint-disable no-empty-pattern */
21
/* eslint-disable prefer-rest-params */
2+
/* eslint-disable no-empty-pattern */
33
import { describe, expect, expectTypeOf, test, vi } from 'vitest'
44

5+
interface Fixtures {
6+
todoList: number[]
7+
doneList: number[]
8+
archiveList: number[]
9+
}
10+
511
const todoList: number[] = [1, 2, 3]
612
const doneList: number[] = []
713
const archiveList: number[] = []
814

9-
const todoFn = vi.fn().mockImplementation(async (use) => {
10-
await use(todoList)
11-
// cleanup
12-
todoFn.mockClear()
13-
todoList.length = 0
14-
todoList.push(1, 2, 3)
15-
})
16-
17-
const doneFn = vi.fn().mockImplementation(async (use) => {
18-
await use(doneList)
19-
// cleanup
20-
doneFn.mockClear()
21-
doneList.length = 0
22-
})
15+
const todoFn = vi.fn()
16+
const doneFn = vi.fn()
2317

2418
const myTest = test
25-
.extend<{ todoList: number[] }>({
26-
todoList: todoFn,
19+
.extend<Pick<Fixtures, 'todoList'>>({
20+
todoList: async ({}, use) => {
21+
todoFn()
22+
await use(todoList)
23+
// cleanup
24+
todoFn.mockClear()
25+
todoList.length = 0
26+
todoList.push(1, 2, 3)
27+
},
2728
})
28-
.extend<{ doneList: number[]; archiveList: number[] }>({
29-
doneList: doneFn,
29+
.extend<Pick<Fixtures, 'doneList' | 'archiveList'>>({
30+
doneList: async ({}, use) => {
31+
doneFn()
32+
await use(doneList)
33+
// cleanup
34+
doneFn.mockClear()
35+
doneList.length = 0
36+
},
3037
archiveList,
3138
})
3239

@@ -54,12 +61,14 @@ describe('test.extend()', () => {
5461
archiveList.push(todoList.shift()!)
5562
expect(todoList).toEqual([])
5663
expect(archiveList).toEqual([3])
64+
65+
archiveList.pop()
5766
})
5867

5968
myTest('should called cleanup functions', ({ todoList, doneList, archiveList }) => {
6069
expect(todoList).toEqual([1, 2, 3])
6170
expect(doneList).toEqual([])
62-
expect(archiveList).toEqual([3])
71+
expect(archiveList).toEqual([])
6372
})
6473

6574
describe('smartly init fixtures', () => {
@@ -114,30 +123,31 @@ describe('test.extend()', () => {
114123
expect(arguments[0].archiveList).toBeUndefined()
115124
})
116125

117-
myTest('should init all fixtures', ({ todoList, ...rest }) => {
118-
expect(todoFn).toBeCalledTimes(1)
126+
myTest('should only init doneList and archiveList', function ({ doneList, archiveList }) {
119127
expect(doneFn).toBeCalledTimes(1)
120128

121-
expectTypeOf(todoList).toEqualTypeOf<number[]>()
122-
expectTypeOf(rest.doneList).toEqualTypeOf<number[]>()
123-
expectTypeOf(rest.archiveList).toEqualTypeOf<number[]>()
129+
expectTypeOf(doneList).toEqualTypeOf<number[]>()
130+
expectTypeOf(archiveList).toEqualTypeOf<number[]>()
131+
expectTypeOf(arguments[0].todoList).not.toEqualTypeOf<number[]>()
124132

125-
expect(todoList).toEqual([1, 2, 3])
126-
expect(rest.doneList).toEqual([])
127-
expect(rest.archiveList).toEqual([3])
133+
expect(doneList).toEqual([])
134+
expect(archiveList).toEqual([])
135+
expect(arguments[0].todoList).toBeUndefined()
128136
})
137+
})
129138

130-
myTest('should init all fixtures', (context) => {
139+
describe('test function', () => {
140+
myTest('prop alias', ({ todoList: todos, doneList: done, archiveList: archive }) => {
131141
expect(todoFn).toBeCalledTimes(1)
132142
expect(doneFn).toBeCalledTimes(1)
133143

134-
expectTypeOf(context.todoList).toEqualTypeOf<number[]>()
135-
expectTypeOf(context.doneList).toEqualTypeOf<number[]>()
136-
expectTypeOf(context.archiveList).toEqualTypeOf<number[]>()
144+
expectTypeOf(todos).toEqualTypeOf<number[]>()
145+
expectTypeOf(done).toEqualTypeOf<number[]>()
146+
expectTypeOf(archive).toEqualTypeOf<number[]>()
137147

138-
expect(context.todoList).toEqual([1, 2, 3])
139-
expect(context.doneList).toEqual([])
140-
expect(context.archiveList).toEqual([3])
148+
expect(todos).toEqual([1, 2, 3])
149+
expect(done).toEqual([])
150+
expect(archive).toEqual([])
141151
})
142152
})
143153
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { expect, test } from 'vitest'
2+
3+
const myTest = test.extend<{ a: number; b: number }>({
4+
a: async ({ b }, use) => {
5+
await use(b)
6+
},
7+
b: async ({ a }, use) => {
8+
await use(a)
9+
},
10+
})
11+
12+
myTest('', ({ a }) => {
13+
expect(a).toBe(0)
14+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { test } from 'vitest'
2+
3+
test.extend({
4+
// eslint-disable-next-line unused-imports/no-unused-vars
5+
a: async (...rest) => {},
6+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { test } from 'vitest'
2+
3+
test.extend({
4+
// eslint-disable-next-line unused-imports/no-unused-vars
5+
a: async ({ ...rest }) => {},
6+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { test } from 'vitest'
2+
3+
test.extend({
4+
// eslint-disable-next-line unused-imports/no-unused-vars
5+
a: async (context) => {},
6+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from 'vitest'
2+
3+
const myTest = test.extend({ a: 1 })
4+
5+
// eslint-disable-next-line unused-imports/no-unused-vars
6+
myTest('', (...rest) => {
7+
8+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from 'vitest'
2+
3+
const myTest = test.extend({ a: 1 })
4+
5+
// eslint-disable-next-line unused-imports/no-unused-vars
6+
myTest('', ({ ...rest }) => {
7+
8+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from 'vitest'
2+
3+
const myTest = test.extend({ a: 1 })
4+
5+
// eslint-disable-next-line unused-imports/no-unused-vars
6+
myTest('', (context) => {
7+
8+
})

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

+14
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@ TypeError: failure
4040
TypeError: failure"
4141
`;
4242
43+
exports[`should fail test-extend/circular-dependency.test.ts > test-extend/circular-dependency.test.ts 1`] = `"Error: circular fixture dependency"`;
44+
45+
exports[`should fail test-extend/fixture-rest-params.test.ts > test-extend/fixture-rest-params.test.ts 1`] = `"Error: the first argument must use object destructuring pattern"`;
46+
47+
exports[`should fail test-extend/fixture-rest-props.test.ts > test-extend/fixture-rest-props.test.ts 1`] = `"Error: Rest parameters are not supported"`;
48+
49+
exports[`should fail test-extend/fixture-without-destructuring.test.ts > test-extend/fixture-without-destructuring.test.ts 1`] = `"Error: the first argument must use object destructuring pattern"`;
50+
51+
exports[`should fail test-extend/test-rest-params.test.ts > test-extend/test-rest-params.test.ts 1`] = `"Error: the first argument must use object destructuring pattern"`;
52+
53+
exports[`should fail test-extend/test-rest-props.test.ts > test-extend/test-rest-props.test.ts 1`] = `"Error: Rest parameters are not supported"`;
54+
55+
exports[`should fail test-extend/test-without-destructuring.test.ts > test-extend/test-without-destructuring.test.ts 1`] = `"Error: the first argument must use object destructuring pattern"`;
56+
4357
exports[`should fail test-timeout.test.ts > test-timeout.test.ts 1`] = `
4458
"Error: Test timed out in 200ms.
4559
Error: Test timed out in 100ms.

0 commit comments

Comments
 (0)
Please sign in to comment.