Testing Generators

Read on to learn more about the testing helpers Banana add to ease the pain of unit testing a generator.

The examples below assume you use pytest. The global concept should apply easily to your unit testing framework of choice.

Organizing your tests

TODO It is important to keep your tests simple and easily editable.

Usually the best way to organize your tests is to separate each generator and sub-generator into its own ... block. Then, add a ... block for each option your generator accept. And then, use an ... block for each assertion (or related assertion).

In code, you should end up with a structure similar to this:

example 
});

Test helpers

Banana provide test helpers methods. They’re contained inside the Banana module.

TODO

You can check the full helpers API here.

The most useful method when unit testing a generator is TODO

Sometimes you may want to construct a test scenario for the generator to run with existing contents in the target directory. In which case, you could invoke inTmpDir() with a callback function, like so:

var path = require('path');
var fs = require('fs-extra');

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    // `dir` is the path to the new temporary directory
    fs.copySync(path.join(__dirname, '../templates/common'), dir)
  })
  .withPrompts({ coffee: false })
  .then(function () {
    assert.file('common/file.txt');
  });

You can also perform asynchronous task in your callback:

var path = require('path');
var fs = require('fs-extra');

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    var done = this.async(); // `this` is the RunContext object.
    fs.copy(path.join(__dirname, '../templates/common'), dir, done);
  })
  .withPrompts({ coffee: false });

The run Promise will resolve with the directory that the generator was run in. This can be useful if you want to use a temporary directory that the generator was run in:

helpers.run(path.join(__dirname, '../app'))
  .inTmpDir(function (dir) {
    var done = this.async(); // `this` is the RunContext object.
    fs.copy(path.join(__dirname, '../templates/common'), dir, done);
  })
  .withPrompts({ coffee: false })
  .then(function (dir) {
    // assert something about the stuff in `dir`
  });

If your generator calls composeWith(), you may want to mock those dependent generators. Using #withGenerators(), pass in array of arrays that use #createDummyGenerator() as the first item and a namespace for the mocked generator as a second item:

var deps = [
  [helpers.createDummyGenerator(), 'karma:app']
];
return helpers.run(path.join(__dirname, '../app')).withGenerators(deps);

If you hate promises, you can use the 'ready', 'error', and 'end' Events emitted:

helpers.run(path.join(__dirname, '../app'))
  .on('error', function (error) {
    console.log('Oh Noes!', error);
  })
  .on('ready', function (generator) {
    // This is called right before `generator.run()` is called
  })
  .on('end', done);

Assertions helpers

TODO

Banana extends the native assert module with generator related assertions helpers. You can see the full list of assertions helpers on the yeoman-assert repository.

Require the assertion helpers:

var assert = require('yeoman-assert');

Assert files exists

assert.file(['Gruntfile.js', test_router.pyr.py', 'app/views/main.js']);

assert.noFile() assert the contrary.

Assert a file content

assert.fileContent('controllers/user.js', /App\.UserController = Ember\.ObjectController\.extend/);

assert.noFileContent() assert the contrary.