Недавно мы перенесли наши тесты из различных репозиториев внешнего интерфейса из Enzyme в React Testing Library. Это был необходимый шаг, чтобы воспользоваться последними передовыми методами тестирования React и подготовиться к плавному обновлению с React 17 до 18.

Что такое библиотека тестирования React?

Библиотека тестирования React является частью проекта с открытым исходным кодом под названием Библиотека тестирования. Он основан на библиотеке тестирования DOM, добавляя API для работы с компонентами React.

Почему мы выбрали библиотеку тестирования React?

Мы выбрали React Testing Library, потому что это более легкая и простая альтернатива Enzyme. Он фокусируется на тестировании поведения ваших компонентов при взаимодействии с ними пользователя, а не на тестировании деталей внутренней реализации ваших компонентов.

Как мы перешли с Enzyme на React Testing Library

Мы успешно мигрировали, последовательно запуская две библиотеки тестов бок о бок в одном приложении, перенося тесты Enzyme в библиотеку тестирования React один за другим.

Некоторые сценарии тестирования

Некоторые из распространенных сценариев тестирования, с которыми мы столкнулись, можно разделить на три категории: синхронное, асинхронное и интерактивное тестирование.

1. Синхронное тестирование

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

const OfficePage = ({name, location}) => {
  return (
    <Fragment>
      <Text variant="title-lg">{name}</Text>
      {location && <Text variant="body-md">{location}</Text>}
    </Fragment>
  )
}

Поверхностная визуализация

фермент

const wrapper = shallow(<OfficePage name="Place Royale" location="Eindhoven" />)

expect(wrapper.find('h1').props().children).toEqual('Place Royale');
expect(wrapper.find('p').props().children).toEqual('Eindhoven');

Библиотека тестирования React

render(<OfficePage name="Place Royale" location="Eindhoven" />)

expect(screen.getByRole('heading')).toHaveTextContent('Place Royale')
expect(screen.getByText('Eindhoven')).toBeInTheDocument()

Полный рендеринг DOM

фермент

const wrapper = mount(<OfficePage name="Place Royale" location="Eindhoven" />)

expect(wrapper.find('h1').text()).toEqual('Place Royale');
expect(wrapper.find('p').text()).toEqual('Eindhoven');

Библиотека тестирования React

render(<OfficePage name="Place Royale" location="Eindhoven" />)

expect(screen.getByRole('heading')).toHaveTextContent('Place Royale')
expect(screen.getByText('Eindhoven')).toBeInTheDocument()

Поиск недостающих элементов

фермент

const wrapper = shallow(<OfficePage name="Place Royale" />)

expect(wrapper.find('h1').props().children).toEqual('Place Royale');
expect(wrapper.find('[data-testid="location"]').exists()).toBe(false);

Библиотека тестирования React

render(<OfficePage name="Place Royale" />)

expect(screen.getByRole('heading')).toHaveTextContent('Place Royale')
expect(screen.queryByText('Eindhoven')).not.toBeInTheDocument()

Обзор визуализации

Обзор запросов

Основываясь на этих Руководящих принципах, наши тесты были написаны так, чтобы максимально походить на то, как пользователи будут взаимодействовать с нашим кодом (компонентом, страницей и т. д.). Имея это в виду, вот рекомендуемый порядок приоритета:

2. Асинхронное тестирование

Здесь у нас есть компонент часто задаваемых вопросов (FAQ), который изначально отображает состояние загрузки, а в useEffect мы извлекаем данные, а состояние загрузки и данных обновляется. Однако, если данных нет, мы отображаем пустое состояние.

const CancelFaqs = () => {
  const [data, setData] = useState(null)
  const [isLoading, setLoading] = useState(true)

  useEffect(() => { /* fetch + setLoading + setData */ }, [])

  if (isLoading) { /* render "Loading" */ }

  if (data.length < 1) { /* render empty state */ }

  render (
    <div className="container">
      <h4>FAQ heading</h4>
      <ul>
        {data.map((faq) => ( <li className="faq-list"> ... </li> ))}
      </ul>
    </div>
  )
}

Состояние загрузки

фермент

const wrapper = shallow(<CancelFaqs />)

expect(wrapper.find('p').text()).toEqual('Loading...');

Библиотека тестирования React

render(<CancelFaqs />)

expect(screen.getByText('Loading...')).toBeInTheDocument();

Пустое состояние

фермент

const wrapper = shallow(<CancelFaqs />)

expect(wrapper.html()).toEqual(null);

Библиотека тестирования React

render(<CancelFaqs />)

expect(await screen.findByText('No Faq found.')).toBeInTheDocument();

Состояние данных

фермент

const wrapper = Shallow(<CancelFaqs />)

expect(wrapper.find('h4').text()).toEqual('FAQ heading');

Библиотека тестирования React

render(<CancelFaqs />)

await waitFor(() => expect(screen.getByRole('heading')).toBeInTheDocument());

Типы запросов в библиотеке тестирования React

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

Здесь у нас есть компонент поиска статей для поиска статей. Он отображает компонент ввода для ввода, а также компонент кнопки для нажатия при поиске.

const ArticleSearch = () => {
  const [query, setQuery] = useState('')
  const [articles, setArticles] = useState(null)
  const search = () => { /* return fetch Promise */ }

  render (
    <div className="container">
      <Input label="Name" value={query} onChange={/* setQuery */} />
      <Button onClick={search}>Search</Button>
      {/* render loading or empty or articles data */}
    </div>
  )
}

Ферментный тест

const wrapper = shallow(<ArticleSearch />)
const searchSpy = jest.spyOn(wrapper.instance(), 'search');

wrapper.find('Input').simulate('change', { target: { value: 'Test
query' } });
wrapper.find('Button').simulate('click');
// Assert the article list here

Библиотека тестирования React (Взаимодействия пользователей)

render(<ArticleSearch />)

await userEvent.type(screen.getByLabelText('Name'))
await userEvent.click(screen.getByRole('button', {name: /search/i))
// Assert the article list here

Ресурсы

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

@testing-library/jest-dom

@testing-library/user-event

Запросы

Отладка запросов

Запросы на появление и исчезновение

Взаимодействия пользователей

Миграция с Enzyme на документы библиотеки тестирования React

Я надеюсь, что вы нашли эту статью полезной, и желаю вам всего наилучшего при переходе на React Testing Library.

Наши технические команды в de Bijenkorf всегда ищут талантливых инженеров-программистов, которые присоединятся к нашим замечательным командам. Дополнительную информацию см. на нашей странице вакансий инженеров.