Снапшот-тестирование маршрутов

Снапшот-тестирование маршрутов позволяет проверять корректность отображения компонентов, связанных с конкретными путями в приложении, без необходимости вручную переходить по маршрутам в браузере. В сочетании с React Testing Library и Jest оно обеспечивает надёжный способ контроля за визуальным и функциональным состоянием маршрутов.


Настройка тестовой среды

Для начала необходимо установить зависимости:

npm install --save-dev @testing-library/react @testing-library/jest-dom jest
npm install react-router-dom

Импортируются основные утилиты:

import { render, screen } from '@testing-library/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';

Использование MemoryRouter вместо обычного BrowserRouter позволяет создавать виртуальную историю маршрутов, что идеально подходит для тестов.


Создание базового маршрута

Предположим, есть структура маршрутов:

function Home() {
  return <h1>Главная страница</h1>;
}

function About() {
  return <h1>О приложении</h1>;
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  );
}

Для тестирования важен корректный рендер компонента в зависимости от переданного пути.


Снапшот-тест для главного маршрута

import renderer from 'react-test-renderer';

test('рендерит главную страницу корректно', () => {
  const tree = renderer
    .create(
      <MemoryRouter initialEntries={['/']}>
        <App />
      </MemoryRouter>
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

Пояснения:

  • initialEntries задаёт текущий путь в памяти.
  • toJSON() преобразует компонент в структуру, удобную для снапшота.
  • toMatchSnapshot() сохраняет снимок дерева компонентов и сравнивает его при последующих запусках теста.

Проверка маршрутов с параметрами

React Router позволяет использовать динамические сегменты URL, например /user/:id. Для тестирования:

function User({ id }) {
  return <h1>Пользователь {id}</h1>;
}

function App() {
  return (
    <Routes>
      <Route path="/user/:id" element={<UserWrapper />} />
    </Routes>
  );
}

function UserWrapper() {
  const { id } = useParams();
  return <User id={id} />;
}

Снапшот-тест:

test('рендерит страницу пользователя', () => {
  const tree = renderer
    .create(
      <MemoryRouter initialEntries={['/user/42']}>
        <App />
      </MemoryRouter>
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

Использование useParams() позволяет динамически получать параметры маршрута, а initialEntries имитирует путь с конкретным значением.


Тестирование навигации между маршрутами

Для проверки переходов можно использовать компонент Link и библиотеку user-event:

import { Link } from 'react-router-dom';
import userEvent from '@testing-library/user-event';

function Nav() {
  return (
    <>
      <Link to="/">Главная</Link>
      <Link to="/about">О приложении</Link>
    </>
  );
}

test('переход по ссылкам корректен', async () => {
  render(
    <MemoryRouter initialEntries={['/']}>
      <Nav />
      <App />
    </MemoryRouter>
  );

  await userEvent.click(screen.getByText('О приложении'));
  expect(screen.getByText('О приложении')).toBeInTheDocument();
});

В данном случае проверяется не только визуальный вид, но и функциональность перехода между маршрутами.


Интеграция с вложенными маршрутами

Вложенные маршруты часто используют Outlet:

function Dashboard() {
  return (
    <div>
      <h1>Панель управления</h1>
      <Outlet />
    </div>
  );
}

function Stats() {
  return <h2>Статистика</h2>;
}

function App() {
  return (
    <Routes>
      <Route path="/dashboard" element={<Dashboard />}>
        <Route path="stats" element={<Stats />} />
      </Route>
    </Routes>
  );
}

Тестирование вложенного маршрута:

test('рендер вложенного маршрута', () => {
  const tree = renderer
    .create(
      <MemoryRouter initialEntries={['/dashboard/stats']}>
        <App />
      </MemoryRouter>
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

В этом случае снапшот включает сразу родительский и дочерний компоненты, что позволяет контролировать корректность рендеринга вложенной структуры.


Полезные рекомендации

  • Использовать MemoryRouter для всех тестов маршрутов.
  • Хранить снапшоты в контролируемой директории, чтобы легко отслеживать изменения.
  • Для компонентов с динамическими данными комбинировать снапшот-тестирование с проверками через screen.getByText или screen.getByRole.
  • Избегать снапшотов для больших страниц с часто меняющимся содержимым — предпочтительно тестировать ключевые элементы интерфейса.

Снапшот-тестирование маршрутов позволяет создавать надёжные, повторяемые тесты для приложений на React с использованием React Router, гарантируя, что при изменениях структуры или содержимого маршрутов визуальное отображение компонентов остаётся ожидаемым.