Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,12 @@ Vitest 4.0 removes some deprecated APIs, including:
- `deps.external`, `deps.inline`, `deps.fallbackCJS` config options. Use `server.deps.external`, `server.deps.inline`, or `server.deps.fallbackCJS` instead.
- `browser.testerScripts` config option. Use [`browser.testerHtmlPath`](/guide/browser/config#browser-testerhtmlpath) instead.
- `minWorkers` config option. Only `maxWorkers` has any effect on how tests are running, so we are removing this public option.
- Vitest no longer supports providing test options as a third argument to `test` and `describe`. Use the second argument instead:

```ts
test('example', () => { /* ... */ }, { retry: 2 }) // [!code --]
test('example', { retry: 2 }, () => { /* ... */ }) // [!code ++]
```

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)).

Expand Down
5 changes: 2 additions & 3 deletions packages/runner/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { DiffOptions } from '@vitest/utils/diff'
import type { FileSpecification, VitestRunner } from './types/runner'
import type {
File,
HookListener,
SequenceHooks,
Suite,
SuiteHooks,
Expand Down Expand Up @@ -130,7 +129,7 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
currentTask: Task,
name: T,
runner: VitestRunner,
args: SuiteHooks[T][0] extends HookListener<infer A, any> ? A : never,
args: SuiteHooks[T][0] extends (...args: infer A) => Awaitable<any> ? A : never,
): Promise<unknown[]> {
const sequence = runner.config.sequence.hooks

Expand All @@ -154,7 +153,7 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
return getBeforeHookCleanupCallback(
hook,
await hook(...args),
name === 'beforeEach' ? args[0] : undefined,
name === 'beforeEach' ? args[0] as TestContext : undefined,
)
}

