title: How use require inside a spec - grunt + karma + jasmine in node
body: <p><strong>Vague version question:</strong></p>
  
  <ul>
  <li>How can I use require inside a spec with grunt?</li>
  </ul>
  
  <p><strong>Context:</strong></p>
  
  <p>I'm working on an existent node project that has no tests yet, so I read some and realized to use karma and jasmine.</p>
  
  <p>I read some tutos (including these):</p>
  
  <ul>
  <li><a href="http://kwilson.me.uk/blog/use-karma-and-grunt-to-run-your-jasmine-tests-in-real-time/">http://kwilson.me.uk/blog/use-karma-and-grunt-to-run-your-jasmine-tests-in-real-time/</a></li>
  <li><a href="http://ahexamples.blogspot.com.br/2014/03/example-of-jasmine-karma-sonar-grunt.html">http://ahexamples.blogspot.com.br/2014/03/example-of-jasmine-karma-sonar-grunt.html</a></li>
  </ul>
  
  <p>So I'm trying to run my specs with grunt and getting this error:</p>
  
  <blockquote>
    <p>X encountered a declaration exception
        ReferenceError: Can't find variable: require in file:///(...)-spec.js (line 2) (1)</p>
  </blockquote>
  
  <p>The line is something like:</p>
  
  <pre><code>var myHelper = require(...);
  </code></pre>
  
  <p>But if I use via terminal "node-jasmine test" it works like a charm...</p>
  
  <p>My project structure:</p>
  
  <blockquote>
    <ul>
    <li>controllers/</li>
    <li>helpers/</li>
    <li>models/</li>
    <li>node_modules/</li>
    <li>resources/</li>
    <li>test/</li>
    <li>test/spec/</li>
    <li>views/</li>
    <li>app.js</li>
    <li>Gruntfile.js</li>
    <li>package.json</li>
    </ul>
  </blockquote>
  
  <p>In my spec (inside test/spec/) I use a require('../../helpers/helper.js') and that's ok for node-jasmine, but no with grunt.</p>
  
  <p>node-jasmine test:</p>
  
  <blockquote>
    <p>.....</p>
    
    <p>Finished in 0.015 seconds 5 tests, 5 assertions, 0 failures, 0 skipped</p>
  </blockquote>
  
  <p>grunt: </p>
  
  <blockquote>
    <p>Running "jasmine:pivotal" (jasmine) task Testing jasmine specs via
    PhantomJS</p>
    
    <blockquote>
      <blockquote>
        <p>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)</p>
      </blockquote>
    </blockquote>
    
    <p>1 spec in 0.005s.</p>
    
    <blockquote>
      <blockquote>
        <p>1 failures Warning: Task "jasmine:pivotal" failed. Use --force to continue.</p>
      </blockquote>
    </blockquote>
    
    <p>Aborted due to warnings.</p>
  </blockquote>
  
  <p>I have all packages installed into node_modules (nothing in dependencies in package.json) and my Gruntfile.js is:</p>
  
  <pre><code>'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');
  }
  </code></pre>
  
  <p>Thank you for your attention.</p>