···11import { processError } from '@vitest/utils/error'
22-import type { File, SuiteHooks } from './types'
22+import type { File, SuiteHooks } from './types/tasks'
33import type { VitestRunner } from './types/runner'
44import {
55 calculateSuiteHash,
+3-3
packages/runner/src/context.ts
···77 SuiteCollector,
88 TaskContext,
99 Test,
1010-} from './types'
1010+} from './types/tasks'
1111import type { VitestRunner } from './types/runner'
1212import { PendingError } from './errors'
1313···1616 currentSuite: null,
1717}
18181919-export function collectTask(task: SuiteCollector) {
1919+export function collectTask(task: SuiteCollector): void {
2020 collectorContext.currentSuite?.tasks.push(task)
2121}
22222323export async function runWithSuite(
2424 suite: SuiteCollector,
2525 fn: () => Awaitable<void>,
2626-) {
2626+): Promise<void> {
2727 const prev = collectorContext.currentSuite
2828 collectorContext.currentSuite = suite
2929 await fn()
+1-1
packages/runner/src/errors.ts
···11-import type { TaskBase } from './types'
11+import type { TaskBase } from './types/tasks'
2233export class PendingError extends Error {
44 public code = 'VITEST_PENDING'
···11import type {
22+ AfterAllListener,
33+ AfterEachListener,
44+ BeforeAllListener,
55+ BeforeEachListener,
26 OnTestFailedHandler,
37 OnTestFinishedHandler,
44- SuiteHooks,
88+ TaskHook,
59 TaskPopulated,
66-} from './types'
1010+} from './types/tasks'
711import { getCurrentSuite, getRunner } from './suite'
812import { getCurrentTest } from './test-state'
913import { withTimeout } from './context'
···1317 return getRunner().config.hookTimeout
1418}
15191616-// suite hooks
1717-export function beforeAll(fn: SuiteHooks['beforeAll'][0], timeout?: number) {
2020+/**
2121+ * Registers a callback function to be executed once before all tests within the current suite.
2222+ * This hook is useful for scenarios where you need to perform setup operations that are common to all tests in a suite, such as initializing a database connection or setting up a test environment.
2323+ *
2424+ * **Note:** The `beforeAll` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
2525+ *
2626+ * @param {Function} fn - The callback function to be executed before all tests.
2727+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
2828+ * @returns {void}
2929+ *
3030+ * @example
3131+ * // Example of using beforeAll to set up a database connection
3232+ * beforeAll(async () => {
3333+ * await database.connect();
3434+ * });
3535+ */
3636+export function beforeAll(fn: BeforeAllListener, timeout?: number): void {
1837 return getCurrentSuite().on(
1938 'beforeAll',
2039 withTimeout(fn, timeout ?? getDefaultHookTimeout(), true),
2140 )
2241}
2323-export function afterAll(fn: SuiteHooks['afterAll'][0], timeout?: number) {
4242+4343+/**
4444+ * Registers a callback function to be executed once after all tests within the current suite have completed.
4545+ * This hook is useful for scenarios where you need to perform cleanup operations after all tests in a suite have run, such as closing database connections or cleaning up temporary files.
4646+ *
4747+ * **Note:** The `afterAll` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
4848+ *
4949+ * @param {Function} fn - The callback function to be executed after all tests.
5050+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
5151+ * @returns {void}
5252+ *
5353+ * @example
5454+ * // Example of using afterAll to close a database connection
5555+ * afterAll(async () => {
5656+ * await database.disconnect();
5757+ * });
5858+ */
5959+export function afterAll(fn: AfterAllListener, timeout?: number): void {
2460 return getCurrentSuite().on(
2561 'afterAll',
2662 withTimeout(fn, timeout ?? getDefaultHookTimeout(), true),
2763 )
2864}
6565+6666+/**
6767+ * Registers a callback function to be executed before each test within the current suite.
6868+ * This hook is useful for scenarios where you need to reset or reinitialize the test environment before each test runs, such as resetting database states, clearing caches, or reinitializing variables.
6969+ *
7070+ * **Note:** The `beforeEach` hooks are executed in the order they are defined one after another. You can configure this by changing the `sequence.hooks` option in the config file.
7171+ *
7272+ * @param {Function} fn - The callback function to be executed before each test. This function receives an `TestContext` parameter if additional test context is needed.
7373+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
7474+ * @returns {void}
7575+ *
7676+ * @example
7777+ * // Example of using beforeEach to reset a database state
7878+ * beforeEach(async () => {
7979+ * await database.reset();
8080+ * });
8181+ */
2982export function beforeEach<ExtraContext = object>(
3030- fn: SuiteHooks<ExtraContext>['beforeEach'][0],
8383+ fn: BeforeEachListener<ExtraContext>,
3184 timeout?: number,
3232-) {
8585+): void {
3386 return getCurrentSuite<ExtraContext>().on(
3487 'beforeEach',
3588 withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true),
3689 )
3790}
9191+9292+/**
9393+ * Registers a callback function to be executed after each test within the current suite has completed.
9494+ * This hook is useful for scenarios where you need to clean up or reset the test environment after each test runs, such as deleting temporary files, clearing test-specific database entries, or resetting mocked functions.
9595+ *
9696+ * **Note:** The `afterEach` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
9797+ *
9898+ * @param {Function} fn - The callback function to be executed after each test. This function receives an `TestContext` parameter if additional test context is needed.
9999+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
100100+ * @returns {void}
101101+ *
102102+ * @example
103103+ * // Example of using afterEach to delete temporary files created during a test
104104+ * afterEach(async () => {
105105+ * await fileSystem.deleteTempFiles();
106106+ * });
107107+ */
38108export function afterEach<ExtraContext = object>(
3939- fn: SuiteHooks<ExtraContext>['afterEach'][0],
109109+ fn: AfterEachListener<ExtraContext>,
40110 timeout?: number,
4141-) {
111111+): void {
42112 return getCurrentSuite<ExtraContext>().on(
43113 'afterEach',
44114 withTimeout(withFixtures(fn), timeout ?? getDefaultHookTimeout(), true),
45115 )
46116}
471174848-export const onTestFailed = createTestHook<OnTestFailedHandler>(
118118+/**
119119+ * Registers a callback function to be executed when a test fails within the current suite.
120120+ * This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
121121+ *
122122+ * **Note:** The `onTestFailed` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
123123+ *
124124+ * @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
125125+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
126126+ * @throws {Error} Throws an error if the function is not called within a test.
127127+ * @returns {void}
128128+ *
129129+ * @example
130130+ * // Example of using onTestFailed to log failure details
131131+ * onTestFailed(({ errors }) => {
132132+ * console.log(`Test failed: ${test.name}`, errors);
133133+ * });
134134+ */
135135+export const onTestFailed: TaskHook<OnTestFailedHandler> = createTestHook(
49136 'onTestFailed',
5050- (test, handler) => {
137137+ (test, handler, timeout) => {
51138 test.onFailed ||= []
5252- test.onFailed.push(handler)
139139+ test.onFailed.push(
140140+ withTimeout(handler, timeout ?? getDefaultHookTimeout(), true),
141141+ )
53142 },
54143)
551445656-export const onTestFinished = createTestHook<OnTestFinishedHandler>(
145145+/**
146146+ * Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
147147+ * This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
148148+ *
149149+ * This hook is useful if you have access to a resource in the test itself and you want to clean it up after the test finishes. It is a more compact way to clean up resources than using the combination of `beforeEach` and `afterEach`.
150150+ *
151151+ * **Note:** The `onTestFinished` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
152152+ *
153153+ * @param {Function} fn - The callback function to be executed after a test finishes. The function can receive parameters providing details about the completed test, including its success or failure status.
154154+ * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
155155+ * @throws {Error} Throws an error if the function is not called within a test.
156156+ * @returns {void}
157157+ *
158158+ * @example
159159+ * // Example of using onTestFinished for cleanup
160160+ * const db = await connectToDatabase();
161161+ * onTestFinished(async () => {
162162+ * await db.disconnect();
163163+ * });
164164+ */
165165+export const onTestFinished: TaskHook<OnTestFinishedHandler> = createTestHook(
57166 'onTestFinished',
5858- (test, handler) => {
167167+ (test, handler, timeout) => {
59168 test.onFinished ||= []
6060- test.onFinished.push(handler)
169169+ test.onFinished.push(
170170+ withTimeout(handler, timeout ?? getDefaultHookTimeout(), true),
171171+ )
61172 },
62173)
6317464175function createTestHook<T>(
65176 name: string,
6666- handler: (test: TaskPopulated, handler: T) => void,
6767-) {
6868- return (fn: T) => {
177177+ handler: (test: TaskPopulated, handler: T, timeout?: number) => void,
178178+): TaskHook<T> {
179179+ return (fn: T, timeout?: number) => {
69180 const current = getCurrentTest()
7018171182 if (!current) {
72183 throw new Error(`Hook ${name}() can only be called inside a test`)
73184 }
741857575- return handler(current, fn)
186186+ return handler(current, fn, timeout)
76187 }
77188}
+2-1
packages/runner/src/index.ts
···1818export { setFn, getFn, getHooks, setHooks } from './map'
1919export { getCurrentTest } from './test-state'
2020export { processError } from '@vitest/utils/error'
2121-export * from './types'
2121+2222+export type * from './types'
+4-4
packages/runner/src/map.ts
···11import type { Awaitable } from '@vitest/utils'
22-import type { Custom, Suite, SuiteHooks, Test, TestContext } from './types'
22+import type { Custom, Suite, SuiteHooks, Test, TestContext } from './types/tasks'
33import type { FixtureItem } from './fixture'
4455// use WeakMap here to make the Test and Suite object serializable
···77const fixtureMap = new WeakMap()
88const hooksMap = new WeakMap()
991010-export function setFn(key: Test | Custom, fn: () => Awaitable<void>) {
1010+export function setFn(key: Test | Custom, fn: () => Awaitable<void>): void {
1111 fnMap.set(key, fn)
1212}
1313···1818export function setFixture(
1919 key: TestContext,
2020 fixture: FixtureItem[] | undefined,
2121-) {
2121+): void {
2222 fixtureMap.set(key, fixture)
2323}
2424···2626 return fixtureMap.get(key as any)
2727}
28282929-export function setHooks(key: Suite, hooks: SuiteHooks) {
2929+export function setHooks(key: Suite, hooks: SuiteHooks): void {
3030 hooksMap.set(key, hooks)
3131}
3232
+10-11
packages/runner/src/run.ts
···1717 TaskResultPack,
1818 TaskState,
1919 Test,
2020-} from './types'
2020+} from './types/tasks'
2121import { partitionSuiteChildren } from './utils/suite'
2222import { limitConcurrency } from './utils/limit-concurrency'
2323import { getFn, getHooks } from './map'
···90909191 const callbacks: HookCleanupCallback[] = []
9292 // stop at file level
9393- const parentSuite: Suite | null
9494- = 'filepath' in suite ? null : suite.suite || suite.file
9393+ const parentSuite: Suite | null = 'filepath' in suite ? null : suite.suite || suite.file
95949695 if (name === 'beforeEach' && parentSuite) {
9796 callbacks.push(
···105104106105 if (sequence === 'parallel') {
107106 callbacks.push(
108108- ...(await Promise.all(hooks.map(fn => fn(...(args as any))))),
107107+ ...(await Promise.all(hooks.map(hook => (hook as any)(...args)))),
109108 )
110109 }
111110 else {
112111 for (const hook of hooks) {
113113- callbacks.push(await hook(...(args as any)))
112112+ callbacks.push(await (hook as any)(...args))
114113 }
115114 }
116115···129128let updateTimer: any
130129let previousUpdate: Promise<void> | undefined
131130132132-export function updateTask(task: Task, runner: VitestRunner) {
131131+export function updateTask(task: Task, runner: VitestRunner): void {
133132 packs.set(task.id, [task.result, task.meta])
134133135134 const { clearTimeout, setTimeout } = getSafeTimers()
···166165 )
167166}
168167169169-export async function runTest(test: Test | Custom, runner: VitestRunner) {
168168+export async function runTest(test: Test | Custom, runner: VitestRunner): Promise<void> {
170169 await runner.onBeforeRunTask?.(test)
171170172171 if (test.mode !== 'run') {
···364363 })
365364}
366365367367-export async function runSuite(suite: Suite, runner: VitestRunner) {
366366+export async function runSuite(suite: Suite, runner: VitestRunner): Promise<void> {
368367 await runner.onBeforeRunSuite?.(suite)
369368370369 if (suite.result?.state === 'fail') {
···477476 }
478477}
479478480480-export async function runFiles(files: File[], runner: VitestRunner) {
479479+export async function runFiles(files: File[], runner: VitestRunner): Promise<void> {
481480 limitMaxConcurrency ??= limitConcurrency(runner.config.maxConcurrency)
482481483482 for (const file of files) {
···496495 }
497496}
498497499499-export async function startTests(paths: string[], runner: VitestRunner) {
498498+export async function startTests(paths: string[], runner: VitestRunner): Promise<File[]> {
500499 await runner.onBeforeCollect?.(paths)
501500502501 const files = await collectTests(paths, runner)
···513512 return files
514513}
515514516516-async function publicCollect(paths: string[], runner: VitestRunner) {
515515+async function publicCollect(paths: string[], runner: VitestRunner): Promise<File[]> {
517516 await runner.onBeforeCollect?.(paths)
518517519518 const files = await collectTests(paths, runner)
+2-2
packages/runner/src/setup.ts
···11import { toArray } from '@vitest/utils'
22-import type { VitestRunner, VitestRunnerConfig } from './types'
22+import type { VitestRunner, VitestRunnerConfig } from './types/runner'
3344export async function runSetupFiles(
55 config: VitestRunnerConfig,
66 runner: VitestRunner,
77-) {
77+): Promise<void> {
88 const files = toArray(config.setupFiles)
99 if (config.sequence.setupFiles === 'parallel') {
1010 await Promise.all(
+121-13
packages/runner/src/suite.ts
···2424 TestAPI,
2525 TestFunction,
2626 TestOptions,
2727-} from './types'
2727+} from './types/tasks'
2828import type { VitestRunner } from './types/runner'
2929import { createChainable } from './utils/chain'
3030import {
···3939import { mergeContextFixtures, withFixtures } from './fixture'
4040import { getCurrentTest } from './test-state'
41414242-// apis
4343-export const suite = createSuite()
4444-export const test = createTest(function (
4242+/**
4343+ * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
4444+ * Suites can contain both tests and other suites, enabling complex test structures.
4545+ *
4646+ * @param {string} name - The name of the suite, used for identification and reporting.
4747+ * @param {Function} fn - A function that defines the tests and suites within this suite.
4848+ *
4949+ * @example
5050+ * // Define a suite with two tests
5151+ * suite('Math operations', () => {
5252+ * test('should add two numbers', () => {
5353+ * expect(add(1, 2)).toBe(3);
5454+ * });
5555+ *
5656+ * test('should subtract two numbers', () => {
5757+ * expect(subtract(5, 2)).toBe(3);
5858+ * });
5959+ * });
6060+ *
6161+ * @example
6262+ * // Define nested suites
6363+ * suite('String operations', () => {
6464+ * suite('Trimming', () => {
6565+ * test('should trim whitespace from start and end', () => {
6666+ * expect(' hello '.trim()).toBe('hello');
6767+ * });
6868+ * });
6969+ *
7070+ * suite('Concatenation', () => {
7171+ * test('should concatenate two strings', () => {
7272+ * expect('hello' + ' ' + 'world').toBe('hello world');
7373+ * });
7474+ * });
7575+ * });
7676+ */
7777+export const suite: SuiteAPI = createSuite()
7878+/**
7979+ * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
8080+ *
8181+ * @param {string | Function} name - The name of the test or a function that will be used as a test name.
8282+ * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
8383+ * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
8484+ * @throws {Error} If called inside another test function.
8585+ *
8686+ * @example
8787+ * // Define a simple test
8888+ * test('should add two numbers', () => {
8989+ * expect(add(1, 2)).toBe(3);
9090+ * });
9191+ *
9292+ * @example
9393+ * // Define a test with options
9494+ * test('should subtract two numbers', { retry: 3 }, () => {
9595+ * expect(subtract(5, 2)).toBe(3);
9696+ * });
9797+ */
9898+export const test: TestAPI = createTest(function (
4599 name: string | Function,
46100 optionsOrFn?: TestOptions | TestFunction,
47101 optionsOrTest?: number | TestOptions | TestFunction,
···60114 )
61115})
621166363-// alias
6464-export const describe = suite
6565-export const it = test
117117+/**
118118+ * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
119119+ * Suites can contain both tests and other suites, enabling complex test structures.
120120+ *
121121+ * @param {string} name - The name of the suite, used for identification and reporting.
122122+ * @param {Function} fn - A function that defines the tests and suites within this suite.
123123+ *
124124+ * @example
125125+ * // Define a suite with two tests
126126+ * describe('Math operations', () => {
127127+ * test('should add two numbers', () => {
128128+ * expect(add(1, 2)).toBe(3);
129129+ * });
130130+ *
131131+ * test('should subtract two numbers', () => {
132132+ * expect(subtract(5, 2)).toBe(3);
133133+ * });
134134+ * });
135135+ *
136136+ * @example
137137+ * // Define nested suites
138138+ * describe('String operations', () => {
139139+ * describe('Trimming', () => {
140140+ * test('should trim whitespace from start and end', () => {
141141+ * expect(' hello '.trim()).toBe('hello');
142142+ * });
143143+ * });
144144+ *
145145+ * describe('Concatenation', () => {
146146+ * test('should concatenate two strings', () => {
147147+ * expect('hello' + ' ' + 'world').toBe('hello world');
148148+ * });
149149+ * });
150150+ * });
151151+ */
152152+export const describe: SuiteAPI = suite
153153+/**
154154+ * Defines a test case with a given name and test function. The test function can optionally be configured with test options.
155155+ *
156156+ * @param {string | Function} name - The name of the test or a function that will be used as a test name.
157157+ * @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
158158+ * @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
159159+ * @throws {Error} If called inside another test function.
160160+ *
161161+ * @example
162162+ * // Define a simple test
163163+ * it('adds two numbers', () => {
164164+ * expect(add(1, 2)).toBe(3);
165165+ * });
166166+ *
167167+ * @example
168168+ * // Define a test with options
169169+ * it('subtracts two numbers', { retry: 3 }, () => {
170170+ * expect(subtract(5, 2)).toBe(3);
171171+ * });
172172+ */
173173+export const it: TestAPI = test
6617467175let runner: VitestRunner
68176let defaultSuite: SuiteCollector
69177let currentTestFilepath: string
701787171-export function getDefaultSuite() {
179179+export function getDefaultSuite(): SuiteCollector<object> {
72180 return defaultSuite
73181}
741827575-export function getTestFilepath() {
183183+export function getTestFilepath(): string {
76184 return currentTestFilepath
77185}
781867979-export function getRunner() {
187187+export function getRunner(): VitestRunner {
80188 return runner
81189}
82190···89197export function clearCollectorContext(
90198 filepath: string,
91199 currentRunner: VitestRunner,
9292-) {
200200+): void {
93201 if (!defaultSuite) {
94202 defaultSuite = createDefaultSuite(currentRunner)
95203 }
···105213 || defaultSuite) as SuiteCollector<ExtraContext>
106214}
107215108108-export function createSuiteHooks() {
216216+export function createSuiteHooks(): SuiteHooks {
109217 return {
110218 beforeAll: [],
111219 afterAll: [],
···468576export function createTaskCollector(
469577 fn: (...args: any[]) => any,
470578 context?: Record<string, unknown>,
471471-) {
579579+): CustomAPI {
472580 const taskFn = fn as any
473581474582 taskFn.each = function <T>(
+2-2
packages/runner/src/test-state.ts
···11-import type { Custom, Test } from './types'
11+import type { Custom, Test } from './types/tasks.ts'
2233let _test: Test | Custom | undefined
4455-export function setCurrentTest<T extends Test | Custom>(test: T | undefined) {
55+export function setCurrentTest<T extends Test | Custom>(test: T | undefined): void {
66 _test = test
77}
88
···11// since this is already part of Vitest via Chai, we can just reuse it without increasing the size of bundle
22import * as loupe from 'loupe'
33+import type { PrettyFormatOptions } from '@vitest/pretty-format'
44+import {
55+ format as prettyFormat,
66+ plugins as prettyFormatPlugins,
77+} from '@vitest/pretty-format'
3849type Inspect = (value: unknown, options: Options) => string
510interface Options {
···18231924type LoupeOptions = Partial<Options>
20252626+const {
2727+ AsymmetricMatcher,
2828+ DOMCollection,
2929+ DOMElement,
3030+ Immutable,
3131+ ReactElement,
3232+ ReactTestComponent,
3333+} = prettyFormatPlugins
3434+3535+const PLUGINS = [
3636+ ReactTestComponent,
3737+ ReactElement,
3838+ DOMElement,
3939+ DOMCollection,
4040+ Immutable,
4141+ AsymmetricMatcher,
4242+]
4343+4444+export function stringify(
4545+ object: unknown,
4646+ maxDepth = 10,
4747+ { maxLength, ...options }: PrettyFormatOptions & { maxLength?: number } = {},
4848+): string {
4949+ const MAX_LENGTH = maxLength ?? 10000
5050+ let result
5151+5252+ try {
5353+ result = prettyFormat(object, {
5454+ maxDepth,
5555+ escapeString: false,
5656+ // min: true,
5757+ plugins: PLUGINS,
5858+ ...options,
5959+ })
6060+ }
6161+ catch {
6262+ result = prettyFormat(object, {
6363+ callToJSON: false,
6464+ maxDepth,
6565+ escapeString: false,
6666+ // min: true,
6767+ plugins: PLUGINS,
6868+ ...options,
6969+ })
7070+ }
7171+7272+ return result.length >= MAX_LENGTH && maxDepth > 1
7373+ ? stringify(object, Math.floor(maxDepth / 2))
7474+ : result
7575+}
7676+2177const formatRegExp = /%[sdjifoOc%]/g
22782323-export function format(...args: unknown[]) {
7979+export function format(...args: unknown[]): string {
2480 if (typeof args[0] !== 'string') {
2581 const objects = []
2682 for (let i = 0; i < args.length; i++) {
+10-8
packages/utils/src/error.ts
···11import { type DiffOptions, diff } from './diff'
22-import { format } from './display'
22+import { format, stringify } from './display'
33import { deepClone, getOwnProperties, getType } from './helpers'
44-import { stringify } from './stringify'
5465// utils is bundled for any environment and might not support `Element`
76declare class Element {
···2827}
29283029// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
3131-export function serializeError(val: any, seen = new WeakMap()): any {
3030+export function serializeError(val: any, seen: WeakMap<WeakKey, any> = new WeakMap()): any {
3231 if (!val || typeof val === 'string') {
3332 return val
3433 }
···113112export function processError(
114113 err: any,
115114 diffOptions?: DiffOptions,
116116- seen = new WeakSet(),
117117-) {
115115+ seen: WeakSet<WeakKey> = new WeakSet(),
116116+): any {
118117 if (!err || typeof err !== 'object') {
119118 return { message: err }
120119 }
···199198export function replaceAsymmetricMatcher(
200199 actual: any,
201200 expected: any,
202202- actualReplaced = new WeakSet(),
203203- expectedReplaced = new WeakSet(),
204204-) {
201201+ actualReplaced: WeakSet<WeakKey> = new WeakSet(),
202202+ expectedReplaced: WeakSet<WeakKey> = new WeakSet(),
203203+): {
204204+ replacedActual: any
205205+ replacedExpected: any
206206+ } {
205207 if (!isReplaceable(actual, expected)) {
206208 return { replacedActual: actual, replacedExpected: expected }
207209 }
+31-7
packages/utils/src/helpers.ts
···44 forceWritable?: boolean
55}
6677+interface ErrorOptions {
88+ message?: string
99+ stackTraceLimit?: number
1010+}
1111+1212+/**
1313+ * Get original stacktrace without source map support the most performant way.
1414+ * - Create only 1 stack frame.
1515+ * - Rewrite prepareStackTrace to bypass "support-stack-trace" (usually takes ~250ms).
1616+ */
1717+export function createSimpleStackTrace(options?: ErrorOptions): string {
1818+ const { message = '$$stack trace error', stackTraceLimit = 1 }
1919+ = options || {}
2020+ const limit = Error.stackTraceLimit
2121+ const prepareStackTrace = Error.prepareStackTrace
2222+ Error.stackTraceLimit = stackTraceLimit
2323+ Error.prepareStackTrace = e => e.stack
2424+ const err = new Error(message)
2525+ const stackTrace = err.stack || ''
2626+ Error.prepareStackTrace = prepareStackTrace
2727+ Error.stackTraceLimit = limit
2828+ return stackTrace
2929+}
3030+731export function notNullish<T>(v: T | null | undefined): v is NonNullable<T> {
832 return v != null
933}
···2246 }
2347}
24482525-export function isPrimitive(value: unknown) {
4949+export function isPrimitive(value: unknown): boolean {
2650 return (
2751 value === null || (typeof value !== 'function' && typeof value !== 'object')
2852 )
2953}
30543131-export function slash(path: string) {
5555+export function slash(path: string): string {
3256 return path.replace(/\\/g, '/')
3357}
3458···93117 Object.getOwnPropertySymbols(obj).forEach(collect)
94118}
951199696-export function getOwnProperties(obj: any) {
120120+export function getOwnProperties(obj: any): (string | symbol)[] {
97121 const ownProps = new Set<string | symbol>()
98122 if (isFinalObj(obj)) {
99123 return []
···170194 return val
171195}
172196173173-export function noop() {}
197197+export function noop(): void {}
174198175199export function objectAttr(
176200 source: any,
177201 path: string,
178202 defaultValue = undefined,
179179-) {
203203+): any {
180204 // a[3].b -> a.3.b
181205 const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')
182206 let result = source
···217241 * toBeAliased('123')
218242 * ```
219243 */
220220-export function getCallLastIndex(code: string) {
244244+export function getCallLastIndex(code: string): number | null {
221245 let charIndex = -1
222246 let inString: string | null = null
223247 let startedBracers = 0
···255279 return null
256280}
257281258258-export function isNegativeNaN(val: number) {
282282+export function isNegativeNaN(val: number): boolean {
259283 if (!Number.isNaN(val)) {
260284 return false
261285 }
···11import { processError } from '@vitest/utils/error'
22import { relative } from 'pathe'
33-import type { File, Suite, TaskBase } from '../types'
33+import type { File, Suite, TaskBase } from '../types/tasks'
4455/**
66 * If any tasks been marked as `only`, mark all other tasks as `skip`.
···1111 onlyMode?: boolean,
1212 parentIsOnly?: boolean,
1313 allowOnly?: boolean,
1414-) {
1414+): void {
1515 const suiteIsOnly = parentIsOnly || suite.mode === 'only'
16161717 suite.tasks.forEach((t) => {
···105105 return `${hash}`
106106}
107107108108-export function calculateSuiteHash(parent: Suite) {
108108+export function calculateSuiteHash(parent: Suite): void {
109109 parent.tasks.forEach((t, idx) => {
110110 t.id = `${parent.id}_${idx}`
111111 if (t.type === 'suite') {
···119119 root: string,
120120 projectName: string,
121121 pool?: string,
122122-) {
122122+): File {
123123 const path = relative(root, filepath)
124124 const file: File = {
125125 id: generateHash(`${path}${projectName || ''}`),
+19-5
packages/runner/src/utils/index.ts
···11-export * from './collect'
22-export * from './suite'
33-export * from './tasks'
44-export * from './chain'
55-export * from './limit-concurrency'
11+export {
22+ interpretTaskModes,
33+ someTasksAreOnly,
44+ generateHash,
55+ calculateSuiteHash,
66+ createFileTask,
77+} from './collect'
88+export { partitionSuiteChildren } from './suite'
99+export {
1010+ isAtomTest,
1111+ getTests,
1212+ getTasks,
1313+ getSuites,
1414+ hasTests,
1515+ hasFailed,
1616+ getNames,
1717+} from './tasks'
1818+export { createChainable, type ChainableFunction } from './chain'
1919+export { limitConcurrency } from './limit-concurrency'
+1-1
packages/runner/src/utils/limit-concurrency.ts
···44/**
55 * Return a function for running multiple async operations with limited concurrency.
66 */
77-export function limitConcurrency(concurrency = Infinity): <Args extends unknown[], T>(func: (...args: Args) => PromiseLike<T> | T, ...args: Args) => Promise<T> {
77+export function limitConcurrency(concurrency: number = Infinity): <Args extends unknown[], T>(func: (...args: Args) => PromiseLike<T> | T, ...args: Args) => Promise<T> {
88 // The number of currently active + pending tasks.
99 let count = 0
1010
+2-2
packages/runner/src/utils/suite.ts
···11-import type { Suite, Task } from '../types'
11+import type { Suite, Task } from '../types/tasks'
2233/**
44 * Partition in tasks groups by consecutive concurrent
55 */
66-export function partitionSuiteChildren(suite: Suite) {
66+export function partitionSuiteChildren(suite: Suite): Task[][] {
77 let tasksGroup: Task[] = []
88 const tasksGroups: Task[][] = []
99 for (const c of suite.tasks) {
+2-2
packages/runner/src/utils/tasks.ts
···11import { type Arrayable, toArray } from '@vitest/utils'
22-import type { Custom, Suite, Task, Test } from '../types'
22+import type { Custom, Suite, Task, Test } from '../types/tasks'
3344export function isAtomTest(s: Task): s is Test | Custom {
55 return s.type === 'test' || s.type === 'custom'
···5454 )
5555}
56565757-export function getNames(task: Task) {
5757+export function getNames(task: Task): string[] {
5858 const names = [task.name]
5959 let current: Task | undefined = task
6060
···189189 * Reduce the number of edits by eliminating semantically trivial equalities.
190190 * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
191191 */
192192-const diff_cleanupSemantic = function (diffs: Array<Diff>) {
192192+const diff_cleanupSemantic = function (diffs: Array<Diff>): void {
193193 let changes = false
194194 const equalities = [] // Stack of indices where equalities are found.
195195 let equalitiesLength = 0 // Keeping our own length var is faster in JS.
+2-2
packages/utils/src/diff/constants.ts
···55 * LICENSE file in the root directory of this source tree.
66 */
7788-export const NO_DIFF_MESSAGE = 'Compared values have no visual difference.'
88+export const NO_DIFF_MESSAGE: string = 'Compared values have no visual difference.'
991010-export const SIMILAR_MESSAGE
1010+export const SIMILAR_MESSAGE: string
1111 = 'Compared values serialize to the same structure.\n'
1212 + 'Printing internal object structure without calling `toJSON` instead.'