jpskill.com
🛠️ 開発・MCP コミュニティ

jest-vitest

JavaScriptやTypeScriptのテストコード作成、Reactコンポーネントのテスト、モック設定など、幅広いテスト関連作業を支援するSkill。

📜 元の英語説明(参考)

JavaScript/TypeScript testing with Jest and Vitest. Use when user asks to "write JS tests", "add unit tests", "test React component", "mock a module", "snapshot testing", "test async code", "set up Jest", "migrate to Vitest", or any JS/TS testing tasks.

🇯🇵 日本人クリエイター向け解説

一言でいうと

JavaScriptやTypeScriptのテストコード作成、Reactコンポーネントのテスト、モック設定など、幅広いテスト関連作業を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o jest-vitest.zip https://jpskill.com/download/6096.zip && unzip -o jest-vitest.zip && rm jest-vitest.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/6096.zip -OutFile "$d\jest-vitest.zip"; Expand-Archive "$d\jest-vitest.zip" -DestinationPath $d -Force; ri "$d\jest-vitest.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して jest-vitest.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → jest-vitest フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-17
取得日時
2026-05-17
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Jest & Vitest

JestとVitestを使ったJavaScript/TypeScriptのテストです。

テストの実行

# Jest
npx jest
npx jest --watch
npx jest --coverage
npx jest path/to/test.ts
npx jest -t "test name pattern"

# Vitest
npx vitest
npx vitest run          # Single run (no watch)
npx vitest --coverage
npx vitest path/to/test.ts

テストの構造

// JestとVitestは同じAPIを共有しています
describe("Calculator", () => {
  let calc: Calculator;

  beforeEach(() => {
    calc = new Calculator();
  });

  afterEach(() => {
    calc.reset();
  });

  it("should add two numbers", () => {
    expect(calc.add(2, 3)).toBe(5);
  });

  it("should throw on division by zero", () => {
    expect(() => calc.divide(1, 0)).toThrow("Division by zero");
  });

  describe("negative numbers", () => {
    it("should handle negative addition", () => {
      expect(calc.add(-1, -2)).toBe(-3);
    });
  });
});

一般的なマッチャー

// 同等性
expect(value).toBe(exact);           // === 厳密
expect(value).toEqual(deepEqual);    // ディープ同等性
expect(value).toStrictEqual(strict); // ディープ + 型

// 真偽値
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

// 数値
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(10);
expect(value).toBeCloseTo(0.3, 5);

// 文字列
expect(str).toMatch(/regex/);
expect(str).toContain("substring");

// 配列/オブジェクト
expect(arr).toContain(item);
expect(arr).toHaveLength(3);
expect(obj).toHaveProperty("key", "value");
expect(obj).toMatchObject({ name: "Alice" });

// 例外
expect(() => fn()).toThrow();
expect(() => fn()).toThrow("message");
expect(() => fn()).toThrow(ErrorClass);

モック

// モック関数
const mockFn = jest.fn();              // Jest
const mockFn = vi.fn();                // Vitest

mockFn.mockReturnValue(42);
mockFn.mockReturnValueOnce(1);
mockFn.mockResolvedValue({ data: [] });
mockFn.mockImplementation((x) => x * 2);

// アサーション
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");

// モックモジュール
jest.mock("./database");               // Jest
vi.mock("./database");                 // Vitest

// 実装付きモック
jest.mock("./api", () => ({
  fetchUser: jest.fn().mockResolvedValue({ name: "Alice" }),
}));

// Vitestでの同等な記述
vi.mock("./api", () => ({
  fetchUser: vi.fn().mockResolvedValue({ name: "Alice" }),
}));

// 既存のメソッドをスパイ
const spy = jest.spyOn(object, "method");   // Jest
const spy = vi.spyOn(object, "method");     // Vitest

// モックタイマー
jest.useFakeTimers();  // Jest
vi.useFakeTimers();    // Vitest

jest.advanceTimersByTime(1000);  // Jest
vi.advanceTimersByTime(1000);    // Vitest

非同期テスト

// Async/await
it("fetches users", async () => {
  const users = await fetchUsers();
  expect(users).toHaveLength(3);
});

// Resolved/rejected
it("resolves with data", async () => {
  await expect(fetchData()).resolves.toEqual({ ok: true });
});

it("rejects with error", async () => {
  await expect(fetchBad()).rejects.toThrow("Network error");
});

スナップショットテスト

// スナップショットの作成/更新
it("renders correctly", () => {
  const tree = render(<Button label="Click" />);
  expect(tree).toMatchSnapshot();
});

// インラインスナップショット
it("serializes", () => {
  expect(serialize(data)).toMatchInlineSnapshot(`"expected output"`);
});

// スナップショットの更新: jest --updateSnapshot / vitest --update

Reactテスト (Testing Library)

import { render, screen, fireEvent, waitFor } from "@testing-library/react";

it("renders and interacts", async () => {
  render(<LoginForm onSubmit={mockSubmit} />);

  // 要素のクエリ
  const input = screen.getByRole("textbox", { name: /email/i });
  const button = screen.getByRole("button", { name: /submit/i });

  // 操作
  fireEvent.change(input, { target: { value: "alice@test.com" } });
  fireEvent.click(button);

  // アサート
  await waitFor(() => {
    expect(mockSubmit).toHaveBeenCalledWith("alice@test.com");
  });

  expect(screen.getByText("Success")).toBeInTheDocument();
});

// userEvent (より現実的)
import userEvent from "@testing-library/user-event";

it("types and submits", async () => {
  const user = userEvent.setup();
  render(<Form />);

  await user.type(screen.getByRole("textbox"), "hello");
  await user.click(screen.getByRole("button"));
});

カバレッジ

# Jest
npx jest --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'

# Vitest (vitest.config.ts)
# coverage: { provider: "v8", thresholds: { lines: 80 } }

設定

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: ["./tests/setup.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      exclude: ["node_modules/", "tests/"],
    },
  },
});
// jest.config.js
module.exports = {
  preset: "ts-jest",
  testEnvironment: "jsdom",
  setupFilesAfterSetup: ["./tests/setup.ts"],
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1",
  },
  coverageThreshold: {
    global: { branches: 80, functions: 80, lines: 80, statements: 80 },
  },
};

参照

高度なパターン、Reactテストのレシピ、移行ガイドについては、references/patterns.mdをご覧ください。

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Jest & Vitest

JavaScript/TypeScript testing with Jest and Vitest.

Running Tests

# Jest
npx jest
npx jest --watch
npx jest --coverage
npx jest path/to/test.ts
npx jest -t "test name pattern"

# Vitest
npx vitest
npx vitest run          # Single run (no watch)
npx vitest --coverage
npx vitest path/to/test.ts

Test Structure

// Jest and Vitest share the same API
describe("Calculator", () => {
  let calc: Calculator;

  beforeEach(() => {
    calc = new Calculator();
  });

  afterEach(() => {
    calc.reset();
  });

  it("should add two numbers", () => {
    expect(calc.add(2, 3)).toBe(5);
  });

  it("should throw on division by zero", () => {
    expect(() => calc.divide(1, 0)).toThrow("Division by zero");
  });

  describe("negative numbers", () => {
    it("should handle negative addition", () => {
      expect(calc.add(-1, -2)).toBe(-3);
    });
  });
});

Common Matchers

// Equality
expect(value).toBe(exact);           // === strict
expect(value).toEqual(deepEqual);    // Deep equality
expect(value).toStrictEqual(strict); // Deep + type

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(10);
expect(value).toBeCloseTo(0.3, 5);

// Strings
expect(str).toMatch(/regex/);
expect(str).toContain("substring");

// Arrays/Objects
expect(arr).toContain(item);
expect(arr).toHaveLength(3);
expect(obj).toHaveProperty("key", "value");
expect(obj).toMatchObject({ name: "Alice" });

// Exceptions
expect(() => fn()).toThrow();
expect(() => fn()).toThrow("message");
expect(() => fn()).toThrow(ErrorClass);

Mocking

// Mock function
const mockFn = jest.fn();              // Jest
const mockFn = vi.fn();                // Vitest

mockFn.mockReturnValue(42);
mockFn.mockReturnValueOnce(1);
mockFn.mockResolvedValue({ data: [] });
mockFn.mockImplementation((x) => x * 2);

// Assertions
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith("arg1", "arg2");

// Mock module
jest.mock("./database");               // Jest
vi.mock("./database");                 // Vitest

// Mock with implementation
jest.mock("./api", () => ({
  fetchUser: jest.fn().mockResolvedValue({ name: "Alice" }),
}));

// Vitest equivalent
vi.mock("./api", () => ({
  fetchUser: vi.fn().mockResolvedValue({ name: "Alice" }),
}));

// Spy on existing method
const spy = jest.spyOn(object, "method");   // Jest
const spy = vi.spyOn(object, "method");     // Vitest

// Mock timers
jest.useFakeTimers();  // Jest
vi.useFakeTimers();    // Vitest

jest.advanceTimersByTime(1000);  // Jest
vi.advanceTimersByTime(1000);    // Vitest

Async Testing

// Async/await
it("fetches users", async () => {
  const users = await fetchUsers();
  expect(users).toHaveLength(3);
});

// Resolved/rejected
it("resolves with data", async () => {
  await expect(fetchData()).resolves.toEqual({ ok: true });
});

it("rejects with error", async () => {
  await expect(fetchBad()).rejects.toThrow("Network error");
});

Snapshot Testing

// Create/update snapshot
it("renders correctly", () => {
  const tree = render(<Button label="Click" />);
  expect(tree).toMatchSnapshot();
});

// Inline snapshot
it("serializes", () => {
  expect(serialize(data)).toMatchInlineSnapshot(`"expected output"`);
});

// Update snapshots: jest --updateSnapshot / vitest --update

React Testing (Testing Library)

import { render, screen, fireEvent, waitFor } from "@testing-library/react";

it("renders and interacts", async () => {
  render(<LoginForm onSubmit={mockSubmit} />);

  // Query elements
  const input = screen.getByRole("textbox", { name: /email/i });
  const button = screen.getByRole("button", { name: /submit/i });

  // Interact
  fireEvent.change(input, { target: { value: "alice@test.com" } });
  fireEvent.click(button);

  // Assert
  await waitFor(() => {
    expect(mockSubmit).toHaveBeenCalledWith("alice@test.com");
  });

  expect(screen.getByText("Success")).toBeInTheDocument();
});

// userEvent (more realistic)
import userEvent from "@testing-library/user-event";

it("types and submits", async () => {
  const user = userEvent.setup();
  render(<Form />);

  await user.type(screen.getByRole("textbox"), "hello");
  await user.click(screen.getByRole("button"));
});

Coverage

# Jest
npx jest --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'

# Vitest (vitest.config.ts)
# coverage: { provider: "v8", thresholds: { lines: 80 } }

Configuration

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: ["./tests/setup.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      exclude: ["node_modules/", "tests/"],
    },
  },
});
// jest.config.js
module.exports = {
  preset: "ts-jest",
  testEnvironment: "jsdom",
  setupFilesAfterSetup: ["./tests/setup.ts"],
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1",
  },
  coverageThreshold: {
    global: { branches: 80, functions: 80, lines: 80, statements: 80 },
  },
};

Reference

For advanced patterns, React testing recipes, and migration guides: references/patterns.md