На работе мы выбрали Jest в качестве предпочтительного фреймворка для модульного тестирования JS.
Ранее в некоторых проектах в качестве комбинированной тестовой среды использовались Mocha, Chai, Sinon, Karma и PhantomJS, и теперь они переносятся на Jest.
Зачем мигрировать?
На наш переход на Jest повлияло несколько факторов, в том числе:
jsdom
быстрее и легче, чемphantomjs
- Мы обнаружили неперехваченные синтаксические ошибки в тестовых наборах Mocha (например, недопустимое использование установки / разрыва), которые могут привести к «тихому» пропуску большого количества тестов, например. нет ошибки
mocha
не поддерживает тестирование снимков- Наша существующая установка включает большое количество зависимостей, которые могут оказаться более сложными для управления совместимостью версий.
- Разработка безголового браузера
phantomjs
была приостановлена в марте 2018 года
Обновление зависимостей
После установки jest
и связанных модулей наши существующие зависимости тестовой среды в package.json
-
"devDependencies": { "@babel/core": "7.2.2", "babel-plugin-istanbul": "3.0.0", "chai": "3.4.1", "chai-as-promised": "6.0.0", "chai-enzyme": "1.0.0-beta.0", "enzyme": "3.3.0", "enzyme-adapter-react-16": "1.1.1", "eslint-plugin-chai-friendly": "0.4.1", "eslint-plugin-mocha": "4.11.0", "karma": "1.0.0", "karma-babel-preprocessor": "6.0.1", "karma-chai": "0.1.0", "karma-coverage": "1.0.0", "karma-mocha": "1.0.1", "karma-mocha-reporter": "2.0.0", "karma-phantomjs-launcher": "1.0.2", "karma-sourcemap-loader": "0.3.7", "karma-webpack": "2.0.2", "mocha": "3.0.1", "sinon": "2.3.7", "sinon-chai": "2.8.0" }
теперь сокращены до -
"devDependencies": { "@babel/core": "7.2.2", "babel-jest": "23.6.0", "enzyme": "3.3.0", "enzyme-adapter-react-16": "1.1.1", "enzyme-to-json": "3.3.3", "eslint-plugin-jest": "21.15.0", "jest": "23.1.0" }
enzyme
сохранен для тестирования компонентов React с добавлением enzyme-to-json
для преобразования оболочек Enzyme в формат JSON для совместимости с тестированием моментальных снимков Jest. enzyme-to-json
также необходимо настроить в поле snapshotSerializers
в jest.config.js
-
module.exports = { projects: [ { displayName: 'tests', snapshotSerializers: ['enzyme-to-json/serializer'] } ] }
Утверждения в chai
заменены на Jest expect
. Аналогичным образом chai-as-promised
заменяется сопоставителями Jest .resolves
/ .rejects
для тестирования асинхронного кода.
Шпионы, заглушки и моки в sinon
заменены на Jest для имитации функций (API), модулей и классов.
В тестах, которые раньше выполнялись в безголовом браузере phantomjs
, теперь используется jsdom
(по умолчанию с Jest). Обратите внимание, что Jest в настоящее время поддерживает только jsdom
в качестве целевой среды. Если у вас есть тесты, которые требуют реальной среды браузера, Jest можно использовать вместе с Puppeteer или Electron для поддержки этого.
JS-компиляция с karma-babel-preprocessor
заменяется на babel-jest
.
Для покрытия кода мы продолжаем использовать istanbul
- ранее добавленное через karma-coverage
, по умолчанию с Jest.
Средство выполнения тестов karma
заменено на jest
CLI.
Перенос существующих тестов
jest-codemods
- это рекомендуемая отправная точка для автоматизации преобразования тестовых файлов из вашей существующей инфраструктуры в Jest.
Чтобы установить и запустить мод, выполните следующие команды в корневом каталоге вашего проекта -
npm i -g jest-codemods jest-codemods
затем выполните серию подсказок -
Из какой тестовой библиотеки вы хотите перейти?
Chai: Should/Expect BDD Syntax
при использовании синтаксиса Chaiexpect
илиshould
Chai: Assert Syntax
при использовании синтаксиса Chaiassert
Mocha
при использовании синтаксиса Mochaassert
Используете ли вы глобальный объект для утверждений (т. е. не требуя их)
Yes
, если ваша тестовая среда делает утверждения доступными в глобальном пространстве имен через установочный файл, например.global.expect = chai.expect
No
если выimport
илиrequire
утверждения в своих тестовых файлах
Будете ли вы использовать Jest на Node.js в качестве средства выполнения тестов?
Yes
, используйте глобальные переменные, предоставленные Jest (рекомендуется)
К каким файлам или каталогам следует применить codemods?
- Введите путь (пути) к файлу / каталогу для тестовых файлов, которые вы хотите перенести. Если у вас большой набор тестов и вам может потребоваться выполнить миграцию в несколько этапов, рекомендуется настроить таргетинг только на путь (пути) к файлу / каталогу, необходимый для этого этапа.
Теперь модификация начнется и по завершении вернет сводку -
All done. Results: 2 errors 0 unmodified 31 skipped 346 ok Time elapsed: 8.512 seconds
Проверка тестового файла (ов) покажет, что большинство утверждений теперь используют синтаксис Jest. Большой!
Однако в сводке отмечается, что несколько тестовых файлов вызвали ошибки или были пропущены -
2 errors 31 skipped
и запуск jest
приводит к множеству новых неудачных тестов…
Исправление оставшихся тестов и конфигурации вручную…
В случае нашего проекта jest-codemods
не может конвертировать тесты, используя -
sinon
sinon-chai
chai-as-promised
Переход от PhantomJS (безголовый браузер) к JSDOM (реализация JS DOM) привел к новым сбоям в тестах с использованием -
document
илиwindow
API браузера
Кроме того, в нашем проекте используется webpack
, и у Jest изначально возникают проблемы с анализом файлов, которые используют -
- Статические активы
- Модули CSS
Вот как решить эти проблемы…
sinon
/ sinon-chai
Поскольку jest-codemods
не поддерживает sinon
, вам нужно будет вручную заменить его использование, чтобы вместо этого использовать Jest API. Это хорошее изложение синтаксических различий между ними.
chai-as-promised
Может быть заменен на сопоставители Jest .resolves
/ .rejects
для тестирования асинхронного кода.
document
или window
API браузера
Тесты с использованием этих API потребуют полифиллов. Если такие API-интерфейсы браузера широко используются в вашем наборе тестов, возможно, имеет смысл добавить их в setupFiles
Jest, чтобы они были доступны для всех тестов. Например, чтобы добавить полифилл window.matchMedia
-
jest.config.js
module.exports = { projects: [ { displayName: 'tests', setupFiles: ['./jest.setup.js'] } ] }
jest.setup.js
require('matchmedia-polyfill') require('matchmedia-polyfill/matchMedia.addListener')
Однако стоит отметить, что setupFiles
будет запускаться один раз для каждого тестового файла и может увеличить время выполнения теста.
Статические ресурсы
Поскольку тесты обычно не слишком связаны со статическими активами, их можно высмеять -
jest.config.js
module.exports = { 'moduleNameMapper': { '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/mocks/fileMock.js', '\\.(css)$': '<rootDir>/mocks/styleMock.js' } }
mocks/styleMock.js
module.exports = {}
mocks/fileMock.js
module.exports = ‘test-file-stub’
Модули CSS
То же, что и выше, но используйте identity-obj-proxy
как макет -
npm i — dev identity-obj-proxy
jest.config.js
module.exports = { 'moduleNameMapper': { '\\.(scss)$': 'identity-obj-proxy' } }
Поэтапный переход
В зависимости от размера вашего набора тестов и / или процента файлов, требующих ручного исправления, вы можете выбрать миграцию набора тестов в несколько этапов, и, следовательно, вам нужно будет запускать обе среды тестирования до завершения. В jest.config.js
файлы / каталоги могут быть включены (testMatch
) или исключены (testPathIgnorePatterns
), чтобы тесты выполнялись только с использованием правильной среды тестирования.
Резюме
Jest предоставляет всестороннюю, универсальную среду тестирования, и jest-codemods
является отличной отправной точкой для переноса в нее существующего проекта.
Если вы ввели дополнительные библиотеки (например, sinon
, sinon-chai
, chai-as-promised
) в дополнение к вашей основной структуре утверждений (например, chai
или mocha
), ожидайте, что ручное обновление этих тестов, вероятно, будет составлять подавляющее большинство времени, потраченного на миграцию в целом.
Кроме того, Jest требуется небольшая конфигурация для поддержки любых форматов файлов и API браузера, которые требуются вашему проекту.