diff --git a/docs/api/index.md b/docs/api/index.md index 7e2576977298..ee69e878d9ce 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -940,7 +940,7 @@ These hooks will throw an error if they are called outside of the test body. This hook is always called after the test has finished running. It is called after `afterEach` hooks since they can influence the test result. It receives a `TaskResult` object with the current test result. -```ts +```ts {1,5} import { onTestFinished, test } from 'vitest' test('performs a query', () => { @@ -953,12 +953,12 @@ test('performs a query', () => { ::: warning If you are running tests concurrently, you should always use `onTestFinished` hook from the test context since Vitest doesn't track concurrent tests in global hooks: -```ts +```ts {3,5} import { test } from 'vitest' -test.concurrent('performs a query', (t) => { +test.concurrent('performs a query', ({ onTestFinished }) => { const db = connectDb() - t.onTestFinished(() => db.close()) + onTestFinished(() => db.close()) db.query('SELECT * FROM users') }) ``` @@ -993,7 +993,7 @@ test('performs an organization query', async () => { This hook is called only after the test has failed. It is called after `afterEach` hooks since they can influence the test result. It receives a `TaskResult` object with the current test result. This hook is useful for debugging. -```ts +```ts {1,5-7} import { onTestFailed, test } from 'vitest' test('performs a query', () => { @@ -1008,10 +1008,10 @@ test('performs a query', () => { ::: warning If you are running tests concurrently, you should always use `onTestFailed` hook from the test context since Vitest doesn't track concurrent tests in global hooks: -```ts +```ts {3,5-7} import { test } from 'vitest' -test.concurrent('performs a query', (t) => { +test.concurrent('performs a query', ({ onTestFailed }) => { const db = connectDb() onTestFailed((result) => { console.log(result.errors) diff --git a/docs/config/index.md b/docs/config/index.md index c7ab349fd30a..c0d73e06e1ae 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -1736,18 +1736,10 @@ Test above this limit will be queued to run when available slot appears. ### cache -- **Type**: `false | { dir? }` +- **Type**: `false` - **CLI**: `--no-cache`, `--cache=false` -Options to configure Vitest cache policy. At the moment Vitest stores cache for test results to run the longer and failed tests first. - -#### cache.dir - -- **Type**: `string` -- **Default**: `node_modules/.vitest` -- **CLI**: `--cache.dir=./cache` - -Path to cache directory. +Use this option if you want to disable the cache feature. At the moment Vitest stores cache for test results to run the longer and failed tests first. ### sequence @@ -1964,7 +1956,7 @@ Retry the test specific number of times if it fails. ### onConsoleLog -- **Type**: `(log: string, type: 'stdout' | 'stderr') => false | void` +- **Type**: `(log: string, type: 'stdout' | 'stderr') => boolean | void` Custom handler for `console.log` in tests. If you return `false`, Vitest will not print the log to the console. @@ -1975,9 +1967,8 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { - onConsoleLog(log: string, type: 'stdout' | 'stderr'): false | void { - if (log === 'message from third party library' && type === 'stdout') - return false + onConsoleLog(log: string, type: 'stdout' | 'stderr'): boolean | void { + return !(log === 'message from third party library' && type === 'stdout') }, }, }) diff --git a/examples/playwright/test/basic.test.ts b/examples/playwright/test/basic.test.ts index 44cee93046d7..4c6631c55b81 100644 --- a/examples/playwright/test/basic.test.ts +++ b/examples/playwright/test/basic.test.ts @@ -20,9 +20,10 @@ describe.runIf(process.platform !== 'win32')('basic', async () => { }) afterAll(async () => { - await browser.close() + // hook timed out and we already have another error + await browser?.close() await new Promise((resolve, reject) => { - server.httpServer.close(error => error ? reject(error) : resolve()) + server?.httpServer.close(error => error ? reject(error) : resolve()) }) }) diff --git a/package.json b/package.json index 7ad6f1127b27..a2f527c5c5ab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/monorepo", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "private": true, "packageManager": "pnpm@8.10.3", "description": "Next generation testing framework powered by Vite", diff --git a/packages/browser/package.json b/packages/browser/package.json index 50bd9fe486c9..e645b755552a 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/browser", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Browser running for Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/browser/src/client/runner.ts b/packages/browser/src/client/runner.ts index 1725b93883d2..f316715a541d 100644 --- a/packages/browser/src/client/runner.ts +++ b/packages/browser/src/client/runner.ts @@ -127,7 +127,7 @@ async function updateFilesLocations(files: File[]) { if (task.location) { const { line, column } = originalPositionFor(traceMap, task.location) if (line != null && column != null) - task.location = { line, column: column + 1 } + task.location = { line, column: task.each ? column : column + 1 } } if ('tasks' in task) task.tasks.forEach(updateLocation) diff --git a/packages/coverage-istanbul/package.json b/packages/coverage-istanbul/package.json index c0887f07f678..df6732f1a85b 100644 --- a/packages/coverage-istanbul/package.json +++ b/packages/coverage-istanbul/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/coverage-istanbul", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Istanbul coverage provider for Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/coverage-v8/package.json b/packages/coverage-v8/package.json index d01b01765276..33cf11cae857 100644 --- a/packages/coverage-v8/package.json +++ b/packages/coverage-v8/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/coverage-v8", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "V8 coverage provider for Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/expect/package.json b/packages/expect/package.json index 7557cf28aa2d..cd29c7bd7c73 100644 --- a/packages/expect/package.json +++ b/packages/expect/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/expect", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Jest's expect matchers as a Chai plugin", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/runner/package.json b/packages/runner/package.json index c35d6b56d047..ca6e0e7f40ea 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/runner", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Vitest test runner", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/runner/src/suite.ts b/packages/runner/src/suite.ts index 0f5feb6b787d..b1761b5c20fc 100644 --- a/packages/runner/src/suite.ts +++ b/packages/runner/src/suite.ts @@ -153,7 +153,7 @@ function createSuiteCollector(name: string, factory: SuiteFactory = () => { }, m Error.stackTraceLimit = 10 const error = new Error('stacktrace').stack! Error.stackTraceLimit = limit - const stack = findStackTrace(error) + const stack = findStackTrace(error, task.each ?? false) if (stack) task.location = stack } @@ -226,7 +226,9 @@ function createSuiteCollector(name: string, factory: SuiteFactory = () => { }, m if (stack) { suite.location = { line: stack.line, - column: stack.column, + // because source map is boundary based, this line leads to ")" in test.each()[(]), + // but it should be the next opening bracket - here we assume it's on the same line + column: each ? stack.column + 1 : stack.column, } } } @@ -430,7 +432,7 @@ function formatTemplateString(cases: any[], args: any[]): any[] { return res } -function findStackTrace(error: string) { +function findStackTrace(error: string, each: boolean) { // first line is the error message // and the first 3 stacks are always from the collector const lines = error.split('\n').slice(4) @@ -439,7 +441,13 @@ function findStackTrace(error: string) { if (stack && stack.file === getTestFilepath()) { return { line: stack.line, - column: stack.column, + /** + * test.each([1, 2])('name') + * ^ leads here, but should + * ^ lead here + * in source maps it's the same boundary, so it just points to the start of it + */ + column: each ? stack.column + 1 : stack.column, } } } diff --git a/packages/snapshot/package.json b/packages/snapshot/package.json index d5d49f769722..5c7eff4acf75 100644 --- a/packages/snapshot/package.json +++ b/packages/snapshot/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/snapshot", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Vitest snapshot manager", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/spy/package.json b/packages/spy/package.json index 90e61ed1a47b..29d66681d392 100644 --- a/packages/spy/package.json +++ b/packages/spy/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/spy", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Lightweight Jest compatible spy implementation", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/ui/package.json b/packages/ui/package.json index 7f03bae2ae92..191131452671 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/ui", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "UI for Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/utils/package.json b/packages/utils/package.json index e2876799baa8..cc5cc8d38698 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/utils", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Shared Vitest utility functions", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 7ad8e7725d85..75503d358839 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -1,7 +1,7 @@ { "name": "vite-node", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Vite as Node.js runtime", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 886cc1966ec0..c41c7faa182c 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -1,7 +1,7 @@ { "name": "vitest", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Next generation testing framework powered by Vite", "author": "Anthony Fu ", "license": "MIT", diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index 754406300697..f236f08816e0 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -200,7 +200,7 @@ export class WebSocketReporter implements Reporter { if (this.clients.size === 0) return this.clients.forEach((client) => { - client.onCollected?.(files).catch(noop) + client.onCollected?.(files)?.catch?.(noop) }) } @@ -222,25 +222,25 @@ export class WebSocketReporter implements Reporter { }) this.clients.forEach((client) => { - client.onTaskUpdate?.(packs).catch(noop) + client.onTaskUpdate?.(packs)?.catch?.(noop) }) } onFinished(files?: File[], errors?: unknown[]) { this.clients.forEach((client) => { - client.onFinished?.(files, errors).catch(noop) + client.onFinished?.(files, errors)?.catch?.(noop) }) } onFinishedReportCoverage() { this.clients.forEach((client) => { - client.onFinishedReportCoverage?.().catch(noop) + client.onFinishedReportCoverage?.()?.catch?.(noop) }) } onUserConsoleLog(log: UserConsoleLog) { this.clients.forEach((client) => { - client.onUserConsoleLog?.(log).catch(noop) + client.onUserConsoleLog?.(log)?.catch?.(noop) }) } } diff --git a/packages/vitest/src/node/cache/index.ts b/packages/vitest/src/node/cache/index.ts index 6783736ba23a..209722e78862 100644 --- a/packages/vitest/src/node/cache/index.ts +++ b/packages/vitest/src/node/cache/index.ts @@ -21,8 +21,8 @@ export class VitestCache { return this.stats.getStats(key) } - static resolveCacheDir(root: string, dir: string | undefined, projectName: string | undefined) { - const baseDir = slash(dir || 'node_modules/.vitest') + static resolveCacheDir(root: string, dir?: string, projectName?: string) { + const baseDir = slash(dir || 'node_modules/.vite/vitest') return projectName ? resolve(root, baseDir, crypto.createHash('md5').update(projectName, 'utf-8').digest('hex')) : resolve(root, baseDir) diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 622fb13f50a7..b5e16b9f526c 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -549,14 +549,13 @@ export const cliOptionsConfig: VitestCLIOptions = { description: 'Enable cache', argument: '', // allow only boolean subcommands: { - dir: { - description: 'Path to the cache directory', - argument: '', - normalize: true, - }, + dir: null, }, + default: true, // cache can only be "false" or an object transform(cache) { + if (typeof cache !== 'boolean' && cache) + throw new Error('--cache.dir is deprecated') if (cache) return {} return cache diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index a6d3b3810a85..9d1c96a18fa3 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -446,9 +446,21 @@ export function resolveConfig( resolved.css.modules.classNameStrategy ??= 'stable' } - resolved.cache ??= { dir: '' } - if (resolved.cache) - resolved.cache.dir = VitestCache.resolveCacheDir(resolved.root, resolved.cache.dir, resolved.name) + if (resolved.cache !== false) { + let cacheDir = VitestCache.resolveCacheDir('', resolve(viteConfig.cacheDir, 'vitest'), resolved.name) + + if (resolved.cache && resolved.cache.dir) { + console.warn( + c.yellow( + `${c.inverse(c.yellow(' Vitest '))} "cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest"`, + ), + ) + + cacheDir = VitestCache.resolveCacheDir(resolved.root, resolved.cache.dir, resolved.name) + } + + resolved.cache = { dir: cacheDir } + } resolved.sequence ??= {} as any if (resolved.sequence.shuffle && typeof resolved.sequence.shuffle === 'object') { diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index a2d3d3154a2a..18146a0c1e4f 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -13,7 +13,6 @@ import type { defineWorkspace } from 'vitest/config' import type { ArgumentsType, CoverageProvider, OnServerRestartHandler, Reporter, ResolvedConfig, UserConfig, UserWorkspaceConfig, VitestRunMode } from '../types' import { hasFailed, noop, slash, toArray, wildcardPatternToRegExp } from '../utils' import { getCoverageProvider } from '../integrations/coverage' -import type { BrowserProvider } from '../types/browser' import { CONFIG_NAMES, configFiles, workspacesFiles as workspaceFiles } from '../constants' import { rootDir } from '../paths' import { WebSocketReporter } from '../api/setup' @@ -43,7 +42,6 @@ export class Vitest { cache: VitestCache = undefined! reporters: Reporter[] = undefined! coverageProvider: CoverageProvider | null | undefined - browserProvider: BrowserProvider | undefined logger: Logger pool: ProcessPool | undefined @@ -51,6 +49,7 @@ export class Vitest { invalidates: Set = new Set() changedTests: Set = new Set() + watchedTests: Set = new Set() filenamePattern?: string runningPromise?: Promise closingPromise?: Promise @@ -623,6 +622,14 @@ export class Vitest { return this._rerunTimer = setTimeout(async () => { + // run only watched tests + if (this.watchedTests.size) { + this.changedTests.forEach((test) => { + if (!this.watchedTests.has(test)) + this.changedTests.delete(test) + }) + } + if (this.changedTests.size === 0) { this.invalidates.clear() return @@ -665,6 +672,15 @@ export class Vitest { }) } + /** + * Watch only the specified tests. If no tests are provided, all tests will be watched. + */ + public watchTests(tests: string[]) { + this.watchedTests = new Set( + tests.map(test => slash(test)), + ) + } + private unregisterWatcher = noop private registerWatcher() { const updateLastChanged = (filepath: string) => { diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 09969d21f1bf..c0b1d9b237b0 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -45,8 +45,8 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t const testConfig = deepMerge( {} as UserConfig, configDefaults, - options, removeUndefinedValues(viteConfig.test ?? {}), + options, ) testConfig.api = resolveApiServerConfig(testConfig) diff --git a/packages/vitest/src/runtime/console.ts b/packages/vitest/src/runtime/console.ts index 45f8a7b20718..14ea15532325 100644 --- a/packages/vitest/src/runtime/console.ts +++ b/packages/vitest/src/runtime/console.ts @@ -85,7 +85,7 @@ export function createCustomConsole(state: WorkerGlobalState) { const stdout = new Writable({ write(data, encoding, callback) { - const id = state?.current?.id ?? getTaskIdByStack(state.ctx.config.root) + const id = state?.current?.id || state?.current?.file?.id || getTaskIdByStack(state.ctx.config.root) let timer = timers.get(id) if (timer) { timer.stdoutTime = timer.stdoutTime || RealDate.now() @@ -106,7 +106,7 @@ export function createCustomConsole(state: WorkerGlobalState) { }) const stderr = new Writable({ write(data, encoding, callback) { - const id = state?.current?.id ?? getTaskIdByStack(state.ctx.config.root) + const id = state?.current?.id || state?.current?.file?.id || getTaskIdByStack(state.ctx.config.root) let timer = timers.get(id) if (timer) { timer.stderrTime = timer.stderrTime || RealDate.now() diff --git a/packages/vitest/src/runtime/runners/test.ts b/packages/vitest/src/runtime/runners/test.ts index c79231941708..e567506e75fc 100644 --- a/packages/vitest/src/runtime/runners/test.ts +++ b/packages/vitest/src/runtime/runners/test.ts @@ -27,6 +27,10 @@ export class VitestTestRunner implements VitestRunner { this.snapshotClient.clear() } + onAfterRunFiles() { + this.workerState.current = undefined + } + async onAfterRunSuite(suite: Suite) { if (this.config.logHeapUsage && typeof process !== 'undefined') suite.result!.heap = process.memoryUsage().heapUsed @@ -44,6 +48,8 @@ export class VitestTestRunner implements VitestRunner { if (result) await rpc().snapshotSaved(result) } + + this.workerState.current = suite.suite } onAfterRunTask(test: Task) { @@ -52,7 +58,7 @@ export class VitestTestRunner implements VitestRunner { if (this.config.logHeapUsage && typeof process !== 'undefined') test.result!.heap = process.memoryUsage().heapUsed - this.workerState.current = undefined + this.workerState.current = test.suite } onCancel(_reason: CancelReason) { @@ -81,6 +87,8 @@ export class VitestTestRunner implements VitestRunner { // (e.g. `toMatchSnapshot`) specifies "filepath" / "name" pair explicitly await this.snapshotClient.startCurrentRun(suite.filepath, '__default_name_', this.workerState.config.snapshotOptions) } + + this.workerState.current = suite } onBeforeTryTask(test: Task) { diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 3dc2d42ef633..f75c660558c1 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -624,10 +624,13 @@ export interface InlineConfig { /** * Options for configuring cache policy. - * @default { dir: 'node_modules/.vitest' } + * @default { dir: 'node_modules/.vite/vitest' } */ cache?: false | { - dir?: string + /** + * @deprecated Use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir\/vitest". + */ + dir: string } /** @@ -854,6 +857,9 @@ export interface ResolvedConfig extends Omit, 'config' | 'f } cache: { + /** + * @deprecated + */ dir: string } | false diff --git a/packages/web-worker/package.json b/packages/web-worker/package.json index 930586920df9..dae5b31f084a 100644 --- a/packages/web-worker/package.json +++ b/packages/web-worker/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/web-worker", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "Web Worker support for testing in Vitest", "license": "MIT", "funding": "https://opencollective.com/vitest", diff --git a/packages/ws-client/package.json b/packages/ws-client/package.json index 67782a4a93b0..05ffc7751cae 100644 --- a/packages/ws-client/package.json +++ b/packages/ws-client/package.json @@ -1,7 +1,7 @@ { "name": "@vitest/ws-client", "type": "module", - "version": "1.3.1", + "version": "1.4.0", "description": "WebSocket client wrapper for communicating with Vitest", "author": "Anthony Fu ", "license": "MIT", diff --git a/test/config/fixtures/cache/basic.test.ts b/test/config/fixtures/cache/basic.test.ts new file mode 100644 index 000000000000..36c7cc207dde --- /dev/null +++ b/test/config/fixtures/cache/basic.test.ts @@ -0,0 +1,5 @@ +import { expect, test } from "vitest"; + +test('', () => { + expect(true).toBe(true) +}) diff --git a/test/config/test/cache.test.ts b/test/config/test/cache.test.ts new file mode 100644 index 000000000000..379ddbc93d38 --- /dev/null +++ b/test/config/test/cache.test.ts @@ -0,0 +1,123 @@ +import { describe, expect, test } from 'vitest' +import { resolve } from 'pathe' +import { runVitest } from '../../test-utils' + +const root = resolve(__dirname, '../fixtures/cache') +const project = resolve(__dirname, '../') + +test('default', async () => { + const { vitest, stdout, stderr } = await runVitest({ + root, + include: ['*.test.ts'], + }) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toBe('') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(project, 'node_modules/.vite/vitest/results.json') + expect(cachePath).toMatch(path) +}) + +test('use cache.dir', async () => { + const { vitest, stdout, stderr } = await runVitest( + { + root, + include: ['*.test.ts'], + cache: { + dir: 'node_modules/.vitest-custom', + }, + }, + ) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toContain('"cache.dir" is deprecated') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(root, 'node_modules/.vitest-custom/results.json') + expect(cachePath).toMatch(path) +}) + +test('use cacheDir', async () => { + const { vitest, stdout, stderr } = await runVitest( + { + root, + include: ['*.test.ts'], + }, + [], + 'test', + { cacheDir: 'node_modules/.vite-custom' }, + ) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toBe('') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(root, 'node_modules/.vite-custom/vitest/results.json') + expect(cachePath).toMatch(path) +}) + +describe('with optimizer enabled', () => { + const deps = { + optimizer: { + web: { + enabled: true, + }, + }, + } + + test('default', async () => { + const { vitest, stdout, stderr } = await runVitest({ + root, + include: ['*.test.ts'], + deps, + }) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toBe('') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(project, 'node_modules/.vite/vitest/results.json') + expect(cachePath).toBe(path) + }) + + test('use cache.dir', async () => { + const { vitest, stdout, stderr } = await runVitest( + { + root, + include: ['*.test.ts'], + deps, + cache: { + dir: 'node_modules/.vitest-custom', + }, + }, + ) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toContain('"cache.dir" is deprecated') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(root, 'node_modules/.vitest-custom/results.json') + expect(cachePath).toBe(path) + }) + + test('use cacheDir', async () => { + const { vitest, stdout, stderr } = await runVitest( + { + root, + include: ['*.test.ts'], + deps, + }, + [], + 'test', + { cacheDir: 'node_modules/.vite-custom' }, + ) + + expect(stdout).toContain('✓ basic.test.ts >') + expect(stderr).toBe('') + + const cachePath = vitest!.cache.results.getCachePath() + const path = resolve(root, 'node_modules/.vite-custom/vitest/results.json') + expect(cachePath).toBe(path) + }) +}) diff --git a/test/config/test/resolution.test.ts b/test/config/test/resolution.test.ts index 63d6009dbfc3..f36b522e5831 100644 --- a/test/config/test/resolution.test.ts +++ b/test/config/test/resolution.test.ts @@ -235,3 +235,31 @@ describe('correctly defines inline and noExternal flags', async () => { ]) }) }) + +describe('correctly defines api flag', () => { + it('CLI overrides disabling api', async () => { + const c = await vitest({ api: false }, { + api: { + port: 1234, + }, + watch: true, + }) + expect(c.server.config.server.middlewareMode).toBe(true) + expect(c.config.api).toEqual({ + middlewareMode: true, + }) + }) + + it('CLI overrides inlined value', async () => { + const c = await vitest({ api: { port: 4321 } }, { + api: { + port: 1234, + }, + watch: true, + }) + expect(c.server.config.server.port).toBe(4321) + expect(c.config.api).toEqual({ + port: 4321, + }) + }) +}) diff --git a/test/core/test/cli-test.test.ts b/test/core/test/cli-test.test.ts index 90f5123799d4..1d4a3ce636cf 100644 --- a/test/core/test/cli-test.test.ts +++ b/test/core/test/cli-test.test.ts @@ -213,16 +213,7 @@ test('maxConcurrency is parsed correctly', () => { test('cache is parsed correctly', () => { expect(getCLIOptions('--cache')).toEqual({ cache: {} }) expect(getCLIOptions('--no-cache')).toEqual({ cache: false }) - - expect(getCLIOptions('--cache.dir=./test/cache.json')).toEqual({ - cache: { dir: 'test/cache.json' }, - }) - expect(getCLIOptions('--cache.dir ./test/cache.json')).toEqual({ - cache: { dir: 'test/cache.json' }, - }) - expect(getCLIOptions('--cache.dir .\\test\\cache.json')).toEqual({ - cache: { dir: 'test/cache.json' }, - }) + expect(() => getCLIOptions('--cache.dir=./cache')).toThrowError('--cache.dir is deprecated') }) test('shuffle is parsed correctly', () => { diff --git a/test/optimize-deps/test/ssr.test.ts b/test/optimize-deps/test/ssr.test.ts index dc59d558b84b..38d519ecad22 100644 --- a/test/optimize-deps/test/ssr.test.ts +++ b/test/optimize-deps/test/ssr.test.ts @@ -8,5 +8,5 @@ import { importMetaUrl } from '@vitest/test-dep-url' // TODO: flaky on Windows // https://github.com/vitest-dev/vitest/pull/5215#discussion_r1492066033 test.skipIf(process.platform === 'win32')('import.meta.url', () => { - expect(importMetaUrl).toContain('/node_modules/.vitest/deps_ssr/') + expect(importMetaUrl).toContain('/node_modules/.vite/vitest/deps_ssr/') }) diff --git a/test/optimize-deps/test/web.test.ts b/test/optimize-deps/test/web.test.ts index 308e7730640f..88af98f6f4af 100644 --- a/test/optimize-deps/test/web.test.ts +++ b/test/optimize-deps/test/web.test.ts @@ -6,5 +6,5 @@ import { expect, test } from 'vitest' import { importMetaUrl } from '@vitest/test-dep-url' test('import.meta.url', () => { - expect(importMetaUrl).toContain('/node_modules/.vitest/deps/') + expect(importMetaUrl).toContain('/node_modules/.vite/vitest/deps/') }) diff --git a/test/public-api/fixtures/custom.spec.ts b/test/public-api/fixtures/custom.spec.ts index 6d604c5b15a4..866ee53f9a0e 100644 --- a/test/public-api/fixtures/custom.spec.ts +++ b/test/public-api/fixtures/custom.spec.ts @@ -14,3 +14,7 @@ afterAll((suite) => { test('custom', ({ task }) => { task.meta.custom = 'some-custom-hanlder' }) + +test.each([1, 2])('custom %s', () => { + // support locations +}) diff --git a/test/public-api/tests/runner.spec.ts b/test/public-api/tests/runner.spec.ts index e8160d4aa7f9..963c9d06c3fe 100644 --- a/test/public-api/tests/runner.spec.ts +++ b/test/public-api/tests/runner.spec.ts @@ -47,7 +47,7 @@ it.each([ const suiteMeta = { done: true } const testMeta = { custom: 'some-custom-hanlder' } - expect(taskUpdate).toHaveLength(2) + expect(taskUpdate).toHaveLength(4) expect(finishedFiles).toHaveLength(1) const files = vitest?.state.getFiles() || [] @@ -87,4 +87,13 @@ it.each([ line: 14, column: 1, }) + + const eachTests = [1, 2] + eachTests.forEach((name, index) => { + expect(files[0].tasks[index + 1].name).toBe(`custom ${name}`) + expect(files[0].tasks[index + 1].location).toEqual({ + line: 18, + column: 18, + }) + }) }) diff --git a/test/reporters/fixtures/console.test.ts b/test/reporters/fixtures/console.test.ts new file mode 100644 index 000000000000..dde0264286f0 --- /dev/null +++ b/test/reporters/fixtures/console.test.ts @@ -0,0 +1,39 @@ +import { afterAll, beforeAll, describe, expect, test } from 'vitest' + +beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') +}) + +afterAll(() => { + console.log('afterAll') + console.error('afterAll') +}) + +describe('suite', () => { + beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') + }) + + afterAll(() => { + console.log('afterAll') + console.error('afterAll') + }) + + describe('nested suite', () => { + beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') + }) + + afterAll(() => { + console.log('afterAll') + console.error('afterAll') + }) + + test('test', () => { + expect(true).toBe(true) + }) + }) +}) diff --git a/test/reporters/tests/console.test.ts b/test/reporters/tests/console.test.ts new file mode 100644 index 000000000000..b84f6e8f968f --- /dev/null +++ b/test/reporters/tests/console.test.ts @@ -0,0 +1,41 @@ +import { resolve } from 'pathe' +import { expect, test } from 'vitest' +import { runVitest } from '../../test-utils' + +test('should print logs correctly', async () => { + const filename = resolve('./fixtures/console.test.ts') + const { stdout, stderr } = await runVitest({ root: './fixtures' }, [filename]) + + expect(stdout).toBeTruthy() + expect(stderr).toBeTruthy() + + expect(stdout).toContain( +` +stdout | console.test.ts > suite > nested suite +beforeAll +afterAll + +stdout | console.test.ts > suite +beforeAll +afterAll + +stdout | console.test.ts +beforeAll +afterAll +`, + ) + + expect(stderr).toContain( +`stderr | console.test.ts > suite > nested suite +beforeAll +afterAll + +stderr | console.test.ts > suite +beforeAll +afterAll + +stderr | console.test.ts +beforeAll +afterAll`, + ) +}) diff --git a/test/ui/fixtures/console.test.ts b/test/ui/fixtures/console.test.ts index 2550b9a32503..8318c03bd7aa 100644 --- a/test/ui/fixtures/console.test.ts +++ b/test/ui/fixtures/console.test.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -import { it } from "vitest"; -import { prettyDOM } from "@testing-library/dom" +import { afterAll, beforeAll, it, describe, expect } from "vitest"; +import { prettyDOM } from "@testing-library/dom"; // https://github.com/vitest-dev/vitest/issues/2765 it('regexp', () => { @@ -31,3 +31,42 @@ it('html-pretty', () => { `.replaceAll(/\n */gm, ""); // strip new liens console.log(prettyDOM(div)) }) + + +beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') +}) + +afterAll(() => { + console.log('afterAll') + console.error('afterAll') +}) + +describe('suite', () => { + beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') + }) + + afterAll(() => { + console.log('afterAll') + console.error('afterAll') + }) + + describe('nested suite', () => { + beforeAll(() => { + console.log('beforeAll') + console.error('beforeAll') + }) + + afterAll(() => { + console.log('afterAll') + console.error('afterAll') + }) + + it('test', () => { + expect(true).toBe(true) + }) + }) +}) diff --git a/test/ui/test/html-report.spec.ts b/test/ui/test/html-report.spec.ts index 0fd7530b024d..b7b732460684 100644 --- a/test/ui/test/html-report.spec.ts +++ b/test/ui/test/html-report.spec.ts @@ -32,7 +32,7 @@ test.describe('html report', () => { await page.goto(pageUrl) // dashbaord - await expect(page.locator('[aria-labelledby=tests]')).toContainText('5 Pass 1 Fail 6 Total') + await expect(page.locator('[aria-labelledby=tests]')).toContainText('6 Pass 1 Fail 7 Total') // unhandled errors await expect(page.getByTestId('unhandled-errors')).toContainText( diff --git a/test/ui/test/ui.spec.ts b/test/ui/test/ui.spec.ts index a54e1a2c608d..e2703dffed0c 100644 --- a/test/ui/test/ui.spec.ts +++ b/test/ui/test/ui.spec.ts @@ -23,7 +23,7 @@ test.describe('ui', () => { await page.goto(pageUrl) // dashbaord - await expect(page.locator('[aria-labelledby=tests]')).toContainText('5 Pass 1 Fail 6 Total') + await expect(page.locator('[aria-labelledby=tests]')).toContainText('6 Pass 1 Fail 7 Total') // unhandled errors await expect(page.getByTestId('unhandled-errors')).toContainText( @@ -61,6 +61,9 @@ test.describe('ui', () => { await page.getByText('fixtures/console.test.ts').click() await page.getByTestId('btn-console').click() await page.getByText('/(?\\w)/').click() + + expect(await page.getByText('beforeAll').all()).toHaveLength(6) + expect(await page.getByText('afterAll').all()).toHaveLength(6) }) test('error', async ({ page }) => {