mcpField
V
vitest

vitest

github.com/prowler-cloudTesting & quality15.1k67 installsUpdated 1d ago
Repository

About vitest

vitest is a skill for writing unit and integration tests with Vitest and React Testing Library. It sets conventions for test structure, queries, interactions, async assertions, mocking, and file organization.

Key features

  1. 01Given/When/Then test structure
  2. 02Behavior-based describe blocks
  3. 03Accessible query priority
  4. 04userEvent interaction guidance
  5. 05Async assertions and mocking practices

Use cases

  1. 01Testing React components
  2. 02Writing unit and integration tests
  3. 03Organizing and reviewing test files

Install

Copy the command and run it in a terminal.

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

After installing, type/vitestin Claude Code to confirm it loaded.

Details

From the project README

For E2E tests: Use prowler-test-ui skill (Playwright). This skill covers unit/integration tests with Vitest + React Testing Library.

Test Structure (REQUIRED)

Use Given/When/Then (AAA) pattern with comments:

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 Block Organization

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

Group by behavior, NOT by method.


Query Priority (REQUIRED)

PriorityQueryUse Case
1getByRoleButtons, inputs, headings
2getByLabelTextForm fields
3getByPlaceholderTextInputs without label
4getByTextStatic text
5getByTestIdLast resort only
// ✅ GOOD
screen.getByRole("button", { name: /submit/i });
screen.getByLabelText(/email/i);

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

userEvent over fireEvent (REQUIRED)

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

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

Async Testing Patterns

// ✅ 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
});

Mocking

// 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 vs vi.mock
MethodWhen to Use
vi.spyOnObserve without replacing (PREFERRED)
vi.mockReplace entire module (use sparingly)

Common Matchers

// 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);

What NOT to Test

// ❌ 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();

File Organization

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

Commands

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

Comments

Markdown supported