new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Vitest · Guide · all subjects

advanced/node-api

97 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

parseCLI usage example

Example of parsing CLI arguments: import { parseCLI } from 'vitest/node' const result = parseCLI('vitest ./files.ts --coverage --browser=chrome') result.options // { // coverage: { enabled: true }, // browser: { name: 'chrome', enabled: true } // } result.filter // ['./files.ts']

Logger usage example with custom streams

Example of constructing a Logger with custom stdout/stderr streams to capture or redirect Vitest's output when running it programmatically: import { Logger } from 'vitest/node' const logger = new Logger(process.stdout, process.stderr)

Logger class definition and import

The Logger class can be imported from 'vitest/node' entry-point. Its constructor signature is: constructor(outputStream?: Writable, errorStream?: Writable). It is Vitest's terminal logger exposed as vitest.logger and handles formatted output, the error summary, the run banner and screen clearing.

PluginHarness usage and purpose

PluginHarness is an advanced, plugin-facing API that you rarely construct directly. You can pass a shared instance to resolveConfig to reuse a logger and package installer across multiple calls.

PluginHarness class definition

The PluginHarness is a class that serves as a container Vitest passes to its internal plugins while the config is being resolved, before a Vitest instance exists. Its properties and methods are: vitest?: Vitest, version: string, logger: Logger, packageInstaller: VitestPackageInstaller, and getVitest(): Vitest. It holds the Logger and package installer and resolved version, and exposes the Vitest instance via getVitest() once it has been created.

createCLI usage example

Example of creating the Vitest CLI parser: import { createCLI } from 'vitest/node' const cli = createCLI()

startVitest function signature and import

The startVitest function can be imported from 'vitest/node' entry-point. Its signature is: function startVitest(cliFilters: string[] = [], options: CliOptions = {}, viteOverrides?: ViteUserConfig, vitestOptions?: VitestOptions): Promise<Vitest>. It returns a Vitest instance if tests can be started. If watch mode is not enabled, Vitest will call the close method automatically. If watch mode is enabled and the terminal supports TTY, Vitest will register console shortcuts.

startVitest basic usage example

Example of starting Vitest using the Node API: import { startVitest } from 'vitest/node' const vitest = await startVitest() await vitest.close()

createCLI function signature and import

The createCLI function can be imported from 'vitest/node' entry-point. Its signature is: function createCLI(options?: CliParseOptions): CAC. It creates the Vitest command-line interface: a cac instance with all of Vitest's commands and options registered. parseCLI is built on top of it; use createCLI directly if you need the raw parser.

startVitest filters for running specific tests

You can pass down a list of filters as the first argument to startVitest. Vitest will run only tests that contain at least one of the passed-down strings in their file path.

startVitest arguments for overriding config and retrieving results

The third argument to startVitest allows passing CLI arguments to override test config options. The fourth argument allows passing the complete Vite config, which will take precedence over any other user-defined options. After running tests, you can get results from the state.getTestModules() API which returns TestModule instances.

createVitest function signature and import

The createVitest function can be imported from 'vitest/node' entry-point. Its signature is: function createVitest(options: CliOptions, viteOverrides: ViteUserConfig = {}, vitestOptions: VitestOptions = {}): Promise<Vitest>. It returns the same Vitest instance as startVitest, but it does not start tests and does not validate installed packages.

createVitest basic usage example

Example of creating a Vitest instance without starting tests: import { createVitest } from 'vitest/node' const vitest = await createVitest('test', { watch: false, })

resolveConfig function signature and import

The resolveConfig function can be imported from 'vitest/node' entry-point. Its signature is: function resolveConfig(options: UserConfig = {}, viteOverrides: ViteUserConfig = {}, harness?: PluginHarness): Promise<ResolvedViteConfig>. This method resolves the config with custom parameters, without creating a Vite server. If no parameters are given, the root will be process.cwd(). It returns the resolved Vite config with the fully resolved Vitest config on its test property.

resolveConfig usage example

Example of resolving Vitest configuration: import { resolveConfig } from 'vitest/node' const viteConfig = await resolveConfig({ mode: 'custom', configFile: false, resolve: { conditions: ['custom'] }, test: { setupFiles: ['/my-setup-file.js'], pool: 'threads', }, }) viteConfig.test.pool // 'threads'

Configuration resolution priority for root config

The root configuration is resolved from three inputs, in ascending priority: 1) the root config file, 2) viteOverrides merged on top of the config file values, 3) CLI options applied on top of everything else.

Project configuration resolution with inheritance

