Skip to content

Latest commit

 

History

History
306 lines (210 loc) · 6.72 KB

File metadata and controls

306 lines (210 loc) · 6.72 KB

Testing Guide

This document provides information about the testing setup and how to run tests in this project.

Testing Stack

  • Test Runner (Unit/Integration): Jest 30.x
  • Testing Library: @testing-library/react 16.x
  • Test Environment: jsdom (simulates browser environment)
  • E2E Testing: Playwright
  • Coverage Provider: V8
  • CI/CD: GitHub Actions

Coverage Thresholds

The project enforces these minimum coverage thresholds:

  • Branches: 50%
  • Functions: 35%
  • Lines: 60%
  • Statements: 60%

Running Tests

Unit/Integration Tests (Jest)

Run all tests

pnpm test

Run tests in watch mode

pnpm test:watch

Run tests with coverage

pnpm test:coverage

Run specific test file

pnpm test path/to/test-file.test.tsx

Run tests matching a pattern

pnpm test --testNamePattern="Button"

E2E Tests (Playwright)

E2E tests are located in tests/e2e/ and run against http://localhost:3001/starmap.

Run all E2E tests

pnpm exec playwright test

Run tests for a specific browser

pnpm exec playwright test --project=chromium
pnpm exec playwright test --project=firefox
pnpm exec playwright test --project=webkit

Run specific test file

pnpm exec playwright test tests/e2e/starmap/ui-controls.spec.ts

Run tests with UI mode

pnpm exec playwright test --ui

View test report

pnpm exec playwright show-report

Test File Structure

Test files should be placed next to the files they test with the .test.ts or .test.tsx extension:

components/
  ui/
    button.tsx
    button.test.tsx  ← Test file
app/
  page.tsx
  page.test.tsx      ← Test file
lib/
  utils.ts
  utils.test.ts      ← Test file

Writing Tests

Component Test Example

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './button';

describe('Button', () => {
  it('renders a button with text', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
  });

  it('handles click events', async () => {
    const handleClick = jest.fn();
    const user = userEvent.setup();
    
    render(<Button onClick={handleClick}>Click me</Button>);
    await user.click(screen.getByRole('button'));
    
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});

Utility Function Test Example

import { cn } from './utils';

describe('cn utility function', () => {
  it('merges class names correctly', () => {
    const result = cn('class1', 'class2');
    expect(result).toBe('class1 class2');
  });
});

Coverage Reports

After running pnpm test:coverage, coverage reports are generated in the coverage/ directory:

  • HTML Report: coverage/index.html - Open in browser for interactive coverage report
  • LCOV Report: coverage/lcov.info - For CI/CD integration
  • JUnit XML: coverage/junit.xml - For CI/CD test result reporting
  • Clover XML: coverage/clover.xml - Alternative coverage format

Viewing Coverage Report

Open the HTML coverage report in your browser:

# Windows
start coverage/index.html

# macOS
open coverage/index.html

# Linux
xdg-open coverage/index.html

Jest Configuration

The Jest configuration is in jest.config.ts and includes:

  • Test Environment: jsdom for React component testing
  • Setup File: jest.setup.ts - Configures testing-library/jest-dom and mocks
  • Module Name Mapper: Handles path aliases (@/components, @/lib, etc.)
  • Coverage Collection: Configured to collect from app/, components/, and lib/ directories
  • Reporters: Default console reporter + JUnit XML reporter for CI

Mocked Modules

The following Next.js modules are automatically mocked in jest.setup.ts:

  • next/image - Mocked to render as standard <img> tag
  • next/navigation - Mocked router hooks (useRouter, usePathname, useSearchParams)

CI/CD Integration

Tests run automatically on:

  • Push to main or develop branches
  • Pull requests to main or develop branches

The CI pipeline:

  1. Installs dependencies
  2. Runs linting (pnpm lint)
  3. Runs tests with coverage (pnpm test:coverage)
  4. Uploads coverage to Codecov (if configured)
  5. Uploads test results and coverage as artifacts
  6. Builds the Next.js application (pnpm build)

GitHub Actions Workflow

The workflow is defined in .github/workflows/ci.yml.

Setting up Codecov (Optional)

To enable Codecov integration:

  1. Sign up at codecov.io
  2. Add your repository
  3. Add CODECOV_TOKEN to your GitHub repository secrets
  4. Coverage will be automatically uploaded on each CI run

Best Practices

1. Test Behavior, Not Implementation

❌ Bad:

expect(component.state.count).toBe(1);

✅ Good:

expect(screen.getByText('Count: 1')).toBeInTheDocument();

2. Use Accessible Queries

Prefer queries that reflect how users interact with your app:

  1. getByRole - Best for most elements
  2. getByLabelText - Good for form fields
  3. getByPlaceholderText - For inputs without labels
  4. getByText - For non-interactive elements
  5. getByTestId - Last resort

3. Use User Events

Use @testing-library/user-event instead of fireEvent:

❌ Bad:

fireEvent.click(button);

✅ Good:

const user = userEvent.setup();
await user.click(button);

4. Clean Up After Tests

Jest automatically cleans up after each test, but if you create side effects:

afterEach(() => {
  // Clean up
  jest.clearAllMocks();
});

5. Test Accessibility

it('has accessible button', () => {
  render(<Button>Click me</Button>);
  const button = screen.getByRole('button', { name: /click me/i });
  expect(button).toBeInTheDocument();
});

Troubleshooting

Tests are slow

  • Use test.only() to run a single test during development
  • Use pnpm test:watch to run only changed tests

Module not found errors

  • Check that path aliases in jest.config.ts match tsconfig.json
  • Ensure the module is properly mocked if it's a Next.js-specific module

Coverage not collected

  • Verify the file is in the collectCoverageFrom patterns in jest.config.ts
  • Check that the file isn't in coveragePathIgnorePatterns

Resources