JavaRush /Курсы /Модуль 3: React /Тестирование пользовательского интерфейса с React Native ...

Тестирование пользовательского интерфейса с React Native Testing Library

Модуль 3: React
25 уровень , 9 лекция
Открыта

Основные принципы React Native Testing Library

Если Jest — это ваш основной инструмент для тестирования логики и базовых функций, то React Native Testing Library — это про взаимодействие пользователя с интерфейсом. Эта библиотека помогает тестировать ваши компоненты так же, как это делал бы настоящий пользователь: ввод данных, нажатия кнопок, прокрутка списков и прочее.

React Native Testing Library следует принципу "тестировать так, как видит пользователь". Это значит:

  • Мы имитируем поведение настоящего пользователя, фокусируясь на том, как компонент "выглядит" и "взаимодействует".
  • Вместо поиска элементов по внутренним идентификаторам (id), мы ориентируемся на текст, метки или доступность (accessibilityLabel). Таким образом, тесты становятся более "человеко-ориентированными".

Почему это важно? Потому что, если интерфейс перестанет работать для пользователя, его не спасёт идеальная логика в вашем Redux или идеальная оптимизация рендеров. UI — это первое, что видят и с чем взаимодействуют пользователи.

Установка React Native Testing Library

Прежде чем начать проверку пользовательского интерфейса, нужно установить библиотеку.

Обычно в современных проектах уже настроен Jest, поэтому установка RNTL минимальна:

npm install --save-dev @testing-library/react-native

Кроме того, убедитесь, что у вас установлены следующие зависимости:

npm install --save-dev jest @types/jest react-test-renderer

Теперь всё готово! Время писать тесты.

Создание тестов для пользовательского интерфейса

Давайте создадим базовый тест, проверяющий, что наш компонент корректно рендерится. Допустим, у нас есть простое приложение с компонентом LoginScreen, который содержит:

  • Поле ввода имени пользователя.
  • Поле ввода пароля.
  • Кнопку для входа.

Файл компонента LoginScreen.tsx:

import React from 'react';
import { View, Text, TextInput, Button } from 'react-native';

export const LoginScreen = () => {
  return (
    <View>
      <Text>Логин</Text>
      <TextInput placeholder="Введите имя пользователя" />
      <TextInput placeholder="Введите пароль" secureTextEntry />
      <Button title="Войти" onPress={() => {}} />
    </View>
  );
};

Теперь добавим тест, который проверяет, что все элементы отображаются корректно:

Файл LoginScreen.test.tsx:

import React from 'react';
import { render } from '@testing-library/react-native';
import { LoginScreen } from './LoginScreen';

test('LoginScreen рендерится правильно', () => {
  const { getByText, getByPlaceholderText } = render(<LoginScreen />);

  // Проверяем текстовые элементы
  expect(getByText('Логин')).toBeTruthy();

  // Проверяем поля ввода
  expect(getByPlaceholderText('Введите имя пользователя')).toBeTruthy();
  expect(getByPlaceholderText('Введите пароль')).toBeTruthy();

  // Проверяем кнопку
  expect(getByText('Войти')).toBeTruthy();
});

Этот тест:

  1. Использует функцию render от React Native Testing Library, чтобы отобразить компонент в тестовом окружении.
  2. Проверяет наличие текста и плейсхолдеров через функции getByText и getByPlaceholderText.

Тестирование взаимодействий

Теперь добавим обработчик для кнопки и протестируем взаимодействие. Изменим наш компонент:

import React, { useState } from 'react';
import { View, Text, TextInput, Button, Alert } from 'react-native';

export const LoginScreen = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = () => {
    if (username === 'admin' && password === 'password') {
      Alert.alert('Добро пожаловать!');
    } else {
      Alert.alert('Ошибка: Неверные данные');
    }
  };

  return (
    <View>
      <Text>Логин</Text>
      <TextInput
        placeholder="Введите имя пользователя"
        value={username}
        onChangeText={text => setUsername(text)}
      />
      <TextInput
        placeholder="Введите пароль"
        value={password}
        secureTextEntry
        onChangeText={text => setPassword(text)}
      />
      <Button title="Войти" onPress={handleLogin} />
    </View>
  );
};

Теперь тестируем, что при вводе правильных данных отображается нужное сообщение:

Файл LoginScreen.test.tsx:

import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import { LoginScreen } from './LoginScreen';

test('При вводе верных данных отображается сообщение об успешном входе', () => {
  const { getByPlaceholderText, getByText } = render(<LoginScreen />);

  // Заполняем поля ввода
  fireEvent.changeText(getByPlaceholderText('Введите имя пользователя'), 'admin');
  fireEvent.changeText(getByPlaceholderText('Введите пароль'), 'password');

  // Нажимаем кнопку "Войти"
  fireEvent.press(getByText('Войти'));

  // Проверяем, что всплывает правильное сообщение
  expect(Alert.alert).toHaveBeenCalledWith('Добро пожаловать!');
});

test('При вводе неверных данных отображается ошибка', () => {
  const { getByPlaceholderText, getByText } = render(<LoginScreen />);

  // Заполняем поля ввода
  fireEvent.changeText(getByPlaceholderText('Введите имя пользователя'), 'wrongUser');
  fireEvent.changeText(getByPlaceholderText('Введите пароль'), 'wrongPassword');

  // Нажимаем кнопку "Войти"
  fireEvent.press(getByText('Войти'));

  // Проверяем, что всплывает сообщение об ошибке
  expect(Alert.alert).toHaveBeenCalledWith('Ошибка: Неверные данные');
});

В этих тестах:

  • fireEvent.changeText используется для симуляции ввода текста в поля.
  • fireEvent.press симулирует нажатие на кнопку.
  • Мы проверяем, чтобы Alert.alert был вызван с правильным сообщением.

📝 Примечание: чтобы протестировать Alert.alert, нужно замокать его в тестах. В Jest это делается так:

jest.spyOn(global, 'Alert').mockImplementation(() => {});

Отладка и улучшение тестов

Писать тесты легко, пока всё идёт по плану, но могут, конечно, возникать трудности:

  • Ваш тест может зависнуть, если элемент интерфейса не находится. Используйте debug() от RNTL, чтобы увидеть текущий "рендер" компонента и понять, что происходит.
  • Если тесты выполняются медленно, проверьте, нет ли лишних рендеров компонентов.
  • Разделяйте крупные тесты на несколько небольших, чтобы упростить отладку.

Пример использования debug():

const { debug } = render(<LoginScreen />);
debug(); // Покажет текущую структуру рендера, доступную для тестирования

Почему это важно для реальных проектов

Тестирование UI помогает в первую очередь избежать регрессий: когда вы изменяете функциональность, это часто ломает существующий интерфейс. Автоматические тесты интерфейса дают уверенность, что хотя бы базовые сценарии работы (логин, ввод данных, переход между экранами) остаются функциональными.

В реальных проектах React Native Testing Library часто используется для обеспечения качества пользовательского опыта.

Теперь у вас есть всё необходимое, чтобы начать тестировать пользовательский интерфейс вашего мобильного приложения с помощью React Native Testing Library. Удачи и помните: тесты — это не лишняя работа, это ваша страховка на будущее!

2
Задача
Модуль 3: React, 25 уровень, 9 лекция
Недоступна
Обработка пользовательского ввода
Обработка пользовательского ввода
3
Опрос
Тестирование компонентов с Jest, 25 уровень, 9 лекция
Недоступен
Тестирование компонентов с Jest
Тестирование компонентов с Jest
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