Simple functional tests for gulp tasks

In the last post, I presented a simple setup to compile ES2015 JS code. Gulp was used there as a task runner and in this article I'll show you a simple way to black-box-test your gulp tasks.

The gulp task

The first step I suggest to do, is to structure your gulp tasks/functions in a modular way, if not already done. For example, my task to compile ES2015 code and bundle the modules could look like this:

export function compileToES2015(files, options) {
  return () => {
    return gulp.src(files)
      .pipe($.rollup({
        sourceMap: true
      }))
      .pipe($.babel())
      .on('error', $.util.log)
      .pipe($.rename(options.filename))
      .pipe($.sourcemaps.write('.'))
      .pipe(gulp.dest(options.destination));
  };
}

Note that this function should be as generic as possible to make it testable and reusable. By using export we make sure that we can test this functionality in the test later.
Firstly, it reads the file and bundles the dependencies with rollup.js. After that, the code will be transformed with babel (with es2015 preset) and renamed. Lastly, the file and its sourcemap will be written to a new location.

To use this function in a gulp task, you just need to give it the required parameters:

gulp.task('compileToES2015', compileToES2015('assets/js/index.js', {
  basePath: 'assets/js/',
  filename: 'bundle.js',
  destination: 'assets/dist/scripts'
}));

The test

Now we're able to write the actual test file. I'll use mocha with jasmine as the testing framework for this case, but this is just personal preference.

Import the functions

The goal is to run the gulp task with fixture input and compare the actual written output with the expectations. In this example we will test if the files are bundled as modules.
Step number one is to make the exported functions from the gulpfile available in the test file.

import * as gulpfile from '../../gulpfile.babel';

Because my gulptests are located in ./tests/gulp I need to go two levels up to get the gulpfile in the root path of the project.
Now it's possible to execute the function above by calling gulpfile. compileToES2015().

Set up the test input

In the next step the input and output directories are set as constant variables:

const inputDir = path.join(__dirname, '/input/');
const outputDir = path.join(__dirname, '/output/');

Within the input directory exist two files which should be the test input.
The main test file (input/index.js) looks like this:

import { testConstant } from 'test-dependency';
(() => {
  console.log(testConstant);
})();

and the test dependency (input/test-dependency.js) is as simple as this:

export const testConstant = 'TESTCASE';

The test task

In the function, which describes the tests for the module bundling, the test gulp task 'compileToES2015' is placed and configured with the input data shown above. To actually test this task, a pseudotask 'test' is created, which has the 'compileToES2015'-task as a dependency. Thus we make sure that 'test' is only called once the compilation task has finished. Within the test task we can put in all of the assertions we need, for example, if the bundled file exists and if the dependency's content is present.
After all assertions are set, a done()-call has to be placed to the tell the testing framework that this test is done ¯_(ツ)_/¯.

describe('Test gulp tasks', function() {
  // increase default timeout in case assert operations take too long (i/o usage)
  this.timeout(4000);

  describe('Enable ES2015 modules', function() {
    gulp.task('compileToES2015', gulpfile.compileToES2015(inputDir + 'index.js', {
      basePath: inputDir,
      filename: 'index.js',
      destination: outputDir
    }));

    it('should bundle ES2015 into a single file', function(done) {
      // pseudo-task
      gulp.task('test', ['compileToES2015'], () => {
        expect(fs.existsSync(outputDir + 'index.js')).to.be(true);
        expect(fs.readFileSync(outputDir + 'index.js').toString('utf8'))
          .to.contain('testConstant');
        done();
      });
      gulp.start('test');
    });
  });
});

Run the test

In order to finally run the tests, a simple npm script can suffice, which transforms the ES2015 code in your test and executes it with mocha.

{
  "scripts": {
    "test": "mocha --compilers js:babel-core/register --recursive tests/gulp/*.js"
  }
}

Other approaches

While this testing approach works for my gulp tasks so far, I'm pretty sure that there are cleaner und more elegant ways of doing such tests. On the internet I didn't find many good resources on this topic, but if you have suggestions, criticism or any other feedback feel free to drop me a comment below :)

Comments on this post


comments powered by Disqus