Для одного нашего front-end проекта я решил мигрировать на Grunt. Grunt — отличный таск-раннер для клиентских проектов на основе node.js/npm. Раньше у нас была некоторая инфраструктура для сборок и тестов. Поэтому весь наш код нужно перенести в инфраструктуру Grunt. К счастью, на http://gruntjs.com/plugins есть много крутых плагинов для Grunt. Плагин для Grunt — это просто модуль npm.

Наши юнит-тесты используют QUnit. Запускаем их в браузере и под PhantomJS с помощью cmd-файла.

Существует официальный плагин Grunt для запуска тестов qunit под PhantomJS — grunt-contrib-qunit. Этот плагин использует другой npm-модуль для запуска PhantomJS — grunt-lib-phantomjs. А этот в свою очередь использует модуль phantomjs.

Модуль «phantomjs» — это просто оболочка, которая загружает исполняемый файл PhantomJS при установке модуля. Во время выполнения модуль возвращает путь к исполняемому файлу фантома (phantomjs.exe), который нам нужно запустить самостоятельно. Именно так ведет себя grunt-lib-phantomjs:

var binPath = require(‘phantomjs’).path;
return grunt.util.spawn({
 cmd: binPath,
 args: args
 }

Поэтому я начал использовать плагин grunt-contrib-qunit. После этого я установил все необходимые модули и настроил задачи Grunt в своем Gruntfile.js, и все мои модульные тесты начали проходить на моей машине. Прохладный. Затем я зафиксировал весь код своего проекта с папкой node_modules в нашу систему контроля версий (TFS) и начал сборку на нашем сервере сборки (TeamCity). Кстати, есть плагин для TeamCity для запуска задач Grunt.
К сожалению, сборка завершилась со следующей ошибкой:
Тестирование http://localhost:9002/tests-runner.html Фатальная ошибка: spawn ENOENT

Такая ошибка означает, что не удалось запустить процесс phantomjs.exe. Я добавляю дополнительные журналы в grunt-contrib-qunit\node_modules\grunt-lib-phantom\js\lib\phantomjs.js перед выполнением метода grunt.util.spawn и вижу путь, который передается в него. Это был путь на моей локальной машине!

Почему?

Оказалось, что модуль grunt-lib-phantomjs строит АБСОЛЮТНЫЙ путь к исполняемому файлу phantomjs при установке (!) и жестко кодирует его в js-файл, из которого он возвращается во время выполнения (как ' поле модуля пути). Невероятный.

Получается, что мы не можем поместить папку «node_modules» в VCS, чтобы разрешить запуск задач на сервере сборки или других машинах без установки всех пакетов npm. Хранение папки «node_modules» в VCS может быть очень удобным для создания проектов на сервере сборки, поскольку он обычно не имеет доступа к Интернету. Мы действительно могли бы создать приватный репозиторий для всех пакетов npm и устанавливать их при каждой сборке на build-server, но зачем нам это делать?

Итак, я пришел к выводу, что модуль phantomjs не подходит. для меня. И поэтому я не могу использовать grunt-lib-phantomjs. И поэтому я не могу использовать grunt-contrib-qunit.

Поэтому мне пришлось написать наш плагин для Grunt для запуска тестов qunit под PhantomJS без прямой ссылки на npm-модуль phatomjs. Встречайте хрюк-крок-кунит.

Grunt-croc-qunit — это объединение официальных плагинов grunt-contrib-qunit и grunt-lib-phantomjs с удаленной зависимостью от phantomjs. Также он имеет небольшое улучшение производительности для внедренного скрипта bridge.js (подробнее см. https://github.com/gruntjs/grunt-contrib-qunit/issues/44).

Плагин grunt-croc-qunit имеет ту же задачу qunit с одним дополнительным параметром — phantomPath. Это путь к исполняемому файлу phantomjs. См. примеры использования на https://github.com/CrocInc/grunt-croc-qunit#usage-examples.

Для установки PhantomJS вы можете продолжать использовать npm-модуль «phantomjs», но это будет зависимость вашего проекта (devDependency), а не плагина grunt-croc-qunit. С помощью grunt-croc-qunit вы можете легко зафиксировать папку node_modules в VCS и/или поделиться ею между машинами. Все будет продолжать работать.