Тестирование снимков

Если вы фронтенд-разработчик, используете React и хотите быть уверены, что компоненты, написанные в вашем проекте, работают так, как должны работать, вы, скорее всего, знаете о тестировании моментальных снимков компонентов React.

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

Как это работает:

  1. Вы создаете тест, в котором компонент отрисовывается с помощью некоторых свойств. Выглядит это так:
import React from 'react';
import renderer from 'react-test-renderer';

import Button from 'components/button';

test('Button', () => {
  const tree = renderer.create(
    <Button
      text="Click me"
    />
  );
  expect(tree).toMatchSnapshot();
});
  1. При первом запуске этого теста Jest создает файл моментального снимка, который содержит строковую JSX-разметку компонента.
  2. При последующих запусках тестов Jest просто сравнит визуализированный результат с предыдущим снимком. Если они совпадают, тест будет пройден. Если они не совпадают, то либо исполнитель тестов обнаружил ошибку в вашем коде, которую следует исправить, либо реализация изменилась и снимок необходимо обновить.

Более подробное описание можно прочитать в официальной документации, но это основные моменты.

Эта проблема

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

Предположим, у нас есть компонент Button с тремя свойствами: text, className, isDisabled. Вот так может выглядеть тестовый файл:

test('Button Case #1', () => {
  const tree = renderer.create(
    <Button
      text="Click me"
      className=""
      isDisabled={false}
    />
  );
   expect(tree).toMatchSnapshot();
});
test('Button Case #2', () => {
  const tree = renderer.create(
    <Button
      text="Click me"
      className="buttonClassName"
      isDisabled={false}
    />
  );
  expect(tree).toMatchSnapshot();
});
test('Button Case #3', () => {
  const tree = renderer.create(
    <Button
      text=""
      className=""
      isDisabled={true}
    />
  );
  expect(tree).toMatchSnapshot();
});
// and so on...

Писать этот файл достаточно скучно. И вот всего 3 случая, когда их количество может составить 3³ = 27.

Разве это не трата времени, чтобы сделать это вручную? Можно ли это автоматизировать и как?

Использование TypeScript с React

TypeScript - это язык, который позволяет вам использовать типы в вашем коде и может быть скомпилирован в простой JavaScript. Компилятор TypeScript проверяет любые ошибки типа в коде и сообщает вам, если что-то не так.

Вы также можете использовать его с React. Вы можете установить типы для свойств компонента React. Для компонента Button, который мы обсуждали выше, это может выглядеть так:

interface IButtonProps {
    text: string;
    className?: string;
    isDisabled?: boolean;
}

Но подождите ... Если у нас есть типы для свойств, значения для каждого из них сильно ограничены. Это означает, что они могут быть рандомизированы автоматически! Бинго! 🎉

Автоматическое создание снимков тестов

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

Для этого и была создана библиотека Snappify. Он берет ваши компоненты React, написанные на TypeScript, и генерирует для них файлы с тестами.

Вам нужно только запустить их! ✨

Как работает Snappify

Установить Snappify глобально:

npm install -g snappify

Запустите Snappify внутри папки проекта с настроенным шаблоном глобуса файлов компонентов React и именем корневой папки для сгенерированных тестов:

snappify components/**/*.tsx --testsRoot=tests

Он создаст каталог с именем tests внутри текущей папки.

Внутри этого каталога он будет генерировать файлы с тестами на основе снимков для каждого из компонентов из файлов, соответствующих шаблону components/**/*.tsx.

Количество сгенерированных тестовых случаев

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

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

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

Подводя итоги ⬇️

Исходный код Snappify находится на GitHub: https://github.com/denisraslov/snappify.

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