@testing-library/react-native (RNTL) cung cấp API tương tự @testing-library/react (web) nhưng adapt cho RN component tree.
Setup:
pnpm add -D jest @testing-library/react-native @testing-library/jest-nativejest.config.js:
module.exports = {
preset: 'react-native',
setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@react-navigation|expo|@expo)/)',
],
}Test ví dụ:
import { render, screen, fireEvent, waitFor } from '@testing-library/react-native'
import { LoginForm } from './LoginForm'
test('submit calls onLogin with email', async () => {
const onLogin = jest.fn()
render(<LoginForm onLogin={onLogin} />)
fireEvent.changeText(screen.getByPlaceholderText('Email'), 'a@b.com')
fireEvent.changeText(screen.getByPlaceholderText('Password'), 'pass1234')
fireEvent.press(screen.getByRole('button', { name: /sign in/i }))
await waitFor(() => expect(onLogin).toHaveBeenCalledWith('a@b.com'))
})Best practices:
- Query bằng accessibility role/label (getByRole, getByLabelText) thay vì testID — tăng coverage a11y luôn.
- Mock native module qua jest.mock('react-native-mmkv', () => ({ MMKV: jest.fn() })).
- Mock navigation: jest.mock('@react-navigation/native') rồi mock useNavigation.
- Snapshot test ít dùng — dễ false negative khi UI legitimate đổi.
Coverage realistic: focus business logic + form validation + navigation flow. Skip pixel-perfect visual (dùng visual regression test thay).
@testing-library/react-native (RNTL) provides an API similar to @testing-library/react (web), adapted for the RN component tree.
Setup:
pnpm add -D jest @testing-library/react-native @testing-library/jest-nativejest.config.js:
module.exports = {
preset: 'react-native',
setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
transformIgnorePatterns: [
'node_modules/(?!(react-native|@react-native|@react-navigation|expo|@expo)/)',
],
}Sample test:
import { render, screen, fireEvent, waitFor } from '@testing-library/react-native'
import { LoginForm } from './LoginForm'
test('submit calls onLogin with email', async () => {
const onLogin = jest.fn()
render(<LoginForm onLogin={onLogin} />)
fireEvent.changeText(screen.getByPlaceholderText('Email'), 'a@b.com')
fireEvent.changeText(screen.getByPlaceholderText('Password'), 'pass1234')
fireEvent.press(screen.getByRole('button', { name: /sign in/i }))
await waitFor(() => expect(onLogin).toHaveBeenCalledWith('a@b.com'))
})Best practices:
- Query by accessibility role/label (getByRole, getByLabelText) instead of testID — boosts a11y coverage at the same time.
- Mock native modules via jest.mock('react-native-mmkv', () => ({ MMKV: jest.fn() })).
- Mock navigation: jest.mock('@react-navigation/native') then mock useNavigation.
- Snapshot tests are rarely useful — they false-negative on legitimate UI changes.
Realistic coverage: focus on business logic + form validation + navigation flow. Skip pixel-perfect visual checks (use a visual regression tool instead).