Every project resolves its own Vite config independently. A project referenced as a config file or directory resolves only its own file without inheriting from root configuration. An inline project inherits the root configuration by default through the extends option: the root config file is re-executed for the project, viteOverrides are merged on top of it, and the project's own options are merged last. With extends: false, an inline project resolves only its own options. With extends: './path', the referenced file is re-executed instead of the root config file, and viteOverrides are not merged.

Options excluded from inheritance in project configuration

The following options are excluded from inheritance: plugins from viteOverrides are never inherited because plugin instances from viteOverrides belong to the root Vite server and cannot be shared with project servers. test.browser and test.tagsFilter from viteOverrides are never inherited. name and projects are never inherited; the root globalSetup is not inherited because it already runs once per test run. The project's own tags always replace the tags array from an extended config instead of being concatenated with it.

Options that reach every project regardless of extends

Independently of extends, two groups of options reach every project: A fixed subset of CLI options that configure how tests run (--testTimeout, --retry, --pool, and similar) is applied to every project at the highest priority. Run-level options only make sense for the test run as a whole: every project receives the root's resolved coverage, attachmentsDir, and mergeReportsLabel values.

parseCLI function signature and import

The parseCLI function can be imported from 'vitest/node' entry-point. Its signature is: function parseCLI(argv: string | string[], config: CliParseOptions = {}): { filter: string[], options: CliOptions }. It accepts a string where arguments are split by a single space or a strings array of CLI arguments in the same format that Vitest CLI uses. It returns a filter and options that you can later pass down to createVitest or startVitest methods.

Example of disabling watcher in createVitest

await createVitest( 'test', {}, { plugins: [ { name: 'stop-watcher', async configureServer(server) { await server.watcher.close() } } ], server: { watch: null, }, } )

Manual test execution with runTestSpecifications and rerunTestSpecifications

After reporters are initialized, use runTestSpecifications or rerunTestSpecifications methods to run tests manually. Use runTestSpecifications when reporter.onWatcher* hooks should not be invoked, and rerunTestSpecifications to trigger those hooks.

getModuleSpecifications vs matchesGlobPattern for newly created files

getModuleSpecifications will not resolve test files unless they were already processed by globTestSpecifications. For newly created files, use project.matchesGlobPattern() to check if a file matches the project's glob pattern, then use project.createSpecification() to create a specification for that file.

Disabling the watcher in Vitest

To disable the watcher, pass either server.watch: null (available since Vite 5.3) or server.watch: { ignored: ['*/*'] } to the Vite config in createVitest call.

Example of startVitest usage with test module inspection

