Три вывода из трех лет работы с RTL.

Последние три года я ежедневно работаю с React-Testing-Library. За это время мой подход к тестированию с помощью RTL изменился, и я научился писать более качественные и устойчивые тесты. Меня часто просят помочь коллегам в написании тестов и отладить их неудачные тесты, и я часто вижу, как они повторяют одни и те же ошибки снова и снова.

Я подумал, что было бы интересно высказать некоторые мысли о том, как лучше писать тесты с помощью React Testing Library. Вот что я нашел.

1. Используйте getByLabelText, чтобы сделать тесты более устойчивыми и простыми в отладке.

Одна из самых неприятных вещей в работе с хорошо протестированными веб-приложениями - это когда наши тесты терпят неудачу с бесполезным результатом.

Допустим, у нас есть компонент React, который показывает пользователю их баланс. Это могло выглядеть примерно так.

Мы могли бы протестировать наш компонент, используя screen.getByText и ища в документе значение 100.00.

Один из способов проверить это - написать что-то вроде этого.

Проблема с этим подходом в том, что он создает хрупкий тест, который легко сломать. Что, если нас попросят добавить компонент «Промежуточный итог» на страницу, на которой также отображается 100,00 долларов США? Что, если 100 долларов США по какой-либо причине изменится на 120 долларов?

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

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

FAIL  src/App.test.tsx
  ✕ renders balances correctly (15 ms)
● renders balances correctly
TestingLibraryElementError: Unable to find an element with the text: /100.00/. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Чтобы сделать наш тест более устойчивым, а наш компонент более доступным, мы можем реорганизовать его, чтобы использовать атрибут aria-labelledby для установления связи между нашей меткой (Итого) и его объектом (100,00 долларов США ).

Затем мы меняем обновление нашего теста следующим образом. Обратите внимание, как мы используем getByLabelText и assertiontoHaveTextContent.

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

Когда я запускаю тест, я ясно вижу из сообщения об ошибке, что не так.

FAIL  src/App.test.tsx
  ✕ renders balances correctly (14 ms)
● renders balances correctly
expect(element).toHaveTextContent()
Expected element to have text content:
      $100.00
    Received:
      -

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

2. Ознакомьтесь с предупреждением о том, что все готово.

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

Warning: An update to Balances inside a test was not wrapped in act(...).

Но почему мы получаем это предупреждение? Обычно это происходит потому, что мы не ожидаем должным образом какой-либо асинхронной активности в нашем приложении (например, ввода данных пользователем, вызова API и т. Д.).

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

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

Тест может выглядеть примерно так.

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

3. Станьте лучше в отладке.

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

Один из приемов здесь - установитьDEBUG_PRINT_LIMIT на большее значение, чем 7000 по умолчанию. Это, по крайней мере, позволит вам увидеть весь вывод DOM в вашей консоли.

Один из хороших способов ограничить объем вывода DOM в наших тестах - использовать внутри. Таким образом, мы можем утверждать, что текст отображается в определенной части DOM, а не во всем объекте экрана.

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

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

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

Есть ли у вас другие советы или рекомендации по написанию более эффективных тестов с использованием библиотеки тестирования React? Сообщите нам об этом в комментариях.