vitest

Detect the project type, generate the right Vitest configuration, and produce working test infrastructure. Not a reference card — this skill creates files.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "vitest" with this command: npx skills add jezweb/claude-skills/jezweb-claude-skills-vitest

Vitest Setup

Detect the project type, generate the right Vitest configuration, and produce working test infrastructure. Not a reference card — this skill creates files.

Workflow

  • Detect — scan the project to determine type and existing setup

  • Configure — generate vitest.config.ts tailored to the environment

  • Scaffold — create test setup, utilities, and a sample test

  • Wire up — add package.json scripts and TypeScript config

Step 1: Detect Project Type

Read these files to determine the project:

package.json → dependencies, scripts, type field tsconfig.json → paths, compiler options wrangler.toml → Cloudflare Workers project vite.config.ts → existing Vite setup (extend, don't replace) vitest.config.ts → already configured? just fill gaps jest.config.* → migration candidate src/ → source structure

Classify as one of:

Type Signals Environment

Cloudflare Workers wrangler.toml, @cloudflare/workers-types, cloudflare vite plugin node with Workers-specific setup

React (Vite) @vitejs/plugin-react, react-dom jsdom or happy-dom

React (SSR/TanStack Start) @tanstack/start, vinxi Split: node for server, jsdom for client

Node/Hono API hono, express, no react-dom node

Library exports field, no framework deps node

If a vite.config.ts already exists, extend it rather than creating a separate vitest.config.ts — Vitest reads Vite config natively.

Step 2: Install Dependencies

Generate the install command based on detected type:

Base (always)

pnpm add -D vitest

React projects — add jsdom and Testing Library

pnpm add -D @vitest/coverage-v8 jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event

Workers projects — add Cloudflare test utilities

pnpm add -D @vitest/coverage-v8 @cloudflare/vitest-pool-workers

Node/Hono projects

pnpm add -D @vitest/coverage-v8

If migrating from Jest, also remove:

pnpm remove jest ts-jest @types/jest jest-environment-jsdom babel-jest

Use the project's package manager (check for pnpm-lock.yaml, yarn.lock, bun.lockb, or package-lock.json).

Step 3: Generate vitest.config.ts

Cloudflare Workers

import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";

export default defineWorkersConfig({ test: { globals: true, poolOptions: { workers: { wrangler: { configPath: "./wrangler.toml" }, }, }, }, });

If the project uses the Cloudflare Vite plugin (@cloudflare/vite-plugin ), integrate into the existing vite.config.ts instead:

/// <reference types="vitest/config" /> import { defineConfig } from "vite"; import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({ plugins: [cloudflare()], test: { globals: true, }, });

React (Vite)

/// <reference types="vitest/config" /> import { defineConfig } from "vite"; import react from "@vitejs/plugin-react";

export default defineConfig({ plugins: [react()], test: { globals: true, environment: "jsdom", setupFiles: ["./src/test/setup.ts"], css: true, }, });

If a vite.config.ts already exists, add the test block to it rather than creating a new file.

Node / Hono API

import { defineConfig } from "vitest/config";

export default defineConfig({ test: { globals: true, environment: "node", }, });

With Coverage (add to any config)

test: { // ... existing config coverage: { provider: "v8", reporter: ["text", "html", "lcov"], exclude: [ "node_modules/", "/.config.", "/*.d.ts", "/test/", ], }, },

Step 4: Generate Test Setup File

Create src/test/setup.ts (React projects only):

import "@testing-library/jest-dom/vitest";

That single import adds all the custom matchers (toBeInTheDocument, toHaveTextContent, etc.) and registers the Vitest expect.extend automatically.

Step 5: Add TypeScript Config

Add to tsconfig.json compilerOptions:

{ "compilerOptions": { "types": ["vitest/globals"] } }

For projects with multiple tsconfig files (e.g. tsconfig.app.json + tsconfig.node.json), add to the one that covers test files — usually the root tsconfig.json or create a tsconfig.test.json that extends it.

Step 6: Add Package.json Scripts

{ "scripts": { "test": "vitest", "test:run": "vitest run", "test:coverage": "vitest run --coverage", "test:ui": "vitest --ui" } }

Don't overwrite existing scripts — merge with what's there.

Step 7: Generate Sample Test

Write one test file that demonstrates the right patterns for this specific project. Place it next to real source code, not in a separate tests directory.

For a Hono API route (e.g. src/routes/health.ts ):

import { describe, it, expect } from "vitest"; import { app } from "../index";

describe("GET /health", () => { it("returns 200 with status ok", async () => { const res = await app.request("/health"); expect(res.status).toBe(200);

const body = await res.json();
expect(body).toEqual({ status: "ok" });

}); });

For a React component (e.g. src/components/Button.tsx ):

import { describe, it, expect } from "vitest"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Button } from "./Button";

describe("Button", () => { it("renders with label", () => { render(<Button>Click me</Button>); expect(screen.getByRole("button", { name: /click me/i })).toBeInTheDocument(); });

it("calls onClick when clicked", async () => { const user = userEvent.setup(); const handleClick = vi.fn(); render(<Button onClick={handleClick}>Click me</Button>);

await user.click(screen.getByRole("button"));
expect(handleClick).toHaveBeenCalledOnce();

}); });

For a utility function (e.g. src/utils/format.ts ):

import { describe, it, expect } from "vitest"; import { formatCurrency } from "./format";

describe("formatCurrency", () => { it("formats whole numbers", () => { expect(formatCurrency(1000)).toBe("$1,000.00"); });

it("formats decimals", () => { expect(formatCurrency(49.9)).toBe("$49.90"); });

it("handles zero", () => { expect(formatCurrency(0)).toBe("$0.00"); }); });

Pick a real file from the project to test. Don't invent a fake module — the sample test should run immediately after setup.

Step 8: Verify

Run the tests to confirm everything works:

pnpm test:run

If it fails, diagnose and fix. Common issues:

Error Fix

Cannot find module 'vitest'

Check install completed, check node_modules/.vitest exists

ReferenceError: describe is not defined

Add globals: true to config, or add types: ["vitest/globals"] to tsconfig

document is not defined

Wrong environment — set environment: "jsdom" for React tests

Cannot use import.meta

Ensure vitest.config uses .ts extension and project has "type": "module" or Vite handles transforms

Workers bindings undefined Use @cloudflare/vitest-pool-workers instead of plain vitest, check wrangler.toml path

Mocking Reference

These patterns are for writing tests after setup is complete. Include them in the sample test or a src/test/examples.test.ts if the user asks for mocking examples.

Module mocking (vi.mock)

import { vi, describe, it, expect } from "vitest"; import { getUser } from "./api";

vi.mock("./api", () => ({ getUser: vi.fn(), }));

it("mocks a module function", async () => { vi.mocked(getUser).mockResolvedValue({ id: 1, name: "Test" }); const user = await getUser(1); expect(user.name).toBe("Test"); expect(getUser).toHaveBeenCalledWith(1); });

Spy on methods (vi.spyOn)

it("spies on console.warn", () => { const spy = vi.spyOn(console, "warn").mockImplementation(() => {}); doSomethingThatWarns(); expect(spy).toHaveBeenCalledOnce(); spy.mockRestore(); });

Fake timers

import { vi, beforeEach, afterEach, it, expect } from "vitest";

beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date("2026-01-15T10:00:00Z")); });