import { startVitest } from 'vitest/node' const vitest = await startVitest( 'test', [], // CLI filters {}, // override test config {}, // override Vite config {}, // custom Vitest options ) const testModules = vitest.state.getTestModules() for (const testModule of testModules) { console.log(testModule.moduleId, testModule.ok() ? 'passed' : 'failed') }

Example of createVitest usage with custom test execution

import { createVitest } from 'vitest/node' const vitest = await createVitest( 'test', {}, // override test config {}, // override Vite config {}, // custom Vitest options ) vitest.onCancel(() => {}) vitest.onClose(() => {}) vitest.onTestsRerun((files) => {}) try { await vitest.start(['my-filter']) } catch (err) { // FilesNotFoundError or GitNotFoundError possible } finally { await vitest.close() }

Example of watching files and rerunning specifications

watcher.on('change', async (file) => { const specifications = vitest.getModuleSpecifications(file) if (specifications.length) { vitest.invalidateFile(file) await vitest.rerunTestSpecifications(specifications) } })

Example of handling new files in watcher with matchesGlobPattern

watcher.on('add', async (file) => { const specifications = [] for (const project of vitest.projects) { if (project.matchesGlobPattern(file)) { specifications.push(project.createSpecification(file)) } } if (specifications.length) { await vitest.rerunTestSpecifications(specifications) } })

startVitest method for running tests via Node.js script

startVitest is imported from 'vitest/node' and initiates Vitest, validates that required packages are installed, and runs tests immediately. It takes four parameters: a mode string (e.g. 'test'), CLI filters array, test config override object, Vite config override object, and custom Vitest options object. It returns a vitest instance with state property containing getTestModules() method to retrieve and inspect test results.

createVitest method for initializing Vitest without running tests

createVitest is imported from 'vitest/node' and creates a Vitest instance without running tests. It takes three parameters: a mode string (e.g. 'test'), test config override object, and Vite config override object. Unlike startVitest, createVitest does not validate that required packages are installed, does not respect config.standalone or config.mergeReports, and does not close Vitest automatically even if watch is disabled.

createVitest callback methods

The Vitest instance returned by createVitest supports three callback methods: onCancel() called when vitest.cancelCurrentRun() is invoked, onClose() called during vitest.close() call, and onTestsRerun(files) called when Vitest reruns test files.

createVitest start method behavior

Calling await vitest.start() with CLI filters will run tests and set process.exitCode to 1 if tests failed, but will not close the process automatically. It can throw errors including 'FilesNotFoundError' if no test files were found or 'GitNotFoundError' when using --changed flag and the repository is not initialized.

Keeping Vitest instance alive with init

To keep a Vitest instance running continuously, call the init method which initializes reporters and the coverage provider but does not run any tests. It is recommended to enable watch mode even if not using the Vitest watcher, so that Vitest's features work correctly in a continuous process.

Debug tests in VS Code using JavaScript Debug Terminal

Open a JavaScript Debug Terminal in VS Code and run npm run test or vitest directly to debug tests. This method works with any code run in Node and supports most JavaScript testing frameworks.

VS Code launch configuration for debugging a single test file

Add a launch configuration to .vscode/launch.json with type 'node', program set to '${workspaceRoot}/node_modules/vitest/vitest.mjs', and args set to ['run', '${relativeFile}']. Enable autoAttachChildProcesses, set smartStep to true, and use integratedTerminal as console. Then open a test file, select 'Debug Current Test File' in the debug tab, and press F5 to start debugging.

Debug tests with Node Inspector using Chrome DevTools

Run vitest with --inspect-brk and --no-file-parallelism flags to debug without an IDE. Vitest will stop execution and wait for a debugger to connect. Open chrome://inspect in a browser to connect Chrome DevTools to the Node.js inspector.

Debug tests in IntelliJ IDEA

Create a Vitest run configuration in IntelliJ IDEA with the working directory set to /path/to/your-project-root. Run the configuration in debug mode and the IDE will stop at JavaScript/TypeScript breakpoints set in the editor.

VS Code compound launch configuration for browser debugging

Create a compound configuration in launch.json that combines a Node launch configuration running Vitest with --inspect-brk, --browser, and --no-file-parallelism, with a Chrome attach configuration targeting port 9229. Set stopAll to true in the compound configuration.

projects configuration with named test suites

The 'projects' array in Vitest configuration can define multiple test projects with individual configurations. Each project object can include a 'test' property with its own settings, such as a 'name' field to identify the project. Example: projects: [{ test: { name: "Unit" } }, { test: { name: "Integration" } }]

workspace config renamed to projects

The 'workspace' configuration option in Vitest has been renamed to 'projects'. Code that previously used 'test.workspace' should now use 'test.projects' instead.

OpenTelemetry API peer dependency

Vitest declares @opentelemetry/api as an optional peer dependency and uses it internally to generate spans when trace collection is enabled. When installing @opentelemetry/sdk-node, it includes @opentelemetry/api as a transitive dependency, satisfying Vitest's requirement. If an error indicates @opentelemetry/api cannot be found, it typically means trace collection has not been enabled or may need explicit installation.

OpenTelemetry support in Vitest

Vitest has experimental OpenTelemetry support for debugging application performance and behavior inside tests. When enabled, Vitest generates spans scoped to each test's worker. OpenTelemetry initialization increases startup time unless Vitest runs without isolation. To enable it, specify an SDK module path via experimental.openTelemetry.sdkPath and set experimental.openTelemetry.enabled to true.

OpenTelemetry SDK export requirement

The OpenTelemetry SDK must be exported as a default export so Vitest can flush network requests before the process closes. Vitest does not automatically call start() on the SDK.

OpenTelemetry quickstart packages

To start using OpenTelemetry in Vitest, install: @opentelemetry/sdk-node, @opentelemetry/auto-instrumentations-node, and @opentelemetry/exporter-trace-otlp-proto.

OpenTelemetry quickstart example configuration

Example SDK file (otel.js): import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; import { NodeSDK } from '@opentelemetry/sdk-node'; const sdk = new NodeSDK({ serviceName: 'vitest', traceExporter: new OTLPTraceExporter(), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); export default sdk. Example vitest.config.js: import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { experimental: { openTelemetry: { enabled: true, sdkPath: './otel.js', }, }, }, });

OpenTelemetry fake timers pitfall

When using fake timers with OpenTelemetry, it is important to reset them before the test ends, otherwise traces might not be tracked properly.

OpenTelemetry sdkPath file extension requirement

The sdkPath module should use the .js extension. Using another extension will slow down tests and may require providing additional Node.js arguments. TypeScript files can be used but require familiarity with Node.js TypeScript type-stripping.

Custom traces in OpenTelemetry

You can use the OpenTelemetry API to track operations in your code. Custom traces automatically inherit the Vitest OpenTelemetry context and are shown inside the vitest.test.runner.test.callback span. Example: import { trace } from '@opentelemetry/api'; import { test } from 'vitest'; import { db } from './src/db'; const tracer = trace.getTracer('vitest'); test('db connects properly', async () => { await tracer.startActiveSpan('db.connect', () => db.connect()); });

Viewing OpenTelemetry traces

To generate traces, run Vitest as usual in either watch mode or run mode. Vitest will call sdk.shutdown() manually after everything is finished to ensure traces are handled properly. Traces can be viewed using any open source or commercial products that support the OpenTelemetry API, such as Jaeger.

OpenTelemetry inter-process context propagation

Vitest supports automatic context propagation from parent processes via the TRACEPARENT and TRACESTATE environment variables as defined in the OpenTelemetry specification. This is useful when running Vitest as part of a larger distributed tracing system, such as CI/CD pipelines with OpenTelemetry instrumentation.

Profile test runner with Node.js CPU and heap profiling

To profile the test runner, use the execArgv configuration option to pass Node.js profiling flags. The supported options are --cpu-prof (CPU profiling), --heap-prof (heap profiling), and --prof (general profiling). The --prof option does not work with pool: 'threads' due to node:worker_threads limitations.

Test runner profiling configuration example

Example showing how to configure execArgv for profiling in vitest.config.ts: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ test: { fileParallelism: false, execArgv: [ '--cpu-prof', '--cpu-prof-dir=test-runner-profile', '--heap-prof', '--heap-prof-dir=test-runner-profile' ], }, }) ``` After running tests, look for *.cpuprofile and *.heapprofile files in the specified directory.

Profile Vitest main thread with Node.js arguments

To profile the main thread (where Vite plugins and globalSetup run), pass Node.js profiling arguments directly to the Node process before the vitest command: ```bash node --cpu-prof --cpu-prof-dir=main-profile ./node_modules/vitest/vitest.mjs --run ``` The Node.js arguments come before vitest.mjs, and Vitest arguments like --run come after.

Redirect imports with resolve.alias to lighter alternatives

If a dependency doesn't provide granular entry points or third-party code imports heavy entry points, use resolve.alias in Vite configuration to redirect imports: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ resolve: { alias: [ { find: /^date-fns$/, replacement: join(dirname(require.resolve('date-fns/package.json')), 'index.cjs'), }, ] }, }) ```

