Testing
Learn how to test components built with Rott UI using Jest and React Native Testing Library.
Setup
Rott UI components work seamlessly with React Native Testing Library.
Install Dependencies
npm install --save-dev @testing-library/react-native @testing-library/jest-native
Jest Configuration
jest.config.js
module.exports = {
preset: 'react-native',
setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@tansuk/rott-ui)/)',
],
};
Testing Components
Button Tests
import { render, fireEvent } from '@testing-library/react-native';
import { Button } from '@tansuk/rott-ui';
describe('Button', () => {
it('calls onPress when pressed', () => {
const onPress = jest.fn();
const { getByText } = render(
<Button variant="primary" onPress={onPress}>
Click Me
</Button>
);
fireEvent.press(getByText('Click Me'));
expect(onPress).toHaveBeenCalledTimes(1);
});
it('does not call onPress when disabled', () => {
const onPress = jest.fn();
const { getByText } = render(
<Button variant="primary" disabled onPress={onPress}>
Click Me
</Button>
);
fireEvent.press(getByText('Click Me'));
expect(onPress).not.toHaveBeenCalled();
});
it('shows loading state', () => {
const { getByText } = render(
<Button variant="primary" isLoading loadingText="Loading...">
Submit
</Button>
);
expect(getByText('Loading...')).toBeTruthy();
});
});
Input Tests
import { render, fireEvent } from '@testing-library/react-native';
import { Input } from '@tansuk/rott-ui';
describe('Input', () => {
it('updates value on text change', () => {
const onChangeText = jest.fn();
const { getByPlaceholderText } = render(
<Input
name="email"
type="email"
placeholder="Email"
onChangeText={onChangeText}
/>
);
const input = getByPlaceholderText('Email');
fireEvent.changeText(input, '[email protected]');
expect(onChangeText).toHaveBeenCalledWith('[email protected]');
});
it('shows error message when provided', () => {
const { getByText } = render(
<Input
name="email"
type="email"
errorMessage="Invalid email"
touched
/>
);
expect(getByText('Invalid email')).toBeTruthy();
});
});
Form Tests
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { Formik } from 'formik';
import * as Yup from 'yup';
const LoginSchema = Yup.object().shape({
email: Yup.string().email('Invalid').required('Required'),
password: Yup.string().min(8, 'Too short').required('Required'),
});
describe('LoginForm', () => {
it('validates form on submit', async () => {
const onSubmit = jest.fn();
const { getByPlaceholderText, getByText } = render(
<Formik
initialValues={{ email: '', password: '' }}
validationSchema={LoginSchema}
onSubmit={onSubmit}
>
{({ handleChange, handleSubmit, errors }) => (
<>
<Input
name="email"
placeholder="Email"
onChangeText={handleChange('email')}
/>
<Input
name="password"
placeholder="Password"
onChangeText={handleChange('password')}
/>
<Button onPress={handleSubmit}>Submit</Button>
</>
)}
</Formik>
);
fireEvent.press(getByText('Submit'));
await waitFor(() => {
expect(onSubmit).not.toHaveBeenCalled();
});
});
});
Mocking
Mock RottProvider
import { RottProvider } from '@tansuk/rott-ui';
const wrapper = ({ children }) => (
<RottProvider>{children}</RottProvider>
);
const { getByText } = render(<MyComponent />, { wrapper });
Mock Navigation
const mockNavigation = {
navigate: jest.fn(),
goBack: jest.fn(),
};
<MyScreen navigation={mockNavigation} />
Snapshot Testing
import { render } from '@testing-library/react-native';
it('matches snapshot', () => {
const { toJSON } = render(
<Button variant="primary">Click Me</Button>
);
expect(toJSON()).toMatchSnapshot();
});
Best Practices
Do's ✅
- Test user interactions, not implementation
- Use data-testid for complex queries
- Test error states and edge cases
- Mock external dependencies
- Use snapshot tests sparingly
Don'ts ❌
- Don't test implementation details
- Don't forget to test accessibility
- Don't skip error scenarios
- Don't over-rely on snapshots