Expand Down
59 changes: 25 additions & 34 deletions packages/runner/src/suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,43 +243,34 @@ export function createSuiteHooks(): SuiteHooks {

function parseArguments<T extends (...args: any[]) => any>(
optionsOrFn: T | object | undefined,
optionsOrTest: object | T | number | undefined,
timeoutOrTest: T | number | undefined,
) {
if (typeof timeoutOrTest === 'object') {
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.`)
}

let options: TestOptions = {}
let fn: T | undefined

// it('', () => {}, { retry: 2 })
if (typeof optionsOrTest === 'object') {
// it('', { retry: 2 }, { retry: 3 })
if (typeof optionsOrFn === 'object') {
throw new TypeError(
'Cannot use two objects as arguments. Please provide options and a function callback in that order.',
)
}
console.warn(
'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',
)
options = optionsOrTest
}
// it('', () => {}, 1000)
else if (typeof optionsOrTest === 'number') {
options = { timeout: optionsOrTest }
if (typeof timeoutOrTest === 'number') {
options = { timeout: timeoutOrTest }
}
// it('', { retry: 2 }, () => {})
else if (typeof optionsOrFn === 'object') {
options = optionsOrFn
}

if (typeof optionsOrFn === 'function') {
if (typeof optionsOrTest === 'function') {
if (typeof timeoutOrTest === 'function') {
throw new TypeError(
'Cannot use two functions as arguments. Please use the second argument for options.',
)
}
fn = optionsOrFn as T
}
else if (typeof optionsOrTest === 'function') {
fn = optionsOrTest as T
else if (typeof timeoutOrTest === 'function') {
fn = timeoutOrTest as T
}

return {
Expand Down Expand Up @@ -384,9 +375,9 @@ function createSuiteCollector(
const test = createTest(function (
name: string | Function,
optionsOrFn?: TestOptions | TestFunction,
optionsOrTest?: number | TestOptions | TestFunction,
timeoutOrTest?: number | TestFunction,
) {
let { options, handler } = parseArguments(optionsOrFn, optionsOrTest)
let { options, handler } = parseArguments(optionsOrFn, timeoutOrTest)

// inherit repeats, retry, timeout from suite
if (typeof suiteOptions === 'object') {
Expand Down Expand Up @@ -533,7 +524,7 @@ function createSuite() {
this: Record<string, boolean | undefined>,
name: string | Function,
factoryOrOptions?: SuiteFactory | TestOptions,
optionsOrFactory?: number | TestOptions | SuiteFactory,
optionsOrFactory?: number | SuiteFactory,
) {
let mode: RunMode = this.only
? 'only'
Expand Down Expand Up @@ -597,14 +588,14 @@ function createSuite() {
return (
name: string | Function,
optionsOrFn: ((...args: T[]) => void) | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number,
) => {
const _name = formatName(name)
const arrayOnlyCases = cases.every(Array.isArray)

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

const fnFirst = typeof optionsOrFn === 'function' && typeof fnOrOptions === 'object'
const fnFirst = typeof optionsOrFn === 'function'

cases.forEach((i, idx) => {
const items = Array.isArray(i) ? i : [i]
Expand All @@ -613,11 +604,11 @@ function createSuite() {
suite(
formatTitle(_name, items, idx),
handler ? () => handler(...items) : undefined,
options,
options.timeout,
)
}
else {
suite(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options)
suite(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options.timeout)
}
}
else {
Expand Down Expand Up @@ -649,7 +640,7 @@ function createSuite() {
return (
name: string | Function,
optionsOrFn: ((...args: T[]) => void) | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number,
) => {
const name_ = formatName(name)
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
Expand Down Expand Up @@ -694,14 +685,14 @@ export function createTaskCollector(
return (
name: string | Function,
optionsOrFn: ((...args: T[]) => void) | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number,
) => {
const _name = formatName(name)
const arrayOnlyCases = cases.every(Array.isArray)

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

const fnFirst = typeof optionsOrFn === 'function' && typeof fnOrOptions === 'object'
const fnFirst = typeof optionsOrFn === 'function'

cases.forEach((i, idx) => {
const items = Array.isArray(i) ? i : [i]
Expand All @@ -711,11 +702,11 @@ export function createTaskCollector(
test(
formatTitle(_name, items, idx),
handler ? () => handler(...items) : undefined,
options,
options.timeout,
)
}
else {
test(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options)
test(formatTitle(_name, items, idx), handler ? () => handler(i) : undefined, options.timeout)
}
}
else {
Expand Down Expand Up @@ -749,7 +740,7 @@ export function createTaskCollector(
return (
name: string | Function,
optionsOrFn: ((...args: T[]) => void) | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number | TestOptions,
fnOrOptions?: ((...args: T[]) => void) | number,
) => {
const _name = formatName(name)
const { options, handler } = parseArguments(optionsOrFn, fnOrOptions)
Expand Down Expand Up @@ -788,7 +779,7 @@ export function createTaskCollector(
return createTest(function (
name: string | Function,
optionsOrFn?: TestOptions | TestFunction,
optionsOrTest?: number | TestOptions | TestFunction,
optionsOrTest?: number | TestFunction,
) {
const collector = getCurrentSuite()
const scopedFixtures = collector.fixtures()
Expand Down Expand Up @@ -825,7 +816,7 @@ function createTest(
> & { fixtures?: FixtureItem[] },
title: string,
optionsOrFn?: TestOptions | TestFunction,
optionsOrTest?: number | TestOptions | TestFunction
optionsOrTest?: number | TestFunction
) => void,
context?: Record<string, any>,
) {
Expand Down
2 changes: 0 additions & 2 deletions packages/runner/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ export type {
FixtureFn,
FixtureOptions,
Fixtures,
HookCleanupCallback,
HookListener,
ImportDuration,
InferFixturesTypes,
OnTestFailedHandler,
Expand Down
42 changes: 3 additions & 39 deletions packages/runner/src/types/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,18 +345,10 @@ type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
: 'fallback']

interface EachFunctionReturn<T extends any[]> {
/**
* @deprecated Use options as the second argument instead
*/
(
name: string | Function,
fn: (...args: T) => Awaitable<void>,
options: TestCollectorOptions
): void
(
name: string | Function,
fn: (...args: T) => Awaitable<void>,
options?: number | TestCollectorOptions
options?: number
): void
(
name: string | Function,
Expand Down Expand Up @@ -411,18 +403,10 @@ interface SuiteForFunction {
}

interface TestCollectorCallable<C = object> {
/**
* @deprecated Use options as the second argument instead
*/
<ExtraContext extends C>(
name: string | Function,
fn: TestFunction<ExtraContext>,
options: TestCollectorOptions
): void
<ExtraContext extends C>(
name: string | Function,
fn?: TestFunction<ExtraContext>,
options?: number | TestCollectorOptions
options?: number
): void
<ExtraContext extends C>(
name: string | Function,
Expand Down Expand Up @@ -560,18 +544,10 @@ export type Fixtures<T extends Record<string, any>, ExtraContext = object> = {
export type InferFixturesTypes<T> = T extends TestAPI<infer C> ? C : T

interface SuiteCollectorCallable<ExtraContext = object> {
/**
* @deprecated Use options as the second argument instead
*/
<OverrideExtraContext extends ExtraContext = ExtraContext>(
name: string | Function,
fn: SuiteFactory<OverrideExtraContext>,
options: TestOptions
): SuiteCollector<OverrideExtraContext>
<OverrideExtraContext extends ExtraContext = ExtraContext>(
name: string | Function,
fn?: SuiteFactory<OverrideExtraContext>,
options?: number | TestOptions
options?: number
): SuiteCollector<OverrideExtraContext>
<OverrideExtraContext extends ExtraContext = ExtraContext>(
name: string | Function,
Expand All @@ -594,18 +570,6 @@ export type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> &
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>
}

/**
* @deprecated
*/
export type HookListener<T extends any[], Return = void> = (
...args: T
) => Awaitable<Return>

/**
* @deprecated
*/
export type HookCleanupCallback = unknown

export interface BeforeAllListener {
(suite: Readonly<Suite | File>): Awaitable<unknown>
}
Expand Down
2 changes: 0 additions & 2 deletions packages/vitest/src/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ export {
test,
} from '@vitest/runner'
export type {
HookCleanupCallback,
HookListener,
ImportDuration,
OnTestFailedHandler,
OnTestFinishedHandler,
Expand Down
10 changes: 5 additions & 5 deletions test/core/test/task-collector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ test('collector keeps the order of arguments', () => {
const fn = vi.fn()
const collector = createTaskCollector(fn)
const cb = vi.fn()
const options = {}
const options = { timeout: 100 }

collector('a', cb, options)
collector('a', cb, options.timeout)

expect(fn).toHaveBeenNthCalledWith(1, 'a', cb, options)
expect(fn).toHaveBeenNthCalledWith(1, 'a', cb, options.timeout)

collector('a', options, cb)

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

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

expect(fn).toHaveBeenNthCalledWith(3, 'a', expect.any(Function), options)
expect(fn).toHaveBeenNthCalledWith(3, 'a', expect.any(Function), options.timeout)

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

Expand Down
8 changes: 0 additions & 8 deletions test/core/test/test-options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ describe('all test variations are allowed', () => {
test.skip('skipped explicitly', fail)
test.skip('skipped explicitly', fail, 1000)
test('skipped explicitly via options', { skip: true }, fail)
test('skipped explicitly via options as the last argument', fail, { skip: true })

test.todo('todo explicitly', fail)
test.todo('todo explicitly', fail, 1000)
test('todo explicitly via options', { todo: true }, fail)
test('todo explicitly via options as the last argument', fail, { todo: true })

test.fails('fails by default', fail)
test.fails('fails by default', fail, 1000)
test('fails explicitly via options', { fails: true }, fail)
test('fails explicitly via options as the last argument', fail, { fails: true })
})

describe('only is allowed explicitly', () => {
Expand All @@ -30,8 +27,3 @@ describe('only is allowed via options', () => {
test('not only by default', fail)
test('only via options', { only: true }, () => {})
})

describe('only is allowed via option as the last argument', () => {
test('not only by default', fail)
test('only via options as the last argument', () => {}, { only: true })
})
4 changes: 1 addition & 3 deletions test/core/test/timeout.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { describe, expect, test } from 'vitest'

describe('suite timeout', () => {
describe('suite timeout', { timeout: 100 }, () => {
test('timeout is inherited', async ({ task }) => {
expect(task.timeout).toBe(100)
})
}, {
timeout: 100,
})

describe('suite timeout simple input', () => {
Expand Down
Loading