Skip to main content

vitest

Vitest unit testing patterns with React Testing Library. Trigger: When writing unit tests for React components, hooks, or utilities.

소스 정보

저장소
prowler-cloud/prowler
최근 소스 활동
2026년 5월 27일 14:42
감지된 SKILL.md 언어
영어
스타
14,884
포크
2,402

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
vitest
description
Vitest unit testing patterns with React Testing Library. Trigger: When writing unit tests for React components, hooks, or utilities.
license
Apache-2.0
metadata
{"author":"prowler-cloud","version":"1.0","scope":["root","ui"],"auto_invoke":["Writing Vitest tests","Writing React component tests","Writing unit tests for UI","Testing hooks or utilities"]}
allowed-tools
Read, Edit, Write, Glob, Grep, Bash, Task
> **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: ```typescript 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 ```typescript describe("ComponentName", () => { describe("when [condition]", () => { it("should [expected behavior]", () => {}); }); }); ``` **Group by behavior, NOT by method.** --- ## Query Priority (REQUIRED) | Priority | Query | Use Case | |----------|-------|----------| | 1 | `getByRole` | Buttons, inputs, headings | | 2 | `getByLabelText` | Form fields | | 3 | `getByPlaceholderText` | Inputs without label | | 4 | `getByText` | Static text | | 5 | `getByTestId` | Last resort only | ```typescript // ✅ GOOD screen.getByRole("button", { name: /submit/i }); screen.getByLabelText(/email/i); // ❌ BAD container.querySelector(".btn-primary"); ``` --- ## userEvent over fireEvent (REQUIRED) ```typescript // ✅ 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 ```typescript // ✅ 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 ```typescript // 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 | Method | When to Use | |--------|-------------| | `vi.spyOn` | Observe without replacing (PREFERRED) | | `vi.mock` | Replace entire module (use sparingly) | --- ## Common Matchers ```typescript // 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 ```typescript // ❌ 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 ```text components/ ├── Button/ │ ├── Button.tsx │ ├── Button.test.tsx # Co-located │ └── index.ts ``` --- ## Commands ```bash pnpm test # Watch mode pnpm test:run # Single run pnpm test:coverage # With coverage pnpm test Button # Filter by name ```
GitHub에서 보기