Bundle external libraries with deps.optimizer

Use deps.optimizer configuration to bundle external libraries into a single file, reducing import overhead for packages with many internal modules: ```ts import { defineConfig } from 'vitest/config' export default defineConfig({ test: { deps: { optimizer: { ssr: { enabled: true, include: ['date-fns'], }, }, }, }, }) ``` Use optimizer.ssr for node/edge environments and optimizer.client for jsdom/happy-dom environments.

Tools for inspecting profiling records

Inspect *.cpuprofile and *.heapprofile files generated during profiling with these tools: Speedscope (speedscope.app), Visual Studio Code Performance Profiling, Chrome DevTools Performance panel for Node.js profiling, or Chrome DevTools Memory panel for heap snapshots.

TestRunner.matchesTags at runtime

You can use TestRunner.matchesTags to check whether the current tags filter matches a set of tags. This is useful for conditionally running expensive setup logic only when relevant tests are included: ```ts import { beforeAll, TestRunner } from 'vitest' beforeAll(async () => { // Seed database when "vitest --tags-filter db" is used if (TestRunner.matchesTags(['db'])) { await seedDatabase() } }) ``` The method accepts an array of tags and returns true if the current --tags-filter would include a test with those tags. If no tags filter is active, it always returns true.

Programmatic tags filter with startVitest

When using the programmatic API, you can pass a tagsFilter option to startVitest or createVitest: ```ts import { startVitest } from 'vitest/node' await startVitest([], { tagsFilter: ['frontend and backend'], }) ```

Test specification with custom tags filter

You can create a test specification with custom tags filters: ```ts const specification = vitest.getRootProject().createSpecification( '/path-to-file.js', { testTagsFilter: ['frontend and backend'], }, ) ```

TestSuite class type property

The TestSuite class instance always has a type property with the value of 'suite'. This can be used to distinguish between different task types by checking if task.type === 'suite'.

Give your agent this brain