Claude
Skills
Sign in
Back

testing-strategy

Included with Lifetime
$97 forever

Comprehensive testing strategy using Vitest for unit/integration tests and Playwright for E2E tests with best practices and coverage targets

Generaltestingvitestplaywrightqualitytdde2e

What this skill does


# Testing Strategy Skill

## Objective

Implement comprehensive testing strategy covering unit, integration, and E2E tests using modern tools (Vitest, Playwright) with clear coverage targets and best practices.

## When to Use This Skill

Auto-invoke when:
- User mentions "test", "testing", "coverage", "TDD", "E2E"
- Setting up new project
- Adding new features (need tests)
- Debugging test failures
- Improving test coverage

## Testing Pyramid

```
        /\
       /E2E\         Few, slow, expensive
      /------\
     /  Integ \      Some, moderate speed
    /----------\
   / Unit Tests \    Many, fast, cheap
  /--------------\
```

**Distribution**:
- **70%** Unit Tests - Fast, isolated, cheap
- **20%** Integration Tests - Moderate speed, test interactions
- **10%** E2E Tests - Slow, expensive, critical user flows

## Test Types

### 1. Unit Tests (Vitest)

**What**: Test individual functions/components in isolation

**Tools**: Vitest, React Testing Library

**Coverage Target**: 80%+

**Setup**:
```bash
npm install -D vitest @vitest/ui @testing-library/react @testing-library/jest-dom
```

**Config** (`vitest.config.ts`):
```typescript
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './tests/setup.ts',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      exclude: ['node_modules/', 'tests/'],
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80
      }
    }
  }
})
```

**Example** (`Button.test.tsx`):
```typescript
import { render, screen, fireEvent } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
import { Button } from './Button'

describe('Button', () => {
  it('renders with text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('calls onClick when clicked', () => {
    const handleClick = vi.fn()
    render(<Button onClick={handleClick}>Click</Button>)
    fireEvent.click(screen.getByText('Click'))
    expect(handleClick).toHaveBeenCalledOnce()
  })

  it('is disabled when disabled prop is true', () => {
    render(<Button disabled>Disabled</Button>)
    expect(screen.getByRole('button')).toBeDisabled()
  })
})
```

**Commands**:
```bash
npm run test              # Run all tests
npm run test:watch        # Watch mode
npm run test:ui           # Visual UI
npm run test:coverage     # With coverage
```

### 2. Integration Tests (Vitest)

**What**: Test component interactions, API calls, state management

**Example** (`UserProfile.test.tsx`):
```typescript
import { render, screen, waitFor } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
import { UserProfile } from './UserProfile'

// Mock API
vi.mock('./api', () => ({
  fetchUser: vi.fn(() => Promise.resolve({
    id: 1,
    name: 'John Doe',
    email: '[email protected]'
  }))
}))

describe('UserProfile Integration', () => {
  it('fetches and displays user data', async () => {
    render(<UserProfile userId="1" />)
    
    expect(screen.getByText('Loading...')).toBeInTheDocument()
    
    await waitFor(() => {
      expect(screen.getByText('John Doe')).toBeInTheDocument()
      expect(screen.getByText('[email protected]')).toBeInTheDocument()
    })
  })
})
```

### 3. E2E Tests (Playwright)

**What**: Test complete user flows in real browser

**Tools**: Playwright

**Coverage Target**: Critical paths only

**Setup**:
```bash
npm install -D @playwright/test
npx playwright install
```

**Config** (`playwright.config.ts`):
```typescript
import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'mobile',
      use: { ...devices['iPhone 13'] },
    },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
})
```

**Example** (`e2e/auth.spec.ts`):
```typescript
import { test, expect } from '@playwright/test'

test.describe('Authentication Flow', () => {
  test('user can sign up and log in', async ({ page }) => {
    // Sign up
    await page.goto('/signup')
    await page.fill('[name="email"]', '[email protected]')
    await page.fill('[name="password"]', 'SecurePass123!')
    await page.click('button[type="submit"]')
    
    // Should redirect to dashboard
    await expect(page).toHaveURL(/\/dashboard/)
    await expect(page.locator('h1')).toContainText('Welcome')
    
    // Log out
    await page.click('[aria-label="User menu"]')
    await page.click('text=Logout')
    
    // Should redirect to home
    await expect(page).toHaveURL('/')
    
    // Log back in
    await page.goto('/login')
    await page.fill('[name="email"]', '[email protected]')
    await page.fill('[name="password"]', 'SecurePass123!')
    await page.click('button[type="submit"]')
    
    await expect(page).toHaveURL(/\/dashboard/)
  })
})
```

**Commands**:
```bash
npx playwright test                    # Run all E2E
npx playwright test --ui               # Interactive mode
npx playwright test --headed           # Show browser
npx playwright test --project=chromium # Specific browser
npx playwright show-report             # View last report
```

## Testing Best Practices

### AAA Pattern
```typescript
// Arrange
const user = { id: 1, name: 'John' }
const mockFetch = vi.fn()

// Act
const result = await fetchUser(mockFetch, 1)

// Assert
expect(result).toEqual(user)
expect(mockFetch).toHaveBeenCalledWith('/api/users/1')
```

### Test Naming
```typescript
// Good: descriptive, explains what and when
it('displays error message when API returns 404', () => {})
it('disables submit button when form is invalid', () => {})

// Bad: vague, unclear
it('works', () => {})
it('test 1', () => {})
```

### One Assertion Per Test (Guideline)
```typescript
// Prefer focused tests
it('renders user name', () => {
  render(<User name="John" />)
  expect(screen.getByText('John')).toBeInTheDocument()
})

it('renders user email', () => {
  render(<User email="[email protected]" />)
  expect(screen.getByText('[email protected]')).toBeInTheDocument()
})

// Over complex tests
it('renders user data', () => {
  // Multiple unrelated assertions
})
```

### Mock External Dependencies
```typescript
// Mock API calls
vi.mock('./api', () => ({
  fetchUser: vi.fn()
}))

// Mock environment
vi.stubEnv('API_URL', 'http://test-api.com')

// Mock timers
vi.useFakeTimers()
const now = new Date('2024-01-01')
vi.setSystemTime(now)
```

## Coverage Strategy

### What to Test

✅ **Do Test**:
- Business logic
- Edge cases and error handling
- User interactions
- API integration
- State management
- Validation logic
- Critical user flows (E2E)

❌ **Don't Test**:
- Third-party libraries
- Framework internals
- Constants
- Simple getters/setters
- Generated code

### Coverage Targets

**Minimum**:
- Lines: 80%
- Functions: 80%
- Branches: 75%
- Statements: 80%

**Ideal**:
- Critical paths: 100%
- Business logic: 95%+
- UI components: 85%+
- Utilities: 90%+

### Run Coverage
```bash
npm run test:coverage

# View in browser
open coverage/index.html
```

## Testing Workflow

### 1. TDD Approach (Recommended)
```
1. Write failing test
2. Write minimal code to pass
3. Refactor
4. Repeat
```

### 2. Test-After (Pragmatic)
```
1. Implement feature
2. Write tests
3. Achieve 80%+ coverage
4. Refactor with confidence
```

### 3. Pre-Commit Testing
```bash
# Run before every commit
npm run test:quick        # Fast unit tests
npm run lint
npm

Related in General