В RN-проекте те же уровни тестов, что во фронтенде, плюс особенность: нативные модули в Jest не работают, их нужно подменять, а E2E-тесты идут на эмуляторе или устройстве.
Unit-тесты: Jest
Jest входит в шаблон проекта (пресет react-native или jest-expo). Тестируют чистую логику: форматирование, редьюсеры, селекторы, хуки данных, очереди и кеши.
test('склеивает страницы без дублей', () => {
expect(mergePages([{ id: 1 }], [{ id: 1 }, { id: 2 }])).toEqual([{ id: 1 }, { id: 2 }]);
});
Время подменяют через jest.useFakeTimers() и jest.advanceTimersByTime(ms), чтобы тест дебаунса не ждал реальные 300 мс.
Компонентные тесты: React Native Testing Library
RNTL рендерит компоненты в тестовом окружении (без устройства) и предлагает искать их так, как видит пользователь:
test('показывает ошибку при пустом email', async () => {
const user = userEvent.setup();
render(<LoginForm onSubmit={jest.fn()} />);
await user.press(screen.getByRole('button', { name: 'Войти' }));
expect(screen.getByText('Введите email')).toBeOnTheScreen();
});
- Запросы:
getByRole,getByText,getByLabelTextпредпочтительнееgetByTestId. Тест через роли заодно проверяет доступность. getBy*бросает ошибку, если элемента нет;queryBy*возвращаетnull(для проверки отсутствия);findBy*асинхронный, ждёт появления.userEventреалистичнееfireEvent: имитирует последовательность событий нажатия и ввода.- Не тестируют детали реализации: состояние компонента и внутренние функции.
Моки нативных модулей
В Jest нет нативной части: вызов нативного модуля упадёт. Варианты:
- готовые моки библиотек (многие поставляют
jest/setupили инструкции: AsyncStorage, Reanimated, Gesture Handler); jest.mock('модуль', () => ({ ... }))для своих модулей;- обёртка над нативным API в виде своего сервиса, который в тестах подменяется фейком.
Сеть мокают на уровне HTTP (MSW поддерживает React Native) или подменой клиента API.
E2E: Detox и Maestro
Detox (Wix): тесты на JS, запускают настоящее приложение на эмуляторе или симуляторе. Главная особенность: синхронизация «серый ящик»: Detox знает о сетевых запросах, таймерах и анимациях внутри приложения и ждёт, пока оно станет неактивным, прежде чем действовать. Отсюда меньше нестабильности без ручных задержек. Требует настройки сборки.
Maestro: сценарии на YAML, работает как «чёрный ящик» поверх готовой сборки, прост в старте, сам выжидает появления элементов и повторяет действия. Подходит и для Expo-проектов, используется в облачных CI-сервисах.
appId: com.example.shop
---
- launchApp
- tapOn: "Войти"
- inputText: "user@example.com"
- assertVisible: "Главная"
E2E-тесты медленные и дорогие, поэтому ими покрывают только критичные сценарии: вход, покупку, онбординг.
Что делает код тестируемым
- Логика в хуках и чистых функциях, а не в JSX.
- Зависимости (API, хранилище, нативные сервисы) передаются через провайдеры и подменяются.
testIDи роли доступности на интерактивных элементах.
Частые ошибки
- Тестировать реализацию, а не поведение.
getByдля проверки отсутствия (нуженqueryBy).- Реальные таймеры и сеть в unit-тестах.
- Пытаться покрыть всё E2E-тестами.
Что спросят на собесе
- Пирамида тестов в RN-проекте.
- Как протестировать компонент с RNTL,
getBy/queryBy/findBy. - Как замокать нативный модуль.
- Detox против Maestro.
- Как тестировать код с таймерами.