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.tsFeature-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.tsxCoverage Targets
| Category | Target |
|---|---|
Shared UI components (src/common/components/) | 80%+ |
| Feature services and hooks | 70%+ |
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
screenfrom@testing-library/react-nativeinstead of destructuringrender(). - 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