Сказка о приключениях, амбициях и модульных тестах JavaScript

Фреймворк для модульного тестирования Facebook Jest имеет много преимуществ: он упрощает написание тестов для компонентов React с помощью функции тестирования моментальных снимков, он очень быстро запускает тесты посредством параллельного выполнения тестов, и его очень легко настроить.

Вдохновленный выступлением Криса Пойера на JSConf.eu 2017, я решил преодолеть свое беспокойство по поводу того, что полагаться на еще один инструмент от большой компании из Menlo Park, и попробовать его.

Когда я начал свой текущий проект Polly в начале этого года, это беспокойство заставило меня положиться на проверенную технологию, которую мы использовали годами: Mocha и различные инструменты, которые обычно используются в сочетании с ней.

Как перенести существующую базу кода на Jest? Давайте наденем солнцезащитные шлемы, застегнем прочные ботинки и приготовимся отправиться в великое неизведанное!

Подготовка к путешествию

Начать работу с Jest легко - опыт разработчика очень важен для Facebook, и это видно. Jest следует парадигме соглашение важнее конфигурации и требует от вас очень мало настроек. Установка jest npm package, изменение команды test в package.json нашего проекта на просто jest и создание теста Hello World заняли считанные минуты, почти секунды.

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

Вы можете запустить код ES6, ES7, ES8 или ESWTF, просто установив другой модуль npm, babel-jest. Я сделал это, Jest нашел мой существующий .babelrc, и я был готов к работе - никаких дополнительных настроек или магии веб-пакетов не было.

Отличное тестирование JavaScript! 👍🏻

… Особенно если вы сравните это с командой, которую мы использовали для запуска наших тестов Mocha:

Отправляясь в путешествие

Наша существующая тестовая установка содержала:

  • 88 тестовых наборов Мокко с 904 тестами
  • Enzyme, утилиты для тестирования компонентов React
  • Sinon.JS, который предоставляет автономные тестовые шпионы, заглушки и моки.
  • Chai, тестовая библиотека утверждений для Mocha с расширениями chai-as-promise, sinon-chai и chai -enerme
  • Mockery, инструмент для имитации зависимостей, импортируемых тестируемыми модулями.
  • Jsdom, реализация DOM на JavaScript для тестирования манипуляций с DOM.
  • Измерение покрытия кода с Стамбул / Нью-Йорк

Jest обещает заменить все это одним фреймворком - слишком хорошо, чтобы быть правдой? Я очень хотел начать свое путешествие, чтобы узнать это для себя!

Модификация кода

Facebook предоставляет codemods, который позволяет нам автоматически переносить наши существующие тесты в Jest: jest-codemods.

Codemods - это небольшие программы, которые помогают автоматизировать изменения в вашей кодовой базе. Думайте о них как о поиске и замене стероидов. Их выполняет инструмент Facebook jscodeshift. (источник: jest-codemods / README.md)

Это было быстро и легко, за исключением того, что 122 из 213 тестовых файлов были пропущены… 🤔

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

Самым очевидным является замена утверждений Chai.should на функцию expect Jest, а равный метод Chai - на toBe Jest:

Как мы также видим в этом примере, Jest поддерживает синтаксис describe / it точно так же, как и Mocha.

Через пустыню

Приключение с переименованием

Я провел тесты и посмотрел, какие из них Jest может без проблем выполнить правильно:

Что? Тестов не найдено?

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

Я выполнил быструю команду оболочки:

Все файлы были красиво переименованы, но почему Jest теперь выдавал мне эту странную ошибку, с которой никакие поиски в Google не могли помочь?

Наша тестовая установка была полностью разрушена, потому что я забыл исключить node_modules из переименования и заменил Jest runTest.js на run.test.js . Ой! rm -rf node_modules && npm install в помощь.

Борьба с Sass

Я был сейчас в точке, где прошло более наших тестов:

Откуда взялась SyntaxError?

Мы использовали загрузчик Sass webpack для стилизации наших компонентов React с синтаксически потрясающими таблицами стилей. Jest не запускает тесты через webpack, как и наша старая установка Mocha.

