Vitest

jezweb/claude-skills/plugins/dev-tools/skills/vitest

作者 jezweb64965d9d9fc7MIT1K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 天前更新

Set up Vitest testing in any project — detects type (Cloudflare Workers, React, Node, library), generates vitest.config.ts, test setup, utilities, and a sample test. Covers mocking patterns, coverage config, workspace setup, Jest migration. Use whenever the user mentions adding tests, setting up Vitest, configuring tests, migrating from Jest, fixing testing infrastructure, or asks 'how do I test this'.

AI 產生的概覽

透過辨識專案類型來設定 Vitest 測試,產生設定、安裝檔案、指令碼與一個範例測試。

功能
讀取設定與原始碼檔案以判斷專案類型(Cloudflare Workers、React、Node/Hono 或函式庫),接著產生對應的 vitest.config.ts,或擴充既有的 Vite 設定。它會建立測試安裝檔案、TypeScript 型別、package.json 測試指令碼,並針對真實原始碼產生至少一個範例測試,同時安裝所需相依套件。文件也涵蓋模擬模式、覆蓋率設定、monorepo 工作區設定以及從 Jest 移轉的步驟。
適用情境
適用於為專案加入測試、設定或配置 Vitest、從 Jest 移轉專案,或修復現有測試基礎架構的情況。也適合回答「如何測試這個專案」這類問題。
執行需求
僅包含說明,不附帶指令碼。需要一個使用套件管理器(pnpm、npm、yarn 或 bun)的 Node.js 專案,並需要網路存取以安裝開發相依套件,例如 vitest、@vitest/coverage-v8、jsdom、Testing Library 相關套件,或依專案類型所需的 @cloudflare/vitest-pool-workers。

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

  1. Detect — scan the project to determine type and existing setup
  2. Configure — generate vitest.config.ts tailored to the environment
  3. Scaffold — create test setup, utilities, and a sample test
  4. 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 fieldtsconfig.json         → paths, compiler optionswrangler.toml         → Cloudflare Workers projectvite.config.ts        → existing Vite setup (extend, don't replace)vitest.config.ts      → already configured? just fill gapsjest.config.*         → migration candidatesrc/                  → source structure

Classify as one of:

TypeSignalsEnvironment
Cloudflare Workerswrangler.toml, @cloudflare/workers-types, cloudflare vite pluginnode with Workers-specific setup
React (Vite)@vitejs/plugin-react, react-domjsdom or happy-dom
React (SSR/TanStack Start)@tanstack/start, vinxiSplit: node for server, jsdom for client
Node/Hono APIhono, express, no react-domnode
Libraryexports field, no framework depsnode

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:

bash
# Base (always)pnpm add -D vitest
# React projects — add jsdom and Testing Librarypnpm add -D @vitest/coverage-v8 jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
# Workers projects — add Cloudflare test utilitiespnpm add -D @vitest/coverage-v8 @cloudflare/vitest-pool-workers
# Node/Hono projectspnpm 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

typescript
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:

typescript
/// <reference types="vitest/config" />import { defineConfig } from "vite";import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({  plugins: [cloudflare()],  test: {    globals: true,  },});

React (Vite)

typescript
/// <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

typescript
import { defineConfig } from "vitest/config";
export default defineConfig({  test: {    globals: true,    environment: "node",  },});

With Coverage (add to any config)

typescript
  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):

typescript
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:

json
{  "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

json
{  "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):

typescript
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):

typescript
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):

typescript
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:

bash
pnpm test:run

If it fails, diagnose and fix. Common issues:

ErrorFix
Cannot find module 'vitest'Check install completed, check node_modules/.vitest exists
ReferenceError: describe is not definedAdd globals: true to config, or add types: ["vitest/globals"] to tsconfig
document is not definedWrong environment — set environment: "jsdom" for React tests
Cannot use import.metaEnsure vitest.config uses .ts extension and project has "type": "module" or Vite handles transforms
Workers bindings undefinedUse @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)

typescript
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)

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

Fake timers

typescript
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

typescript
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

typescript
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

typescript
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):

  1. Generate the vitest.config.ts using the steps above
  2. Update imports in existing test files:
typescript
// Beforeimport { jest } from "@jest/globals";jest.mock("./api");jest.fn();jest.spyOn(obj, "method");
// Afterimport { vi } from "vitest";vi.mock("./api");vi.fn();vi.spyOn(obj, "method");
  1. Remove Jest packages:
bash
pnpm remove jest ts-jest @types/jest jest-environment-jsdom babel-jest @jest/globals
  1. Update tsconfig — replace "types": ["jest"] with "types": ["vitest/globals"]

  2. Run tests and fix any remaining issues

Key replacements:

JestVitest
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/globalsvitest
jest.config.jsvitest.config.ts

Workspace Setup (Monorepos)

For monorepo projects with multiple packages:

typescript
// vitest.workspace.tsimport { 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.

來源與署名

來源:jezweb/claude-skills位於plugins/dev-tools/skills/vitest提交64965d9

授權條款: MIT

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架