Last Updated: February 25, 2016
·
2.607K
· nevi

Grunt/Watch/Mocha only run on my changed file

Here is a little snippet to reach on of the lazy people dream :D

First we need a grunt watch task.

grunt.initConfig({
    watch: {
      automatic: {
        files: ['src/**/*.js']
      }
});

There is the worker:

MochaTester = {

      mochaOptions: {
        reporter: 'dot'
      },

      Mocha: require('mocha'),
      path: require('path'),
      fs: require('fs'),

      registerToWatchTask: function(target, mochaOptions){
        var tester = Object.create(this);

        tester.target = target;
        tester.mochaOptions = mochaOptions ? 
                                              mochaOptions : 
                                              this.mochaOptions;

        grunt.event.on("watch", tester.listener.bind(tester));
        return tester;
      },

      listener: function(action, filepath, target)
      {
        if (!this.isListenedEvent(action, target)) {
          return;
        }

        var testFile = this.getTestFilePath(filepath);

        if (filepath != testFile) {
          this.clearCache(filepath);
        }

        this.clearCache(testFile);
        this.createMochaWithFile(testFile);

        setTimeout(this.run.bind(this), 500);
      },

      isListenedEvent: function(action, target)
      {
        return action == 'changed' && target == this.target;
      },

      // */myFile.js
      // */test/myFileTest.js
      // either my file or his test file changed get the test file
      getTestFilePath: function(filepath)
      {
        var isTestFile = filepath.indexOf('Test.js') != -1,
              testFile = !isTestFile ? 
                             filepath.replace(/(.+)\/(\w+)\.js/, '/test/Test.js') : 
                             filepath;

        if (!isTestFile && !this.path.existsSync(filepath)) {
          throw new Error('\nTestFile not found:\n'+filepath)
        }

        return testFile;
      },

      // require cache all time, so second time zero test will execute
      // if does not clear from the cache
      clearCache: function(filepath)
      {
        require.cache[require.resolve('./'+filepath)] = undefined;
      },

      createMochaWithFile: function(filepath)
      {
        this.mocha = new this.Mocha(this.mochaOptions);
        this.mocha.addFile(filepath);
      },

      run: function()
      {
        this.mocha.run(function(failureCount){
          if (failureCount) {
            grunt.log.error('falling: ' + failureCount)
          } else {
            grunt.log.ok('OK');
          }
        });
      }
    }

And something familiar: need to register the task:)

MochaTester.registerToWatchTask('automatic');

3 Responses
Add your response

Good work, you saved me after a couple of hours trying to do that!

over 1 year ago ·

Hey you should publish that as a grunt-contrib package.

over 1 year ago ·

I'm glad to help you.

That would be nice, but first I need to figure out how can I do it with an extendable approach.

Like I run this way my phpunit tests too :D

over 1 year ago ·

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside