Ai-coding-project-boilerplate frontend-typescript-testing
Designs tests with React Testing Library, MSW, and Playwright E2E. Applies component testing and E2E testing patterns.
install
source · Clone the upstream repo
git clone https://github.com/shinpr/ai-coding-project-boilerplate
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/shinpr/ai-coding-project-boilerplate "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills-en/frontend-typescript-testing" ~/.claude/skills/shinpr-ai-coding-project-boilerplate-frontend-typescript-testing && rm -rf "$T"
manifest:
.claude/skills-en/frontend-typescript-testing/SKILL.mdsource content
TypeScript Testing Rules (Frontend)
References
| Test Type | Reference | When to Use |
|---|---|---|
| Unit / Integration | This document | Implementing React component tests with RTL + Vitest + MSW |
| E2E | references/e2e.md | Implementing browser-level E2E tests with Playwright |
Test Framework
- Vitest: This project uses Vitest
- React Testing Library: For component testing
- MSW (Mock Service Worker): For API mocking
- Test imports:
import { describe, it, expect, beforeEach, vi } from 'vitest' - Component test imports:
import { render, screen } from '@testing-library/react' - User interaction:
import userEvent from '@testing-library/user-event' - Mock creation: Use
vi.mock()
Basic Testing Policy
Quality Requirements
- Coverage: Unit test coverage must be 60% or higher (Frontend standard 2025)
- Independence: Each test can run independently without depending on other tests
- Reproducibility: Tests are environment-independent and always return the same results
- Readability: Test code maintains the same quality as production code
Coverage Requirements (ADR-0002 Compliant)
Mandatory: Unit test coverage must be 60% or higher Component-specific targets:
- Atoms (Button, Text, etc.): 70% or higher
- Molecules (FormField, etc.): 65% or higher
- Organisms (Header, Footer, etc.): 60% or higher
- Custom Hooks: 65% or higher
- Utils: 70% or higher
Metrics: Statements, Branches, Functions, Lines
Test Types and Scope
-
Unit Tests (React Testing Library)
- Verify behavior of individual components or functions
- Mock all external dependencies
- Most numerous, implemented with fine granularity
- Focus on user-observable behavior
-
Integration Tests (React Testing Library + MSW)
- Verify coordination between multiple components
- Mock APIs with MSW (Mock Service Worker)
- No actual DB connections (backend manages DB)
- Verify major functional flows
-
Cross-functional Verification in E2E Tests
- Mandatory verification of impact on existing features when adding new features
- Cover integration points with "High" and "Medium" impact levels from Design Doc's "Integration Point Map"
- Verification pattern: Existing feature operation -> Enable new feature -> Verify continuity of existing features
- Success criteria: No change in displayed content, rendering time within 5 seconds
- Designed for automatic execution in CI/CD pipelines
Test Implementation Conventions
Directory Structure (Co-location Principle)
src/ └── components/ └── Button/ ├── Button.tsx ├── Button.test.tsx # Co-located with component └── index.ts
Rationale:
- React Testing Library best practice
- ADR-0002 Co-location principle
- Easy to find and maintain tests alongside implementation
Naming Conventions
- Test files:
{ComponentName}.test.tsx - Integration test files:
{FeatureName}.integration.test.tsx - Test suites: Names describing target components or features
- Test cases: Names describing expected behavior from user perspective
Test Code Quality Rules
Recommended: Keep all tests always active
- Merit: Guarantees test suite completeness
- Practice: Fix problematic tests and activate them
Avoid: test.skip() or commenting out
- Reason: Creates test gaps and incomplete quality checks
- Solution: Completely delete unnecessary tests
Mock Type Safety Enforcement
MSW (Mock Service Worker) Setup
// Type-safe MSW handler (MSW v2) import { http, HttpResponse } from 'msw' const handlers = [ http.get('/api/users/:id', () => { return HttpResponse.json({ id: '1', name: 'John' } satisfies User) }) ]
Component Mock Type Safety
// Only required parts type TestProps = Pick<ButtonProps, 'label' | 'onClick'> const mockProps: TestProps = { label: 'Click', onClick: vi.fn() } // Only when absolutely necessary, with clear justification const mockRouter = { push: vi.fn() } as unknown as Router // Complex router type structure
Basic React Testing Library Example
import { describe, it, expect, vi } from 'vitest' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { Button } from './Button' describe('Button', () => { it('should call onClick when clicked', async () => { const user = userEvent.setup() const onClick = vi.fn() render(<Button label="Click me" onClick={onClick} />) await user.click(screen.getByRole('button', { name: 'Click me' })) expect(onClick).toHaveBeenCalledOnce() }) })
Test Design Patterns
// Correct: test user-visible results it('increments count when clicked', async () => { const user = userEvent.setup() render(<Counter />) await user.click(screen.getByRole('button', { name: '+' })) expect(screen.getByText('Count: 1')).toBeInTheDocument() }) // Avoid: testing implementation details it('calls setState', () => { const setState = vi.spyOn(React, 'useState') render(<Counter />) // ... })