Мы использовали инструмент под названием css-modules-require-hook, чтобы наши стилизованные компоненты React работали в наших модульных тестах. Выглядело это примерно так:

Приведенный выше файл setup.js загружается перед запуском тестов с использованием параметра командной строки compilers Mocha:

Как добиться того же с помощью Jest?

Вместо того, чтобы пытаться интегрировать css-modules-require-hook в нашу тестовую установку Jest, я решил действовать «способом Jest».

Вы можете добавить конфигурацию для Jest в файл package.json вашего проекта. Я использовал это, чтобы добавить параметр moduleNameMapper:

Это говорит Jest: «Когда вы найдете оператор импорта для файла, имя которого заканчивается на .scss, не волнуйтесь, просто импортируйте вместо него мой модуль styleMock.js. ”

Файл-макет - это просто пустой модуль:

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

С другой стороны, это позволяет тестам Jest работать намного быстрее, чем наши старые тесты Mocha, которые фактически компилировали код Sass.

Как заставить ESLint играть хорошо

Одна вещь, которая меня беспокоила, заключалась в том, что моя IDE испещрила мой код красными волнистыми линиями подчеркивания, потому что она не понимала оператор Jest expect.

Мы используем ESLint для проверки синтаксиса кода, поэтому я изменил нашу настройку на использование Jest ESLint plugin. Я установил плагин с помощью npm install -D eslint-plugin-jest и добавил его в наш файл .eslintrc:

Когда кодить становится сложно…

Итак, мы разобрались с модулями Sass и ESLint, это что-то значит, верно? Нет - еще больше неудачных тестов:

Мне удалось только получить разные сообщения об ошибках. Ну хоть какой-то прогресс…

toBe () или not.to.be (), вот в чем вопрос

Я продолжил исследование ошибок. В Jest утверждения записываются с помощью операторов ожидать, например:

(пример взят из документации Jest API)

С другой стороны, мы использовали библиотеку утверждений Chai для написания нашего тестового кода таким понятным образом:

Jest-codemods отлично работают в таком простом случае, как этот, но не работают при более сложном использовании Chai, таком как этот - код до:

… И после

Запуск этого теста дал мне эту ошибку:

Ручное исправление здесь заключалось в замене оператора expect на два отдельных, каждый из которых использовал метод утверждения toBe:

В этот момент у моего искателя приключений упало сердце: исправить вручную 552 неверных утверждения? Это займет несколько дней кропотливого труда… 😓

Чай и Шут - Партия, заключенная на небесах

Проблемы были еще хуже с теми тестами, в которых использовались плагины Chai, а мы использовали их в большом количестве: chai-as-обещано, chai -etherme и sinon-chai.

Я не хотел избавляться от этих плагинов, по крайней мере, сразу, и вместо этого искал способы заставить Chai работать с Jest.

Эта прекрасная статья Рубена Остинга дала мне новую надежду:



Основная идея состоит в том, чтобы иметь установочный файл, который загружается до выполнения тестов, и обезьяний патч Jest ожидает с сопоставлениями с ожиданием Чай, например:

(вся заслуга в этом примере кода принадлежит Рубену Остинге)

Чтобы Jest выполнил сценарий setup.js перед тестами, я добавил его в наш package.json (в дополнение к moduleNameMapper, который у меня был используется для работы Sass):

Глядь - работает!

Нет коротышек

При таком подходе есть одно предостережение: вам нужно обойтись без сокращенных функций стрелок в утверждениях - это не сработает:

Утверждения Chai не возвращают undefined, и если стрелочная функция написана сокращенно, она возвращает значение, возвращаемое утверждением, что не нравится Jest:

Не элегантное исправление - не использовать сокращенные функции стрелок:

Если у вас, уважаемый читатель, есть более элегантное решение, я буду рад услышать от вас в комментариях. 😍

Продолжение следует…

Достигнет ли наш отважный исследователь своей цели? Настройтесь в следующий раз, чтобы прочитать о самой большой проблеме, с которой я столкнулся в нашем проекте миграции: об использовании способа Jest имитировать зависимости модулей, что очень круто, но сильно отличается от того, что мы использовали раньше.