Jest — это исполнитель тестов, что означает, что он знает, где искать тестовые файлы, как запускать несколько тестов параллельно и объединять их результаты, а также как отображать полезные сообщения об ошибках, когда в вашей реализации что-то идет не так. код.

Помимо своей функциональности в качестве средства запуска тестов, Jest также полезен своей уникальной функцией моментального тестирования. Подробнее об этом позже.

Enzyme, с другой стороны, представляет собой библиотеку вспомогательных функций, которые особенно полезны для тестирования компонентов React. Без Enzyme тестирование компонентов React будет значительно сложнее, потому что вам придется реализовывать свои собственные функции для «поверхностного рендеринга» компонента (в отличие от фактического монтирования его в DOM) и, например, самостоятельно искать в них определенные элементы.

Короче:

  • Jest — это средство запуска тестов, и оно предоставляет классную функцию, называемую тестированием моментальных снимков.
  • Enzyme предоставляет полезные вспомогательные функции для тестирования компонентов React (например, shallow())

Шуточные заметки с поля

  • describe() используется для группировки нескольких релевантных тестов вместе.
  • it() является псевдонимом test()
  • expect() используется для утверждения
  • eg. expect(wrapper.find('.header').text()).toEqual('hello');
  • Совершенно нормально вкладывать describe в другой. Как сказано в этой статье: описание предназначено для объяснения условий, тогда как его предназначено для объяснения ожидаемого результата.
  • Мы используем уникальную функцию Jest тестирование моментальных снимков, чтобы легко отслеживать нежелательные изменения в наших представлениях React.
  • Jest автоматически создаст новый снимок и сравнит его со старым снимком всякий раз, когда в тестовом коде вызывается toMatchSnapshot().
  • снимки — это простые текстовые файлы с расширением .snap, которые содержат разметку, сгенерированную при рендеринге компонента React.
  • снимки автоматически генерируются и сохраняются в папке __snapshots__
  • эта функция имеет больше вариантов использования, чем сохранение замороженного снимка визуализированного представления React, но нам придется изучить ее на более позднем этапе.

Ферментные заметки с поля

  • shallow() будет поверхностно отображать компонент React без DOM. Он отображает только сам компонент, а его дочерние компоненты (например, <ChildComponent>) будут просто отображаться как <ChildComponent> вместо составляющих его HTML-элементов. Это сделано для того, чтобы тесты для одного компонента не ломались, если его дочерние компоненты были изменены — это хорошо, потому что тесты можно делать изолированно
  • Если вы сомневаетесь, используйте поверхностный рендеринг для тестирования компонентов React. Используйте только mount() или render(), когда вы действительно не можете протестировать только с поверхностным рендерингом.

пакет.json

Вот исчерпывающий список пакетов npm и конфигураций Jest, которые нам понадобились для совместного использования комбинации Jest/Enzyme:

// package.json
...
  "devDependencies": {
    "enzyme": "^3.2.0", 
    "enzyme-adapter-react-15": "^1.0.5",
    "enzyme-to-json": "^3.3.0",  // to seralise Enzyme output for use with Jest snapshots
    "eslint-plugin-jest": "^21.5.0",  // linter plugin for Jest
    "jest": "^22.0.4",
    "jest-cli": "^22.0.4",
    "react-test-renderer": "^15.6.2",  // dependency of enzyme-adapter-react
  },

  "jest": {
    "moduleDirectories": [
      "client",
      "node_modules"
    ],
    "moduleNameMapper": {  // specify mock file for import/require statements that match these
      ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|scss|css)$": "/private/jest/fileMock.js",
      "imports?.*": "/private/jest/fileMock.js"
    },
    "moduleFileExtensions": ["js", "json", "jsx", "node"],
    "setupFiles": [  // make available global variables like lodash, jQuery, Backbone, etc.
      "/private/jest/setup.js"
    ],
    "snapshotSerializers": [  // configure to use enzyme-to-json as serializer for snapshots
      "enzyme-to-json/serializer"
    ]
  }
...

Как запускать тесты

Это наша настройка скриптов в package.json:

...
  "scripts": {
    "test": "jest",
    "test:up": "jest -u",
    "test:watch": "jest --watch"
  },
...

Как только «скрипты» в package.json будут настроены, как указано выше, для запуска существующих тестов:

$ npm run test

Как использовать снимки Jest

С помощью Jest моментальные снимки визуализированных компонентов React автоматически восстанавливаются при каждом вызове .toMatchSnapshot(), существующем в ваших тестах.

