Тестирование Link и NavLink

В современном веб-разработке часто используются маршрутизаторы, такие как react-router, для навигации по приложениям. В этом контексте компоненты Link и NavLink играют ключевую роль в управлении переходами между различными страницами. Тестирование этих компонентов с использованием Enzyme важно для обеспечения корректной работы навигации в приложении.

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

  1. Проверка рендеринга компонента

    Простой тест, который проверяет, что компонент Link рендерится без ошибок и имеет нужные атрибуты:

    import { shallow } from 'enzyme';
    import { Link } from 'react-router-dom';
    
    test('Компонент Link рендерится корректно', () => {
      const wrapper = shallow(<Link to="/home">Home</Link>);
      expect(wrapper.exists()).toBe(true);
      expect(wrapper.prop('to')).toBe('/home');
    });
  2. Проверка кликабельности

    Для проверки функциональности ссылки важно убедиться, что клик по компоненту вызывает нужное поведение. Для этого можно использовать Enzyme вместе с моками и проверками:

    import { mount } from 'enzyme';
    import { Link } from 'react-router-dom';
    import { MemoryRouter } from 'react-router-dom';
    
    test('Клик по компоненту Link приводит к изменению маршрута', () => {
      const wrapper = mount(
        <MemoryRouter initialEntries={['/']}>
          <Link to="/home">Home</Link>
        </MemoryRouter>
      );
    
      wrapper.find('a').simulate('click', { button: 0 });
      expect(wrapper.find(Link).prop('to')).toBe('/home');
    });

NavLink из react-router-dom является расширением компонента Link, предоставляя дополнительные функции для стилизации активных ссылок. Он имеет пропс activeClassName, который позволяет применить класс CSS к ссылке, когда она активна, а также isActive, который позволяет вручную определить, является ли ссылка активной.

  1. Проверка активного класса

    Один из важных аспектов тестирования NavLink — это проверка, что активный маршрут правильно выделяется, например, путем применения CSS класса. Для этого можно проверить наличие активного класса в зависимости от маршрута.

    import { mount } from 'enzyme';
    import { NavLink } from 'react-router-dom';
    import { MemoryRouter } from 'react-router-dom';
    
    test('NavLink применяет активный класс', () => {
      const wrapper = mount(
        <MemoryRouter initialEntries={['/home']}>
          <NavLink to="/home" activeClassName="active">
            Home
          </NavLink>
          <NavLink to="/about" activeClassName="active">
            About
          </NavLink>
        </MemoryRouter>
      );
    
      expect(wrapper.find(NavLink).at(0).hasClass('active')).toBe(true);
      expect(wrapper.find(NavLink).at(1).hasClass('active')).toBe(false);
    });
  2. Проверка активного состояния через isActive

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

    import { mount } from 'enzyme';
    import { NavLink } from 'react-router-dom';
    import { MemoryRouter } from 'react-router-dom';
    
    test('NavLink с пропсом isActive работает корректно', () => {
      const wrapper = mount(
        <MemoryRouter initialEntries={['/home']}>
          <NavLink
            to="/home"
            isActive={(match, location) => location.pathname === '/home'}
            activeClassName="active"
          >
            Home
          </NavLink>
        </MemoryRouter>
      );
    
      expect(wrapper.find(NavLink).hasClass('active')).toBe(true);
    });
  3. Проверка с несколькими NavLink

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

    import { mount } from 'enzyme';
    import { NavLink } from 'react-router-dom';
    import { MemoryRouter } from 'react-router-dom';
    
    test('Только одна ссылка активна из нескольких', () => {
      const wrapper = mount(
        <MemoryRouter initialEntries={['/home']}>
          <NavLink to="/home" activeClassName="active">Home</NavLink>
          <NavLink to="/about" activeClassName="active">About</NavLink>
        </MemoryRouter>
      );
    
      const activeLinks = wrapper.find('.active');
      expect(activeLinks.length).toBe(1);
      expect(activeLinks.text()).toBe('Home');
    });

Мокирование контекста маршрута

В некоторых случаях компоненты Link и NavLink используют контекст маршрута, который предоставляется с помощью компонента BrowserRouter или MemoryRouter. Для тестирования этих компонентов важно использовать соответствующий контейнер маршрута, чтобы убедиться, что компоненты правильно обрабатывают состояние маршрутов.

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

test('Link работает в контексте MemoryRouter', () => {
  const wrapper = mount(
    <MemoryRouter initialEntries={['/']}>
      <Link to="/home">Home</Link>
    </MemoryRouter>
  );

  wrapper.find('a').simulate('click', { button: 0 });
  expect(wrapper.find(Link).prop('to')).toBe('/home');
});

Тестирование с использованием фрагментов и вложенных маршрутов

Компоненты Link и NavLink могут быть вложены в другие компоненты, и важно проверять, что они корректно работают даже в более сложных структурах. Например, можно тестировать их в составе навигационного меню с вложенными маршрутами.

import { mount } from 'enzyme';
import { NavLink, Route } from 'react-router-dom';
import { MemoryRouter } from 'react-router-dom';

test('NavLink работает с вложенными маршрутами', () => {
  const wrapper = mount(
    <MemoryRouter initialEntries={['/home']}>
      <NavLink to="/home" activeClassName="active">Home</NavLink>
      <Route path="/home" render={() => <div>Home Page</div>} />
    </MemoryRouter>
  );

  expect(wrapper.find(NavLink).hasClass('active')).toBe(true);
  expect(wrapper.find('div').text()).toBe('Home Page');
});

Заключение

Тестирование компонентов Link и NavLink с использованием Enzyme требует внимания к различным аспектам: рендеринг, проверка маршрутов, активные классы и взаимодействие с контекстом маршрутов. Правильное тестирование этих компонентов обеспечивает стабильность навигации и улучшает качество приложения.