How to Configure and Execute Vitest Tests Using Vite+'s Bundled Testing Framework

Vite+ bundles Vitest directly into its CLI distribution, enabling developers to configure and run tests via the unified vp test command without installing a separate vitest package.

The voidzero-dev/vite-plus project integrates Vitest—the official Vite testing framework—into a single binary that handles development, building, and testing. This consolidation eliminates version skew between Vite and Vitest while providing a consistent configuration experience through the standard vite.config.ts file.

Configuring the Test Environment in Vite+

Vite+ re-exports Vitest’s configuration types, allowing you to declare test settings within the same configuration object used for your build and development server.

Declaring Test Configuration in vite.config.ts

Add a test field to the object exported by defineConfig to configure Vitest options. This field accepts all standard Vitest configuration parameters, including test patterns, coverage settings, and environment options.

// vite.config.ts
import { defineConfig } from 'vite-plus';

export default defineConfig({
  plugins: [],
  test: {
    include: ['src/**/*.spec.ts', 'src/**/*.test.ts'],
    environment: 'jsdom',
    coverage: {
      reporter: ['text', 'html'],
    },
  },
});

Source: README example lines 56-60

TypeScript Type Merging for Test Options

The UserConfig interface in packages/cli/src/index.ts uses declaration merging to include the test field, providing full TypeScript autocomplete and type checking for Vitest options within your Vite+ configuration.

// packages/cli/src/index.ts – declaration merging
declare module '@voidzero-dev/vite-plus-core' {
  interface UserConfig {
    test?: VitestConfig;   // imported from Vitest
  }
}

Source: index.ts lines 10-30

Executing Tests with the VP CLI

The vp test command invokes the bundled Vitest binary through a Rust-based execution layer, handling environment setup and process spawning automatically.

Resolving the Bundled Vitest Binary

When you run vp test, the CLI handler calls resolve-test.ts, which constructs the absolute path to the Vitest entry point located at dist/cli.js inside the @voidzero-dev/vite-plus-test package. The function returns both the binary path and a set of required environment variables to the Rust core.

// packages/cli/src/resolve-test.ts
export async function test(): Promise<{ binPath: string; envs: Record<string,string> }> {
  const binPath = join(dirname(resolve('@voidzero-dev/vite-plus-test')), 'dist', 'cli.js');
  // ...
}

Source: resolve-test.ts line 30-34

Passing CLI Flags and Arguments

Pass any standard Vitest CLI flags after a double-dash (--) to the vp test command. The Rust core forwards these arguments directly to the spawned Vitest process.


# Run all tests once

vp test

# Enable watch mode

vp test -- --watch

# Generate coverage reports

vp test -- --coverage

# Run a specific test file

vp test -- tests/unit/example.test.ts

Environment Variables and Test Execution

Vite+ automatically injects specific environment variables when spawning Vitest. These defaults are defined in packages/cli/src/utils/constants.ts and include VITE_TEST_MODE=1 to signal test execution context.

// packages/cli/src/utils/constants.ts
export const DEFAULT_ENVS = {
  VITE_TEST_MODE: '1',
  // ...other defaults
};

Source: constants.ts line 1-5

You can override behavior using additional environment variables. For example, setting DEBUG_DISABLE_SOURCE_MAP disables source map generation for faster debugging sessions.

DEBUG_DISABLE_SOURCE_MAP=1 vp test -- --verbose

The Execution Flow Under the Hood

The test execution follows a specific orchestration between the Rust core and JavaScript resolver:

  1. CLI Entry – vp test invokes the Rust core (vite_task) with the test sub-command.
  2. Resolution – The Rust core calls resolve-test.ts to retrieve the binPath and environment variables.
  3. Process Spawn – The core spawns a Node.js process pointing at the bundled Vitest CLI (cli.js).
  4. Config Loading – Vitest reads the test section from your Vite+ config file, treating it identically to a standalone vitest.config.ts.
  5. Output – Test results report through Vite+'s unified output utilities (vite_shared::output).

This architecture provides a single binary (vp) that manages dev servers, linting, formatting, building, and testing.

Summary

  • Unified Configuration: Define Vitest settings within vite.config.ts using the test field, with full TypeScript support via declaration merging in packages/cli/src/index.ts.
  • Bundled Binary: Vite+ includes Vitest internally; vp test resolves the binary path via packages/cli/src/resolve-test.ts without requiring a separate installation.
  • CLI Flexibility: Pass Vitest-specific flags after -- to vp test for watch mode, coverage, or file-specific execution.
  • Environment Injection: The CLI automatically sets VITE_TEST_MODE=1 and other defaults from packages/cli/src/utils/constants.ts when spawning test processes.

Frequently Asked Questions

Do I need to install Vitest separately when using Vite+?

No. Vite+ bundles Vitest inside the @voidzero-dev/vite-plus-test package and resolves it automatically through the vp test command. The binary path is located at dist/cli.js within the bundled package, eliminating the need for a separate vitest dependency in your package.json.

Can I use a separate vitest.config.ts file instead of the test field in vite.config.ts?

While Vite+ reads Vitest configuration from the test field in your unified config, Vitest itself will still recognize a dedicated vitest.config.ts if present. However, using the unified vite.config.ts approach is recommended to maintain a single source of configuration truth and leverage the type definitions in packages/cli/src/index.ts.

How do I enable watch mode or coverage reporting?

Pass the appropriate flags after a double-dash: vp test -- --watch enables file watching, while vp test -- --coverage generates coverage reports. These arguments are forwarded directly to the bundled Vitest process by the Rust core, behaving identically to running standalone Vitest.

What happens if the bundled Vitest version differs from my project's expectations?

Vite+ pins a specific Vitest version within its bundle to ensure compatibility with the vp CLI's Rust core and resolver logic. This eliminates version skew issues common when managing separate Vite and Vitest installations, guaranteeing that the resolve-test.ts resolver and DEFAULT_ENVS constants remain synchronized with the test runner.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →