mcpField
V
vitest

vitest

github.com/prowler-cloudテスト・品質15.1k67 回インストール1 日前に更新
リポジトリ

vitest について

vitestは、VitestとReact Testing Libraryでユニットテストと統合テストを書くためのスキルです。テスト構成、クエリ、操作、非同期アサーション、モック、ファイル整理の規則を示します。

主な機能

  1. 01Given/When/Thenのテスト構成
  2. 02振る舞い別のdescribeブロック
  3. 03アクセシブルなクエリの優先順位
  4. 04userEventによる操作指針
  5. 05非同期アサーションとモックの規則

活用シーン

  1. 01Reactコンポーネントのテスト
  2. 02ユニットテストと統合テストの作成
  3. 03テストファイルの整理とレビュー

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/prowler-cloud/prowler --skill vitest

インストール後、Claude Code で/vitestを入力して読み込まれたか確認します。

詳細

E2E テストの場合:prowler-test-ui スキル(Playwright)を使用します。 このスキルでは、Vitest と React Testing Library を使ったユニットテスト/統合テストを扱います。

テスト構成(必須)

コメントを使ったGiven/When/Then(AAA)パターンを使用します。

it("should update user name when form is submitted", async () => {
  // Given - Arrange
  const user = userEvent.setup();
  const onSubmit = vi.fn();
  render(<UserForm onSubmit={onSubmit} />);

  // When - Act
  await user.type(screen.getByLabelText(/name/i), "John");
  await user.click(screen.getByRole("button", { name: /submit/i }));

  // Then - Assert
  expect(onSubmit).toHaveBeenCalledWith({ name: "John" });
});

Describe ブロックの構成

describe("ComponentName", () => {
  describe("when [condition]", () => {
    it("should [expected behavior]", () => {});
  });
});

メソッドではなく、動作ごとにグループ化します。


クエリの優先順位(必須)

優先順位クエリ使用例
1getByRoleボタン、入力欄、見出し
2getByLabelTextフォームフィールド
3getByPlaceholderTextラベルのない入力欄
4getByText静的テキスト
5getByTestId最終手段のみ
// ✅ GOOD
screen.getByRole("button", { name: /submit/i });
screen.getByLabelText(/email/i);

// ❌ BAD
container.querySelector(".btn-primary");

fireEvent より userEvent を優先(必須)

// ✅ ALWAYS use userEvent
const user = userEvent.setup();
await user.click(button);
await user.type(input, "hello");

// ❌ NEVER use fireEvent for interactions
fireEvent.click(button);

非同期テストのパターン

// ✅ findBy for elements that appear async
const element = await screen.findByText(/loaded/i);

// ✅ waitFor for assertions
await waitFor(() => {
  expect(screen.getByText(/success/i)).toBeInTheDocument();
});

// ✅ ONE assertion per waitFor
await waitFor(() => expect(mockFn).toHaveBeenCalled());
await waitFor(() => expect(screen.getByText(/done/i)).toBeVisible());

// ❌ NEVER multiple assertions in waitFor
await waitFor(() => {
  expect(mockFn).toHaveBeenCalled();
  expect(screen.getByText(/done/i)).toBeVisible(); // Slower failures
});

モック

// Basic mock
const handleClick = vi.fn();

// Mock with return value
const fetchUser = vi.fn().mockResolvedValue({ name: "John" });

// Always clean up
afterEach(() => {
  vi.restoreAllMocks();
});
vi.spyOn と vi.mock
メソッド使用する場面
vi.spyOn置き換えずに監視する場合(推奨)
vi.mockモジュール全体を置き換える場合(控えめに使用)

よく使うマッチャー

// Presence
expect(element).toBeInTheDocument();
expect(element).toBeVisible();

// State
expect(button).toBeDisabled();
expect(input).toHaveValue("text");
expect(checkbox).toBeChecked();

// Content
expect(element).toHaveTextContent(/hello/i);
expect(element).toHaveAttribute("href", "/home");

// Functions
expect(fn).toHaveBeenCalledWith(arg1, arg2);
expect(fn).toHaveBeenCalledTimes(2);

テストしてはいけないもの

// ❌ Internal state
expect(component.state.isLoading).toBe(true);

// ❌ Third-party libraries
expect(axios.get).toHaveBeenCalled();

// ❌ Static content (unless conditional)
expect(screen.getByText("Welcome")).toBeInTheDocument();

// ✅ User-visible behavior
expect(screen.getByRole("button")).toBeDisabled();

ファイル構成

components/
├── Button/
│   ├── Button.tsx
│   ├── Button.test.tsx    # Co-located
│   └── index.ts

コマンド

pnpm test                    # Watch mode
pnpm test:run               # Single run
pnpm test:coverage          # With coverage
pnpm test Button            # Filter by name

コメント