Стратегия тестирования
Тестирование React Native приложений включает три уровня:
▸Пирамида тестирования
Jest: базовая настройка
Jest включен в React Native по умолчанию через react-native preset.
▸Конфигурация
1// jest.config.js2module.exports = {3 preset: 'react-native',4 setupFilesAfterSetup: ['./jest.setup.js'],5 transformIgnorePatterns: [6 'node_modules/(?!(react-native|@react-native|@react-navigation)/)',7 ],8 moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],9};
▸Юнит-тесты утилит
1// utils/formatters.test.js2import { formatCurrency, formatDate } from './formatters';34describe('formatCurrency', () => {5 it('formats number as currency', () => {6 expect(formatCurrency(1234.56)).toBe('1 234,56 ₽');7 });89 it('handles zero', () => {10 expect(formatCurrency(0)).toBe('0,00 ₽');11 });12});1314describe('formatDate', () => {15 it('formats date in Russian locale', () => {16 const date = new Date('2024-01-15');17 expect(formatDate(date)).toBe('15 января 2024');18 });19});
Тестирование компонентов
▸React Native Testing Library
1npm install --save-dev @testing-library/react-native
1import { render, fireEvent, waitFor } from '@testing-library/react-native';2import LoginScreen from '../screens/LoginScreen';34describe('LoginScreen', () => {5 it('renders login form', () => {6 const { getByPlaceholderText, getByText } = render(<LoginScreen />);78 expect(getByPlaceholderText('Email')).toBeTruthy();9 expect(getByPlaceholderText('Пароль')).toBeTruthy();10 expect(getByText('Войти')).toBeTruthy();11 });1213 it('shows error on invalid credentials', async () => {14 const { getByText, getByPlaceholderText } = render(<LoginScreen />);1516 fireEvent.changeText(17 getByPlaceholderText('Email'),18 'wrong@email.com'19 );20 fireEvent.changeText(21 getByPlaceholderText('Пароль'),22 'wrongpassword'23 );24 fireEvent.press(getByText('Войти'));2526 await waitFor(() => {27 expect(getByText('Неверные данные')).toBeTruthy();28 });29 });30});
▸Мокирование нативных модулей
1// __mocks__/@react-native-async-storage/async-storage.js2export default {3 setItem: jest.fn(() => Promise.resolve()),4 getItem: jest.fn(() => Promise.resolve(null)),5 removeItem: jest.fn(() => Promise.resolve()),6 clear: jest.fn(() => Promise.resolve()),7};
Detox: E2E тестирование
Detox — это фреймворк дляEnd-to-End тестирования React Native приложений.
▸Установка
1npm install --save-dev detox2npx detox init
▸Конфигурация
1{2 "configurations": {3 "ios.debug": {4 "device": "ios.simulator",5 "app": "ios.debug"6 },7 "android.debug": {8 "device": "android.emulator",9 "app": "android.debug"10 }11 }12}
▸E2E тест
1describe('Login Flow', () => {2 beforeAll(async () => {3 await device.launchApp();4 });56 beforeEach(async () => {7 await device.reloadReactNative();8 });910 it('should login successfully', async () => {11 await element(by.id('email-input')).typeText('user@example.com');12 await element(by.id('password-input')).typeText('password123');13 await element(by.id('login-button')).tap();1415 await expect(element(by.id('home-screen'))).toBeVisible();16 });1718 it('should show validation errors', async () => {19 await element(by.id('login-button')).tap();2021 await expect(element(by.text('Email обязателен'))).toBeVisible();22 });23});
Мокирование API-запросов
1import nock from 'nock';23beforeEach(() => {4 nock('https://api.example.com')5 .get('/users/1')6 .reply(200, { id: 1, name: 'John' });7});89afterEach(() => {10 nock.cleanAll();11});
Заключение
Правильная стратегия тестирования включает unit-тесты для бизнес-логики, компонентные тесты для UI и E2E тесты для критических пользовательских сценариев. Комбинация Jest и Detox обеспечивает покрытие всех уровней приложения.