Симуляция навигации

Enzyme предоставляет мощные инструменты для тестирования компонентов React, в том числе и для симуляции навигации. Этот процесс может включать в себя тестирование поведения компонентов, которые изменяют состояние приложения или осуществляют переходы между различными страницами, например, при использовании react-router.

Для полноценного тестирования навигации важно уметь имитировать действия пользователя, такие как клики по ссылкам, и отслеживать изменения, которые происходят в результате этих действий. В Enzyme для этих целей используется метод .simulate(), а также можно интегрировать тестирование с библиотеками маршрутизации, такими как react-router-dom.

Тестирование с использованием react-router

При работе с приложениями, использующими маршрутизацию, важно удостовериться, что компоненты корректно взаимодействуют с роутером и что навигация осуществляется так, как задумано. В Enzyme тестирование компонентов с роутером потребует обертывания компонента в соответствующий провайдер маршрутизации, например, MemoryRouter из библиотеки react-router-dom.

import { shallow, mount } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('должен переходить на правильный маршрут при клике на ссылку', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/']}>
        <MyComponent />
      </MemoryRouter>
    );

    // Имитируем клик по ссылке
    wrapper.find('a').simulate('click', { button: 0 });

    // Проверяем, что навигация произошла
    expect(wrapper.find('MyComponent').prop('location').pathname).toBe('/new-path');
  });
});

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

Симуляция кликов и переходов

Для проверки навигации важно научиться симулировать пользовательские действия, такие как клики по элементам интерфейса. Метод .simulate() позволяет имитировать события на компонентах, например, на ссылках или кнопках. После этого можно проверять изменения в состоянии приложения, которые должны быть вызваны навигацией.

import { shallow } from 'enzyme';
import { Link } from 'react-router-dom';

describe('Тестирование навигации', () => {
  it('при клике на ссылку происходит переход на новый маршрут', () => {
    const wrapper = shallow(<Link to="/new-page">Перейти на новую страницу</Link>);
    const link = wrapper.find('a');

    // Имитируем клик по ссылке
    link.simulate('click', { button: 0 });

    // Ожидаем, что произойдёт переход
    expect(window.location.pathname).toBe('/new-page');
  });
});

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

Обработка асинхронных операций

В случае, если навигация зависит от асинхронных операций (например, загрузка данных перед рендером нового маршрута), важно правильно синхронизировать тесты с этими операциями. Для этого Enzyme предоставляет инструменты для ожидания завершения асинхронных операций, такие как wrapper.update() и методы работы с промисами.

import { mount } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';

describe('Тестирование асинхронной навигации', () => {
  it('должен корректно перейти после загрузки данных', async () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/']}>
        <MyComponent />
      </MemoryRouter>
    );

    // Имитируем загрузку данных, которая инициирует переход
    await wrapper.instance().loadData();

    // Ожидаем, что маршрут изменится после завершения асинхронной операции
    await wrapper.update();
    expect(wrapper.find('MyComponent').prop('location').pathname).toBe('/loaded-page');
  });
});

В данном примере после выполнения асинхронной операции с методом loadData() компонента происходит навигация на новый маршрут. Мы используем wrapper.update(), чтобы дождаться обновления компонента и проверяем новый путь.

Использование Enzyme с компонентами, зависящими от навигации

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

import { mount } from 'enzyme';
import { MemoryRouter, Route } from 'react-router-dom';
import MyComponent from './MyComponent';

describe('Рендер компонента в зависимости от маршрута', () => {
  it('должен отрендерить правильный компонент в зависимости от маршрута', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/page-1']}>
        <Route path="/page-1" component={() => <MyComponent />} />
      </MemoryRouter>
    );

    // Проверяем, что компонент MyComponent был отрендерен
    expect(wrapper.find(MyComponent)).toHaveLength(1);
  });
});

Этот тест проверяет, что компонент корректно рендерится в зависимости от маршрута. Здесь мы оборачиваем компонент в MemoryRouter и используем Route для указания маршрута, на который должен реагировать компонент.

Тестирование с историей

Использование истории маршрутов (history) помогает отслеживать переходы между страницами. Для того чтобы тестировать изменения в истории, можно использовать MemoryRouter, который позволяет настраивать начальную историю.

import { mount } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';

describe('Тестирование изменения истории', () => {
  it('должен изменять историю при переходе на новый маршрут', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/']}>
        <MyComponent />
      </MemoryRouter>
    );

    // Имитируем клик по элементу, который меняет маршрут
    wrapper.find('a').simulate('click', { button: 0 });

    // Проверяем, что история изменилась
    expect(wrapper.find('MyComponent').prop('location').pathname).toBe('/new-path');
  });
});

Тест проверяет, что при переходе по ссылке происходит правильное изменение маршрута и обновление истории.

Использование Enzyme с хуками

Если компонент использует хуки, например, для работы с состоянием маршрута (useLocation, useHistory), важно убедиться, что тесты корректно симулируют использование этих хуков. Для этого также используется обёртка MemoryRouter.

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

describe('Тестирование хуков с маршрутизацией', () => {
  it('должен использовать хуки для доступа к информации о маршруте', () => {
    render(
      <MemoryRouter initialEntries={['/page-1']}>
        <Route path="/page-1" component={MyComponent} />
      </MemoryRouter>
    );

    // Проверяем, что компонент использует информацию о маршруте
    expect(screen.getByText('/page-1')).toBeInTheDocument();
  });
});

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

Заключение

Симуляция навигации в Enzyme играет ключевую роль в тестировании маршрутизируемых React-приложений. Использование MemoryRouter, simulate() и других методов позволяет эффективно моделировать пользовательское поведение, проверять корректность переходов и взаимодействие компонентов с роутером.