Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting grunt karma to run one unit test

I was wondering if anyone has got grunt karma to run just one spec that is changed on watch. This is my config below. The problem is that the line grunt.config('karma.unit.options.files', filepath); doesn't seem to be doing anything as all the specs still get run however foo does get output before the karma:unit:run gets fired.

grunt.initConfig({
    karma: {
        unit: {
            configFile: 'karma.conf.js',
            background: true,
            singleRun: false,
            options: {
                files: allFilesArray
            }
        }
    },
    watch: {
        options: {
            spawn: false,
            livereload: true
        },
        karma: {
            files: ['js/spec/**/*.spec.js', 'js/src/**/*.js'],
            tasks: ['karma:unit:run']
        }
    }
})

grunt.event.on('watch', function (action, filepath){
    console.log('foo');
    grunt.config('karma.unit.options.files', filepath);
});

Is there anyone out there who has achieved running one spec in the terminal on file change? We have thousands of tests so it is starting to get slow.

Thanks, Alex

like image 687
alexrogers Avatar asked Jan 23 '15 11:01

alexrogers


People also ask

What does it mean to set the Singlerun attribute to true located in the Karma Conf js file?

CLI: --single-run , --no-single-run. Description: Continuous Integration mode. If true , Karma will start and capture all configured browsers, run tests and then exit with an exit code of 0 or 1 depending on whether all tests passed or any tests failed.


2 Answers

I got this to work. Basically, you use watch with an event handler to dynamically change the karma config whenever a file changes. Here's the rundown:

My Grunt config has two karma tasks: "all" and "one". "all" runs all of them, and "one" only runs a single file which it does not know beforehand.

grunt.initConfig({
  // ...
  karma: {
    all: {
      configFile: 'karma.conf.js',
      browsers: ['PhantomJS'],
      singleRun: true,
      options: {
        files: [
          'bower_components/jquery/dist/jquery.js', // dependencies
          'src/js/**/*.js', // js source files
          'src/js/**/*.spec.js' // unit test files
        ]
      }
    },
    one: {
      configFile: 'karma.conf.js',
      browsers: ['PhantomJS'],
      singleRun: true,
      files: [
        {src: 'bower_components/jquery/dist/jquery.js'}, // dependencies
        {src: ['src/js/**/*.js','!src/js/**/*.spec.js']} // source files
        // (exclude the unit test files)
        // watchEventListener will add the unit test file to run
      ]
    }
  },
  // ...
});

And then later in my gruntfile, I add a listener for watch events. This listener updates the karma:one task and adds the unit test file. We keep a copy of the original files array, or else our additions would persist and accumulate through the lifetime of the watch task.

// when a unit test changes, execute only it
var original_karmaOne_files = grunt.config.get('karma.one.files'); // keep the original files array
grunt.event.on('watch', function watchEventListener(action, filepath, target){

  // this handler handles ALL watch changes. Try to filter out ones from other watch tasks
  if (target == 'js_spec') handleJSHintSpec();

  // ---------------------
  function handleJSHintSpec() {
    if (action == 'deleted') return; // we don't need to run any tests when a file is deleted
    // this will probably fail if a watch task is triggered with multiple files at once
    // dynamically change the config
    grunt.config.set('karma.one.files', [].concat(original_karmaOne_files, [{src: filepath}]));
  }
});

And here is my gruntfile's watch task:

watch: {
  // ...
  // when js spec files change,
  // lint them
  // run unit tests
  js_spec: {
    options: {
      interrupt: true
    },
    files: 'src/js/**/*.spec.js',
    tasks: ['jshint:js_spec', 'karma:one']
  },
  // ...
}

My karma.conf.js file is pretty default, but its files array is empty. Actually, I commented it out, so the property is undefined.

// list of files / patterns to load in the browser
//files: [], // specified in the gruntfile
like image 108
Matthias Avatar answered Sep 27 '22 22:09

Matthias


TL; DR: Use karma:unit everywhere instead of karma:unit:run and use grunt.event.on('watch', function(){}); to edit the karma config to only include the test files you want to run.

I have this working, but it might not be what you want. I'm starting the server up again every time I save a file. Further explanation is below. Here is some of the config:

    watch: {
        tests: {
            files: 'tests/**/*.js',
            tasks: ['karma:unit']
        },
        tsChanged: {
            files: config.tsFiles,
            tasks: [
                'ts',
                'karma:unit'
            ]
        }
    }

    grunt.event.on('watch', function(action, filepath){
        grunt.config(['karma', 'unit', 'files'], [{
            src: [
                path/to/your/source/files,
                path/to/your/test/file,
            ]
        }]);
    });

It seems to me that karma loads all of the app files and the test files into the browser whenever it starts the server. In your case, that would be when you enter "grunt karma:unit:start watch" into the command line. So here, I used "grunt watch" and just added a "karma:unit" to the process. Then I caught the save event and updated the karma config before it started up the server.

Hope this helps.

like image 26
Kyle Merritt Avatar answered Sep 27 '22 22:09

Kyle Merritt