Skip to Content

Testing

RNCopilot uses Jest 30 with jest-expo and @testing-library/react-native for component testing. This page covers test file location, patterns, and coverage targets.

Test File Location

Tests live next to the source files they test, not in a separate top-level test directory:

Button/ ├── Button.tsx ├── Button.test.tsx # Unit test ├── Button.styles.ts ├── Button.types.ts └── index.ts

Feature-level integration tests go in a __tests__/ directory within the feature:

src/features/auth/ ├── components/ ├── hooks/ ├── services/ ├── __tests__/ │ └── authFlow.test.tsx # Integration test └── ...

Test Pattern

Use @testing-library/react-native for component tests. Follow the arrange-act-assert structure:

import { render, screen, fireEvent } from '@testing-library/react-native'; import { Button } from './Button'; describe('Button', () => { it('renders with title', () => { render(<Button title="Submit" onPress={jest.fn()} />); expect(screen.getByText('Submit')).toBeTruthy(); }); it('shows loading indicator when loading', () => { render(<Button title="Submit" loading onPress={jest.fn()} />); expect(screen.getByRole('button')).toHaveAccessibilityState({ busy: true, }); }); it('calls onPress when pressed', () => { const onPress = jest.fn(); render(<Button title="Submit" onPress={onPress} />); fireEvent.press(screen.getByRole('button')); expect(onPress).toHaveBeenCalledTimes(1); }); it('does not call onPress when disabled', () => { const onPress = jest.fn(); render(<Button title="Submit" onPress={onPress} disabled />); fireEvent.press(screen.getByRole('button')); expect(onPress).not.toHaveBeenCalled(); }); });

Test Commands

# Run all tests npm test # Run tests with coverage report npm run test:coverage # Run a specific test file npx jest src/common/components/Button/Button.test.tsx

Coverage Targets

CategoryTarget
Shared UI components (src/common/components/)80%+
Feature services and hooks70%+
Utility functions (src/utils/)100%

These are targets, not hard gates. Aim to meet or exceed them for new code. Do not reduce coverage when modifying existing files.

What to Test

Components

  • Renders correctly with required props
  • Responds to user interaction (press, type, scroll)
  • Shows correct states (loading, disabled, error)
  • Accessibility roles and labels are present

Hooks

  • Returns correct initial state
  • Updates state in response to actions
  • Handles edge cases (empty data, errors)

Services

  • Returns expected data on success
  • Throws or returns error on failure
  • Passes correct parameters to the API client

Utilities

  • Every code path is covered
  • Edge cases and boundary values are tested
  • Error cases are tested

Testing Best Practices

  • Query by role or text rather than test IDs when possible.
  • Use screen from @testing-library/react-native instead of destructuring render().
  • Mock external dependencies (API, storage, navigation) at the module level.
  • Keep tests focused — one behavior per it() block.
  • Do not test implementation details (internal state, private methods).
Last updated on