vitest について
プロジェクトに合わせて Vitest の設定、スクリプト、実行可能なサンプルテストを用意するスキルです。Jest からの移行にも対応します。
主な機能
- 01プロジェクト種別と既存設定の検出
- 02環境に合わせた Vitest 設定の生成
- 03セットアップファイルとテスト例の作成
- 04TypeScript 設定とスクリプトの追加
- 05Jest 移行のガイド
活用シーン
- 01React や Node プロジェクトへのテスト導入
- 02Cloudflare Workers のテスト設定
- 03monorepo の複数パッケージでの Vitest 設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill vitestインストール後、Claude Code で/vitestを入力して読み込まれたか確認します。
詳細
Vitest のセットアップ
プロジェクトの種類を検出し、適切な Vitest 設定を生成して、動作するテスト基盤を構築します。これはリファレンスカードではなく、ファイルを作成するスキルです。
ワークフロー
- 検出 — プロジェクトをスキャンして、種類と既存のセットアップを確認します
- 設定 — 環境に合わせて vitest.config.ts を生成します
- 足場の作成 — テストのセットアップ、ユーティリティ、サンプルテストを作成します
- 接続 — package.json のスクリプトと TypeScript 設定を追加します
Step 1: プロジェクトの種類を検出する
プロジェクトの種類を判定するため、次のファイルを読み取ります。
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
次のいずれかに分類します。
| 種類 | 判定の手がかり | 環境 |
|---|---|---|
| Cloudflare Workers | wrangler.toml、@cloudflare/workers-types、cloudflare vite plugin | Workers 固有のセットアップを使用する node |
| React (Vite) | @vitejs/plugin-react、react-dom | jsdom または happy-dom |
| React (SSR/TanStack Start) | @tanstack/start、vinxi | 分割構成:サーバーには node、クライアントには jsdom |
| Node/Hono API | hono、express、react-dom なし | node |
| ライブラリ | exports フィールド、フレームワーク依存関係なし | node |
既に vite.config.ts がある場合は、別の vitest.config.ts を作成せず、既存の設定を拡張します。Vitest は Vite 設定をネイティブに読み込みます。
Step 2: 依存関係をインストールする
検出した種類に基づいてインストールコマンドを生成します。
# 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
プロジェクトのパッケージマネージャーを使用します(pnpm-lock.yaml、yarn.lock、bun.lockb、または package-lock.json を確認してください)。
Step 3: 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" },
},
},
},
});
プロジェクトが Cloudflare Vite プラグイン(@cloudflare/vite-plugin)を使用している場合は、代わりに既存の vite.config.ts に統合します。
/// <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,
},
});
既に vite.config.ts がある場合は、新しいファイルを作成せず、test ブロックを追加します。
Node / Hono API
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
},
});
カバレッジを有効にする場合(任意の設定に追加)
test: {
// ... existing config
coverage: {
provider: "v8",
reporter: ["text", "html", "lcov"],
exclude: [
"node_modules/",
"**/*.config.*",
"**/*.d.ts",
"**/test/**",
],
},
},
Step 4: テストセットアップファイルを生成する
src/test/setup.ts を作成します(React プロジェクトのみ)。
import "@testing-library/jest-dom/vitest";
この単一のインポートで、すべてのカスタムマッチャー(toBeInTheDocument、toHaveTextContent など)が追加され、Vitest の expect.extend が自動的に登録されます。
Step 5: TypeScript 設定を追加する
tsconfig.json の compilerOptions に追加します。
{
"compilerOptions": {
"types": ["vitest/globals"]
}
}
複数の tsconfig ファイルがあるプロジェクト(例:tsconfig.app.json + tsconfig.node.json)では、テストファイルを対象とする設定に追加します。通常はルートの tsconfig.json ですが、そこから拡張する tsconfig.test.json を作成してもかまいません。
Step 6: package.json のスクリプトを追加する
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui"
}
}
既存のスクリプトを上書きせず、既存の内容にマージします。
Step 7: サンプルテストを生成する
このプロジェクトに合ったパターンを示すテストファイルを1つ作成します。テストファイルは、独立した __tests__ ディレクトリではなく、実際のソースコードの隣に配置します。
Hono API ルートの場合(例: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" });
});
});
React コンポーネントの場合(例: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();
});
});
ユーティリティ関数の場合(例: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");
});
});
テストする実際のファイルをプロジェクトから選びます。架空のモジュールは作成しないでください。セットアップ後すぐに実行できるサンプルテストにします。
Step 8: 検証する
すべてが動作することを確認するため、テストを実行します。
pnpm test:run
失敗した場合は、原因を特定して修正します。よくある問題は次のとおりです。
| エラー | 修正方法 |
|---|---|
Cannot find module 'vitest' | インストールが完了していることと、node_modules/.vitest が存在することを確認します |
ReferenceError: describe is not defined | 設定に globals: true を追加するか、tsconfig に types: ["vitest/globals"] を追加します |
document is not defined | 環境が適切ではありません。React テストでは environment: "jsdom" を設定します |
Cannot use import.meta | vitest.config の拡張子が .ts であること、プロジェクトに "type": "module" が設定されていること、または Vite が変換を処理していることを確認します |
| Workers のバインディングが未定義 | 通常の vitest ではなく @cloudflare/vitest-pool-workers を使用し、wrangler.toml のパスを確認します |
モックのリファレンス
以下のパターンは、セットアップ完了後にテストを書くためのものです。モックの例を求められた場合は、サンプルテストまたは src/test/examples.test.ts に含めます。
モジュールのモック(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);
});
メソッドを監視する(vi.spyOn)
it("spies on console.warn", () => {
const spy = vi.spyOn(console, "warn").mockImplementation(() => {});
doSomethingThatWarns();
expect(spy).toHaveBeenCalledOnce();
spy.mockRestore();
});
フェイクタイマー
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");
});
グローバルスタブ
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();
});
スナップショットテスト
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",
}
`);
});
パラメーター化テスト
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 からの移行
検出されたプロジェクトに Jest がある場合(依存関係に jest.config.*、@types/jest、ts-jest がある場合):
- 上記の手順に従って vitest.config.ts を生成する
- 既存のテストファイルのインポートを更新する:
// 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");
- Jest パッケージを削除する:
pnpm remove jest ts-jest @types/jest jest-environment-jsdom babel-jest @jest/globals
-
tsconfig を更新する —
"types": ["jest"]を"types": ["vitest/globals"]に置き換えます -
テストを実行し、残っている問題を修正します
主な置き換え:
| 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 |
ワークスペースの設定(モノレポ)
複数のパッケージを含むモノレポプロジェクトの場合:
// vitest.workspace.ts
import { defineWorkspace } from "vitest/config";
export default defineWorkspace([
"packages/*/vitest.config.ts",
]);
各パッケージにそれぞれの設定ファイルを用意します。ワークスペースファイルは、それらを参照するだけです。
このスキルで作成されるもの
実行後、プロジェクトには次のものが用意されます:
vitest.config.ts(または既存の vite.config.ts に追加された test ブロック)src/test/setup.ts(React プロジェクトの場合)- vitest/globals 型を指定した更新済みの
tsconfig.json - test スクリプトを含む更新済みの
package.json - 実際のソースコードを対象とする、少なくとも 1 つの成功するサンプルテスト
- インストール済みの依存関係
テストは最初の実行で成功するはずです。成功しない場合は、完了前に修正してください。