frontend-typescript-testing

star 219

Designs tests with React Testing Library, MSW, and Playwright E2E. Applies component testing and E2E testing patterns.

shinpr By shinpr schedule Updated 6/14/2026

name: frontend-typescript-testing description: Designs tests with React Testing Library, MSW, and Playwright E2E. Applies component testing and E2E testing patterns.

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: prioritize meaningful assertions on critical paths and high-reuse components; treat coverage as a signal for gaps, not a target (a target gets gamed into trivial tests — Goodhart's Law). Any numeric threshold is the project's CI config
  • 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

Where to concentrate test rigor

Test foundational, high-reuse units the hardest — shared components, custom hooks, and utils reused across many features carry the widest blast radius. Higher-composition surfaces (organisms, pages) lean on integration/E2E coverage instead. Any numeric threshold is the project's CI config.

Metrics (what coverage reports break down): Statements, Branches, Functions, Lines

Test Types and Scope

  1. 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
  2. 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
  3. 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
  • Co-location principle: tests live alongside the implementation they cover
  • 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

Test user-visible results, not implementation details. Query by accessibility (getByRole/getByLabelText/getByText), not getByTestId or container.querySelector. Cover empty, error, and loading/async states, not only the happy path; await async UI with findBy*.

// Test the user-visible result
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()
})

// Error state: override the handler for one test
it('shows an error message on API failure', async () => {
  server.use(http.get('/api/users', () => new HttpResponse(null, { status: 500 })))
  render(<UserList />)
  expect(await screen.findByText('Something went wrong')).toBeInTheDocument()
})
Install via CLI
npx skills add https://github.com/shinpr/ai-coding-project-boilerplate --skill frontend-typescript-testing
Repository Details
star Stars 219
call_split Forks 23
navigation Branch main
article Path SKILL.md
More from Creator