Урок по треку React Native 6 мин

Тестирование: Jest, Testing Library, Detox и Maestro

Jest, React Native Testing Library, моки нативных модулей, E2E на Detox и Maestro.

В 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.
  • Как тестировать код с таймерами.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.