Skip to content

Commit 4d41928

Browse files
authored
feat!: remove deprecated order from test() API (#8594)
1 parent e3138bd commit 4d41928

File tree

9 files changed

+42
-96
lines changed

9 files changed

+42
-96
lines changed

docs/guide/migration.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ Vitest 4.0 removes some deprecated APIs, including:
315315
- `deps.external`, `deps.inline`, `deps.fallbackCJS` config options. Use `server.deps.external`, `server.deps.inline`, or `server.deps.fallbackCJS` instead.
316316
- `browser.testerScripts` config option. Use [`browser.testerHtmlPath`](/guide/browser/config#browser-testerhtmlpath) instead.
317317
- `minWorkers` config option. Only `maxWorkers` has any effect on how tests are running, so we are removing this public option.
318+
- Vitest no longer supports providing test options as a third argument to `test` and `describe`. Use the second argument instead:
319+
320+
```ts
321+
test('example', () => { /* ... */ }, { retry: 2 }) // [!code --]
322+
test('example', { retry: 2 }, () => { /* ... */ }) // [!code ++]
323+
```
318324

319325
This release also removes all deprecated types. This finally fixes an issue where Vitest accidentally pulled in `@types/node` (see [#5481](https://github.com/vitest-dev/vitest/issues/5481) and [#6141](https://github.com/vitest-dev/vitest/issues/6141)).
320326

packages/runner/src/run.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { DiffOptions } from '@vitest/utils/diff'
33
import type { FileSpecification, VitestRunner } from './types/runner'
44
import type {
55
File,
6-
HookListener,
76
SequenceHooks,
87
Suite,
98
SuiteHooks,
@@ -130,7 +129,7 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
130129
currentTask: Task,
131130
name: T,
132131
runner: VitestRunner,
133-
args: SuiteHooks[T][0] extends HookListener<infer A, any> ? A : never,
132+
args: SuiteHooks[T][0] extends (...args: infer A) => Awaitable<any> ? A : never,
134133
): Promise<unknown[]> {
135134
const sequence = runner.config.sequence.hooks
136135

@@ -154,7 +153,7 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
154153
return getBeforeHookCleanupCallback(
155154
hook,
156155
await hook(...args),
157-
name === 'beforeEach' ? args[0] : undefined,
156+
name === 'beforeEach' ? args[0] as TestContext : undefined,
158157
)
159158
}
160159

packages/runner/src/suite.ts

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -243,43 +243,34 @@ export function createSuiteHooks(): SuiteHooks {
243243

244244
function parseArguments<T extends (...args: any[]) => any>(
245245
optionsOrFn: T | object | undefined,
246-
optionsOrTest: object | T | number | undefined,
246+
timeoutOrTest: T | number | undefined,
247247
) {
248+
if (typeof timeoutOrTest === 'object') {
249+
throw new TypeError(`Siganture "test(name, fn, { ... })" was deprecated in Vitest 3 and removed in Vitest 4. Please, provide options as a second argument instead.`)
250+
}
251+
248252
let options: TestOptions = {}
249253
let fn: T | undefined
250254

251-
// it('', () => {}, { retry: 2 })
252-
if (typeof optionsOrTest === 'object') {
253-
// it('', { retry: 2 }, { retry: 3 })
254-
if (typeof optionsOrFn === 'object') {
255-
throw new TypeError(
256-
'Cannot use two objects as arguments. Please provide options and a function callback in that order.',
257-
)
258-
}
259-
console.warn(
260-
'Using an object as a third argument is deprecated. Vitest 4 will throw an error if the third argument is not a timeout number. Please use the second argument for options. See more at https://vitest.dev/guide/migration',
261-
)
262-
options = optionsOrTest
263-
}
264255
// it('', () => {}, 1000)
265-
else if (typeof optionsOrTest === 'number') {
266-
options = { timeout: optionsOrTest }
256+
if (typeof timeoutOrTest === 'number') {
257+
options = { timeout: timeoutOrTest }
267258
}
268259
// it('', { retry: 2 }, () => {})
269260
else if (typeof optionsOrFn === 'object') {
270261
options = optionsOrFn
271262
}
272263

273264
if (typeof optionsOrFn === 'function') {
274-
if (typeof optionsOrTest === 'function') {
265+
if (typeof timeoutOrTest === 'function') {
275266
throw new TypeError(
276267
'Cannot use two functions as arguments. Please use the second argument for options.',
277268
)
278269
}
279270
fn = optionsOrFn as T
280271
}
281-
else if (typeof optionsOrTest === 'function') {
282-
fn = optionsOrTest as T
272+
else if (typeof timeoutOrTest === 'function') {
273+
fn = timeoutOrTest as T
283274
}
284275

285276
return {
@@ -384,9 +375,9 @@ function createSuiteCollector(
384375
const test = createTest(function (
385376
name: string | Function,
386377
optionsOrFn?: TestOptions | TestFunction,
387-
optionsOrTest?: number | TestOptions | TestFunction,
378+
timeoutOrTest?: number | TestFunction,
388379
) {
389-
let { options, handler } = parseArguments(optionsOrFn, optionsOrTest)
380+
let { options, handler } = parseArguments(optionsOrFn, timeoutOrTest)
390381

391382
// inherit repeats, retry, timeout from suite
392383
if (typeof suiteOptions === 'object') {
@@ -533,7 +524,7 @@ function createSuite() {
533524
this: Record<string, boolean | undefined>,
534525
name: string | Function,
535526
factoryOrOptions?: SuiteFactory | TestOptions,
536-
optionsOrFactory?: number | TestOptions | SuiteFactory,
527+
optionsOrFactory?: number | SuiteFactory,
537528
) {
538529
let mode: RunMode = this.only
539530
? 'only'
@@ -597,14 +588,14 @@ function createSuite() {
597588
return (
598589
name: string | Function,
599590
optionsOrFn: ((...args: T[]) => void) | TestOptions,
600-
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
591+
fnOrOptions?: ((...args: T[]) => void) | number,
601592
) => {
602593
const _name = formatName(name)
603594
const arrayOnlyCases = cases.every(Array.isArray)
604595

605596
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
606597

607-
const fnFirst = typeof optionsOrFn === 'function' && typeof fnOrOptions === 'object'
598+
const fnFirst = typeof optionsOrFn === 'function'
608599

609600
cases.forEach((i, idx) => {
610601
const items = Array.isArray(i) ? i : [i]
@@ -613,11 +604,11 @@ function createSuite() {
613604
suite(
614605
formatTitle(_name, items, idx),
615606
handler ? () => handler(...items) : undefined,
616-
options,
607+
options.timeout,
617608
)
618609
}
619610
else {
620-
suite(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options)
611+
suite(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options.timeout)
621612
}
622613
}
623614
else {
@@ -649,7 +640,7 @@ function createSuite() {
649640
return (
650641
name: string | Function,
651642
optionsOrFn: ((...args: T[]) => void) | TestOptions,
652-
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
643+
fnOrOptions?: ((...args: T[]) => void) | number,
653644
) => {
654645
const name_ = formatName(name)
655646
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
@@ -694,14 +685,14 @@ export function createTaskCollector(
694685
return (
695686
name: string | Function,
696687
optionsOrFn: ((...args: T[]) => void) | TestOptions,
697-
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
688+
fnOrOptions?: ((...args: T[]) => void) | number,
698689
) => {
699690
const _name = formatName(name)
700691
const arrayOnlyCases = cases.every(Array.isArray)
701692

702693
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
703694

704-
const fnFirst = typeof optionsOrFn === 'function' && typeof fnOrOptions === 'object'
695+
const fnFirst = typeof optionsOrFn === 'function'
705696

706697
cases.forEach((i, idx) => {
707698
const items = Array.isArray(i) ? i : [i]
@@ -711,11 +702,11 @@ export function createTaskCollector(
711702
test(
712703
formatTitle(_name, items, idx),
713704
handler ? () => handler(...items) : undefined,
714-
options,
705+
options.timeout,
715706
)
716707
}
717708
else {
718-
test(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options)
709+
test(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options.timeout)
719710
}
720711
}
721712
else {
@@ -749,7 +740,7 @@ export function createTaskCollector(
749740
return (
750741
name: string | Function,
751742
optionsOrFn: ((...args: T[]) => void) | TestOptions,
752-
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
743+
fnOrOptions?: ((...args: T[]) => void) | number,
753744
) => {
754745
const _name = formatName(name)
755746
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
@@ -788,7 +779,7 @@ export function createTaskCollector(
788779
return createTest(function (
789780
name: string | Function,
790781
optionsOrFn?: TestOptions | TestFunction,
791-
optionsOrTest?: number | TestOptions | TestFunction,
782+
optionsOrTest?: number | TestFunction,
792783
) {
793784
const collector = getCurrentSuite()
794785
const scopedFixtures = collector.fixtures()
@@ -825,7 +816,7 @@ function createTest(
825816
> & { fixtures?: FixtureItem[] },
826817
title: string,
827818
optionsOrFn?: TestOptions | TestFunction,
828-
optionsOrTest?: number | TestOptions | TestFunction
819+
optionsOrTest?: number | TestFunction
829820
) => void,
830821
context?: Record<string, any>,
831822
) {

packages/runner/src/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ export type {
1616
FixtureFn,
1717
FixtureOptions,
1818
Fixtures,
19-
HookCleanupCallback,
20-
HookListener,
2119
ImportDuration,
2220
InferFixturesTypes,
2321
OnTestFailedHandler,

packages/runner/src/types/tasks.ts

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,10 @@ type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
345345
: 'fallback']
346346

347347
interface EachFunctionReturn<T extends any[]> {
348-
/**
349-
* @deprecated Use options as the second argument instead
350-
*/
351-
(
352-
name: string | Function,
353-
fn: (...args: T) => Awaitable<void>,
354-
options: TestCollectorOptions
355-
): void
356348
(
357349
name: string | Function,
358350
fn: (...args: T) => Awaitable<void>,
359-
options?: number | TestCollectorOptions
351+
options?: number
360352
): void
361353
(
362354
name: string | Function,
@@ -411,18 +403,10 @@ interface SuiteForFunction {
411403
}
412404

413405
interface TestCollectorCallable<C = object> {
414-
/**
415-
* @deprecated Use options as the second argument instead
416-
*/
417-
<ExtraContext extends C>(
418-
name: string | Function,
419-
fn: TestFunction<ExtraContext>,
420-
options: TestCollectorOptions
421-
): void
422406
<ExtraContext extends C>(
423407
name: string | Function,
424408
fn?: TestFunction<ExtraContext>,
425-
options?: number | TestCollectorOptions
409+
options?: number
426410
): void
427411
<ExtraContext extends C>(
428412
name: string | Function,
@@ -560,18 +544,10 @@ export type Fixtures<T extends Record<string, any>, ExtraContext = object> = {
560544
export type InferFixturesTypes<T> = T extends TestAPI<infer C> ? C : T
561545

562546
interface SuiteCollectorCallable<ExtraContext = object> {
563-
/**
564-
* @deprecated Use options as the second argument instead
565-
*/
566-
<OverrideExtraContext extends ExtraContext = ExtraContext>(
567-
name: string | Function,
568-
fn: SuiteFactory<OverrideExtraContext>,
569-
options: TestOptions
570-
): SuiteCollector<OverrideExtraContext>
571547
<OverrideExtraContext extends ExtraContext = ExtraContext>(
572548
name: string | Function,
573549
fn?: SuiteFactory<OverrideExtraContext>,
574-
options?: number | TestOptions
550+
options?: number
575551
): SuiteCollector<OverrideExtraContext>
576552
<OverrideExtraContext extends ExtraContext = ExtraContext>(
577553
name: string | Function,
@@ -594,18 +570,6 @@ export type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> &
594570
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>
595571
}
596572

597-
/**
598-
* @deprecated
599-
*/
600-
export type HookListener<T extends any[], Return = void> = (
601-
...args: T
602-
) => Awaitable<Return>
603-
604-
/**
605-
* @deprecated
606-
*/
607-
export type HookCleanupCallback = unknown
608-
609573
export interface BeforeAllListener {
610574
(suite: Readonly<Suite | File>): Awaitable<unknown>
611575
}

packages/vitest/src/public/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ export {
8383
test,
8484
} from '@vitest/runner'
8585
export type {
86-
HookCleanupCallback,
87-
HookListener,
8886
ImportDuration,
8987
OnTestFailedHandler,
9088
OnTestFinishedHandler,

test/core/test/task-collector.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ test('collector keeps the order of arguments', () => {
66
const fn = vi.fn()
77
const collector = createTaskCollector(fn)
88
const cb = vi.fn()
9-
const options = {}
9+
const options = { timeout: 100 }
1010

11-
collector('a', cb, options)
11+
collector('a', cb, options.timeout)
1212

13-
expect(fn).toHaveBeenNthCalledWith(1, 'a', cb, options)
13+
expect(fn).toHaveBeenNthCalledWith(1, 'a', cb, options.timeout)
1414

1515
collector('a', options, cb)
1616

1717
expect(fn).toHaveBeenNthCalledWith(2, 'a', options, cb)
1818

19-
collector.each([1])('a', cb, options)
19+
collector.each([1])('a', cb, options.timeout)
2020

21-
expect(fn).toHaveBeenNthCalledWith(3, 'a', expect.any(Function), options)
21+
expect(fn).toHaveBeenNthCalledWith(3, 'a', expect.any(Function), options.timeout)
2222

2323
collector.each([1])('a', options, cb)
2424

test/core/test/test-options.test.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@ describe('all test variations are allowed', () => {
88
test.skip('skipped explicitly', fail)
99
test.skip('skipped explicitly', fail, 1000)
1010
test('skipped explicitly via options', { skip: true }, fail)
11-
test('skipped explicitly via options as the last argument', fail, { skip: true })
1211

1312
test.todo('todo explicitly', fail)
1413
test.todo('todo explicitly', fail, 1000)
1514
test('todo explicitly via options', { todo: true }, fail)
16-
test('todo explicitly via options as the last argument', fail, { todo: true })
1715

1816
test.fails('fails by default', fail)
1917
test.fails('fails by default', fail, 1000)
2018
test('fails explicitly via options', { fails: true }, fail)
21-
test('fails explicitly via options as the last argument', fail, { fails: true })
2219
})
2320

2421
describe('only is allowed explicitly', () => {
@@ -30,8 +27,3 @@ describe('only is allowed via options', () => {
3027
test('not only by default', fail)
3128
test('only via options', { only: true }, () => {})
3229
})
33-
34-
describe('only is allowed via option as the last argument', () => {
35-
test('not only by default', fail)
36-
test('only via options as the last argument', () => {}, { only: true })
37-
})

test/core/test/timeout.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { describe, expect, test } from 'vitest'
22

3-
describe('suite timeout', () => {
3+
describe('suite timeout', { timeout: 100 }, () => {
44
test('timeout is inherited', async ({ task }) => {
55
expect(task.timeout).toBe(100)
66
})
7-
}, {
8-
timeout: 100,
97
})
108

119
describe('suite timeout simple input', () => {

0 commit comments

Comments
 (0)