mocha-gherkin-ui
Version:
A Mocha BDD Gherking UI, introducing selective test skip on fail and tags!
178 lines (143 loc) • 5.35 kB
JavaScript
const Mocha = require('mocha');
const Suite = require('mocha/lib/suite');
const GherkinTest = require('./lib/GherkinTest');
const GherkinSuite = require('./lib/GherkinSuite');
const programParams = require('minimist')(process.argv.slice(2));
Mocha.interfaces['mocha-gherkin-ui'] = module.exports = mochaCakes;
const _commasToArray = (str) => {
if(str) {
return str.split(',').map(s=>s&&s.trim()).filter(s=>!!s)
}
return undefined;
}
const ourParams = {
/**
* Three options: [default|absolute|moderate]
* [original]: Leaves out default mocha test execution, no changes respect to what you are used to.
* [absolute]: Once 'Given'|'When'|'Then'|'And'|'But' fails, all subsequent steps within an scenario will be skipped.
* [moderate]: When a step 'Given'|'When'|'Then' or a sub-step like 'And'|'But' fails, it will skip only from subsequent main step, all substeps following a main step will be executed (Recommended).
* Default: moderate
*/
mochaGherkinUiSkipMode: /^(original|absolute|moderate)$/.exec(programParams.mochaGherkinUiSkipMode) ? programParams.mochaGherkinUiSkipMode : 'moderate',
/**
* Comma separated filters, for the given Tags on Scenarios or Features.
*/
mochaGherkinUiFilterTags: _commasToArray(programParams.mochaGherkinUiFilterTags)
};
function mochaCakes(suite) {
var suites = [suite];
suite.on('pre-require', function (context, file, mocha) {
var common = require('mocha/lib/interfaces/common')(suites, context, mocha);
context.run = mocha.options.delay && common.runWithSuite(suite);
var wrapperCreator = createWrapper(file, suites, context, mocha);
var testTypeCreator = createTestType(file, suites, mocha);
context.after = common.after;
context.afterEach = common.afterEach;
context.before = common.before;
context.beforeEach = common.beforeEach;
context.Scenario = wrapperCreator('Scenario');
context.Feature = wrapperCreator('Feature');
context.Tags = tagsFunctionCreator(context);
context.Given = testTypeCreator('Given');
context.When = testTypeCreator('When');
context.Then = testTypeCreator('Then');
context.And = testTypeCreator('And');
context.But = testTypeCreator('But');
// lower-case aliases
context.tags = context.Tags;
context.scenario = context.Scenario;
context.feature = context.Feature;
context.given = context.Given;
context.when = context.When;
context.then = context.Then;
context.and = context.And;
context.but = context.But;
});
}
function tagsFunctionCreator(context) {
//Tag function.
return (...tags)=>{
// Decorator for a GherkinSuite definition, adding tags filtering.
const tagsWrapper = (fn) => {
let tagFunction = (...args) => {
return fn(...args, tags);
};
tagFunction.skip = (...args) => {
return fn.skip(...args);
};
tagFunction.only = (...args) => {
return fn.only(...args, args);
}
return tagFunction;
}
//Return only Suites, tagging should only apply to Suites.
return {
Scenario: tagsWrapper(context.Scenario),
Feature: tagsWrapper(context.Feature),
}
};
}
/**
* Helper functions
**/
function createTestType(file, suites, mocha) {
return function testTypeCreator(type) {
function testType(title, fn) {
let suite = suites[0];
if (suite.pending) fn = null;
let test = new GherkinTest(title, fn, type, file, ourParams);
suite.addTest(test);
return test;
}
testType.skip = function skip(title) {
return testType(title);
};
testType.only = function only(title, fn) {
var test = testType(title, fn);
mocha.grep(test.fullTitle());
return test;
};
return testType;
};
}
function createWrapper(file, suites, context, mocha) {
return function wrapperCreator(type) {
function createLabel(title) {
return type ? `${type}: ${title}` : title;
}
// Didn't like the fact that i had to modify the number of parameters, but apparently there is no other way to reenable a skipped test after the steps encapsulated here are executed.
function wrapper(title, fn, tags) {
//var suite = Suite.create(suites[0], createLabel(title));
let suite = new GherkinSuite(title, suites[0],type, ourParams);
if(ourParams.mochaGherkinUiFilterTags) {
//We skip all the suites, so only tags matching are executed.
suite.pending = true;
//We need to to this here, mocha handles the state at this point an apparently there is no way to skip a Suite, as i could see in https://github.com/mochajs/mocha/issues/332
suite.filterByTags(tags);
}
if (!suite.pending) {
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
}
return suite;
}
wrapper.skip = function skip(title, fn) {
var suite = Suite.create(suites[0], createLabel(title));
suite.pending = true;
suite.manuallySkipped = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
};
wrapper.only = function only(title, fn) {
var suite = wrapper(title, fn);
mocha.grep(suite.fullTitle());
return suite;
};
return wrapper;
};
}
;