Например, если tab-simple.test.jsx имеет 10 блоков expect(...), каждый из которых выполняет вызов .toMatchSnapshot(), будет создано 10 снимков в 1 файле в __snapshots__/tab-simple.test.jsx.snap.

Вот пример простого текстового файла tab-simple.test.jsx.snap:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`TabSimple component should render exactly as last snapshot 1`] = `
  • Вкладка 1
`;

Создать новый снимок

Для моментальных снимков, которые создаются впервые (т. е. есть новый тест с использованием .toMatchSnapshot()), вам следует:

  1. Откройте сгенерированный файл .snap
  2. Найдите часть, содержащую новую разметку снимка.
  3. Убедитесь, что разметка соответствует вашим ожиданиям и будет отображаться в вашем компоненте.
  4. Если это не так, узнайте, почему, устраните проблему и обновите снимок (см. ниже).

Обновить снимки

Иногда вам нужно будет заменить старый снимок новым (например, когда вы меняете пользовательский интерфейс внешнего интерфейса или когда ваш только что созданный снимок показывает вам неожиданную разметку). Чтобы обновить соответствующий снимок, внимательно выполните следующие действия:

  1. Поймите серьезность ситуации. Снимки полезны только для оповещения вас об изменении отображаемого вывода компонента React. Вы сами определяете, ожидается изменение или нет, и что с этим делать, если оно неожиданное.
  2. Используйте выходные данные терминала из Jest, чтобы определить часть снимка, которая теперь отличается
  3. Проверьте, ожидается ли это изменение (возможно, потому, что вы изменили пользовательский интерфейс или базовую реализацию).
  • если это ожидается, то обновите свой снимок (см. ниже команду для этого)
  • если изменение неожиданное, исправьте свою реализацию и перезапустите тест, пока он снова не пройдет!
// update ALL snapshots
$ npm run test:up

// or if in watch mode, hit 'u' (only after confirming changes are EXPECTED)
$ npm run test:watch

Как писать тесты во время разработки

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

Поместите тестовые файлы в ближайшую папку с тестами

Поскольку Jest запускает тесты, он автоматически находит все файлы внутри папок __tests__ и использует их в качестве исходных файлов всякий раз, когда мы запускаем npm run test.

Мы должны хранить __tests__ файлов рядом с реализацией. Например, тестовый файл для client/components/component-x.view.jsx должен находиться в client/components/__tests__/component-x.test.jsx. Визуально:

client/
|--- components/
|  |--- __tests__/
|  |   |---> component-x.test.jsx
|  |---> component-x.view.jsx
|

Примечание. По соглашению тестовые файлы должны называться с суффиксом .test..

Использовать режим часов

Режим просмотра — очень полезная функция, которая работает аналогично другим командам с флагом --watch. В режиме наблюдения Jest будет наблюдать за изменениями в любых файлах в __tests__ папках и автоматически перезапускать все тесты для нас. Он даже оптимизирован для запуска только файлов с изменениями с момента вашего последнего коммита git!

Чтобы запустить Jest в режиме часов:

$ npm run test:watch

Используйте макет, чтобы вернуть фиктивную функцию/объект

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

  • Поддерживайте изоляцию в тестируемом компоненте, удаляя внешние зависимости. Это предотвращает потенциальный сбой наших тестов, например, из-за ошибки в зависимости (см. Этот ответ SO)
  • Предотвращение ошибок импорта/требования ES6 или AMD с внешними библиотеками (например, у меня были ошибки при импорте библиотеки Blueimp jQuery file upload, и ее насмешка решила проблему)

Начните с «опишите» и «это первое».

Заимствуя из разработки через тестирование (TDD) и предыдущих воплощений, вы должны по умолчанию писать тестовый код до написания кода реализации, если вы создаете новый компонент React.

Воспользуйтесь преимуществами структуры тестов, которая заключается в написании блоков describe(...), за которыми следуют несколько вложенных блоков it(...). Описывая свои ожидания от компонента, который вы собираетесь создать, до написания кода тестирования или реализации, вы уточняете требования.

Вот пример написания общих блоков describe и it перед написанием любого тестового кода:

describe('EmailBuilder component', () => {
    it('always renders a "Subject Line" label and input');
    it('always renders 4 Recommender draggable components');
    it('always renders 5 Basic draggable components');
    it('should not render Sandbox component by default');

    describe('when used in Campaign (One-off Campaign)', () => {
        it('should render exactly as last snapshot');
        it('always renders at least 1 variant tab');
        it('always renders a "Preview Mode" button');
        it('should not render a Receipt draggable component');
    });
});

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

Полезные ресурсы:

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

Первоначально опубликовано на сайте Nick Ang.