afterEach(() => { vi.useRealTimers(); });

it("uses controlled time", () => { expect(new Date().toISOString()).toBe("2026-01-15T10:00:00.000Z"); });

Global stubs

it("stubs fetch", async () => { const mockFetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ data: "test" }), }); vi.stubGlobal("fetch", mockFetch);

const res = await fetch("/api/data"); expect(mockFetch).toHaveBeenCalledWith("/api/data");

vi.unstubAllGlobals(); });

Snapshot testing

it("matches snapshot", () => { const result = generateConfig({ debug: true }); expect(result).toMatchSnapshot(); });

it("matches inline snapshot", () => { expect({ status: "ok", count: 3 }).toMatchInlineSnapshot( { "count": 3, "status": "ok", } ); });

Parameterized tests

describe.each([ { input: "hello", expected: "HELLO" }, { input: "world", expected: "WORLD" }, { input: "", expected: "" }, ])("toUpperCase($input)", ({ input, expected }) => { it(returns ${expected}, () => { expect(input.toUpperCase()).toBe(expected); }); });

Jest Migration

When the detected project has Jest (jest.config.* , @types/jest , ts-jest in dependencies):

  • Generate the vitest.config.ts using the steps above

  • Update imports in existing test files:

// Before import { jest } from "@jest/globals"; jest.mock("./api"); jest.fn(); jest.spyOn(obj, "method");

// After import { vi } from "vitest"; vi.mock("./api"); vi.fn(); vi.spyOn(obj, "method");

  • Remove Jest packages:

pnpm remove jest ts-jest @types/jest jest-environment-jsdom babel-jest @jest/globals

Update tsconfig — replace "types": ["jest"] with "types": ["vitest/globals"]

Run tests and fix any remaining issues

Key replacements:

Jest Vitest

jest.fn()

vi.fn()

jest.mock()

vi.mock()

jest.spyOn()

vi.spyOn()

jest.useFakeTimers()

vi.useFakeTimers()

jest.clearAllMocks()

vi.clearAllMocks()

jest.requireActual()

vi.importActual()

@jest/globals

vitest

jest.config.js

vitest.config.ts

Workspace Setup (Monorepos)

For monorepo projects with multiple packages:

// vitest.workspace.ts import { defineWorkspace } from "vitest/config";

export default defineWorkspace([ "packages/*/vitest.config.ts", ]);

Each package gets its own config. The workspace file just points to them.

What This Skill Produces

After running, the project should have:

  • vitest.config.ts (or test block added to existing vite.config.ts)

  • src/test/setup.ts (React projects)

  • Updated tsconfig.json with vitest/globals type

  • Updated package.json with test scripts

  • At least one passing sample test against real source code

  • Dependencies installed

The tests should pass on first run. If they don't, fix them before finishing.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwind-v4-shadcn

No summary provided by upstream source.

Repository SourceNeeds Review
2.7K-jezweb
General

tanstack-query

No summary provided by upstream source.

Repository SourceNeeds Review
2.5K-jezweb
General

shadcn-ui

No summary provided by upstream source.

Repository SourceNeeds Review
2.4K-jezweb
General

tailwind-theme-builder

No summary provided by upstream source.

Repository SourceNeeds Review
2.1K-jezweb