How use require inside a spec - grunt + karma + jasmine in node

Vague version question:

  • How can I use require inside a spec with grunt?

Context:

I'm working on an existent node project that has no tests yet, so I read some and realized to use karma and jasmine.

I read some tutos (including these):

So I'm trying to run my specs with grunt and getting this error:

X encountered a declaration exception ReferenceError: Can't find variable: require in file:///(...)-spec.js (line 2) (1)

The line is something like:

var myHelper = require(...);

But if I use via terminal "node-jasmine test" it works like a charm...

My project structure:

  • controllers/
  • helpers/
  • models/
  • node_modules/
  • resources/
  • test/
  • test/spec/
  • views/
  • app.js
  • Gruntfile.js
  • package.json

In my spec (inside test/spec/) I use a require('../../helpers/helper.js') and that's ok for node-jasmine, but no with grunt.

node-jasmine test:

.....

Finished in 0.015 seconds 5 tests, 5 assertions, 0 failures, 0 skipped

grunt:

Running "jasmine:pivotal" (jasmine) task Testing jasmine specs via PhantomJS

ReferenceError: Can't find variable: require at app.js:1 Service Helper Tests X encountered a declaration exception ReferenceError: Can't find variable: require in file:///(...)/test/spec/serviceHelper-spec.js (line 2) (1)

1 spec in 0.005s.

1 failures Warning: Task "jasmine:pivotal" failed. Use --force to continue.

Aborted due to warnings.

I have all packages installed into node_modules (nothing in dependencies in package.json) and my Gruntfile.js is:

'use strict';

module.exports = function(grunt) {
    var $srcFiles = 'app.js';
    var $testFiles = 'test/spec/*-spec.js';
    var $outputDir = 'test/target'
    var $junitResults = $outputDir + '/junit-test-results.xml';
    var $jasmineSpecRunner = $outputDir + '/_SpecRunner.html';
    var $coverageOutputDir = $outputDir + '/coverage';


    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        // Jasmine test
        jasmine: {
            pivotal: {
                src: $srcFiles,
                options: {
                    specs: $testFiles,
                    outfile: $jasmineSpecRunner,
                    keepRunner: 'true'  // keep SpecRunner/outfile file
                }
            }
        },

        // coverage using Karma
        karma: {
            continuous: {
                singleRun: 'true',
                browsers: [ 'PhantomJS' ]
            },

            options: {
                plugins: [
                    'karma-jasmine',
                    'karma-phantomjs-launcher',
                    'karma-junit-reporter',
                    'karma-coverage'
                ],
                frameworks: [ 'jasmine' ],
                files: [ $srcFiles, $testFiles ],
                reporters: [ 'junit', 'coverage' ],
                junitReporter: {
                  outputFile: $junitResults
                },
                preprocessors: {
                    // source files must be a literal string
                    'helpers/*.js': [ 'coverage' ]
                },
                coverageReporter: {
                    type: 'lcov',
                    dir: $coverageOutputDir
                }
            }
        },

        // export Karma coverage to SonarQube
        karma_sonar: {
            your_target: {
                // properties for SonarQube dashboard
                project: {
                    key: 'net.ahexample:ahexample-jasmine-karma-sonar',
                    name: 'Jasmine with Karma and SonarQube Example',
                    version: '0.0.1'
                }

                // sources property is set at runtime (see below)
            }
        },

        clean: [ $outputDir ]
    });


    /*
     * Task to set karma_sonar's sources property.
     * This is needed because karma (coverage) stores its results in a
     * directory whose name uses the browser's user agent info
     * (name/version and the platform name).
     * The latter may well he different to the OS name and so its needs an
     * OS to platform translator.
     * For example, OS name for Apple Mac OS X is Darwin.
     */
    grunt.registerTask('set-karma-sonar-sources-property', function() {
        var $done = this.async();
        var $phantomjs = require('karma-phantomjs-launcher/node_modules/phantomjs');
        var $spawn = require('child_process').spawn;
        var $phantomUserAgent = $spawn($phantomjs.path,
            // phantomjs script to print user agent string
            [ 'lib/phantomjs-useragent.js' ]
        );

        /*
         * Construct coverage LCOV file path from PhantomJS'
         * user agent string, then use it to set karma_sonar's
         * sources property.
         */
        $phantomUserAgent.stdout.on('data', function(msg) {
            var $useragent = require('karma/node_modules/useragent');
            var $agent = $useragent.parse(msg);
            // An example of dirName is 'PhantomJS 1.9.7 (Mac OS X)'
            var $dirName = $agent.toAgent() + ' (' + $agent.os + ')';
            var $coverageResults = $coverageOutputDir + '/' + $dirName + '/lcov.info';
            var $sonarSources = makeSonarSourceDirs($srcFiles, $coverageResults);
            var $karmaSonarConfig = 'karma_sonar';
            var $ksConfig = grunt.config($karmaSonarConfig);

            grunt.log.writeln('coverage LCOV file: ' + $coverageResults);
            $ksConfig['your_target']['sources'] = $sonarSources;
            grunt.config($karmaSonarConfig, $ksConfig);

        });

        $phantomUserAgent.on('close', function(exitCode) {
            $done();
        });


        /*
         * Create sonar source object for each directory of source file pattern.
         */
        function makeSonarSourceDirs($filesPattern, $coverageResults) {
            var $path = require('path');
            var $dirs = [];

            grunt.file.expand(
                {
                    filter: function($filePath) {
                        $dirs.push({
                            path: $path.dirname($filePath),
                            prefix: '.',    // path prefix in lcov.info
                            coverageReport: $coverageResults,
                            testReport: $junitResults
                        });
                    }
                },
                $filesPattern
            );

            return $dirs;
        }
    });


    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-karma');
    grunt.loadNpmTasks('grunt-karma-sonar');


    grunt.registerTask('test', [ 'jasmine', 'karma:continuous' ]);
    grunt.registerTask('sonar-only', [ 'set-karma-sonar-sources-property', 'karma_sonar' ]);
    grunt.registerTask('sonar', [ 'test', 'sonar-only' ]);
    grunt.registerTask('default', 'test');
}

Thank you for your attention.