Created
February 26, 2015 15:38
-
-
Save MatthewBarker/770114dd534aae3642d4 to your computer and use it in GitHub Desktop.
Provides simplified Gherkin style syntax for Mocha tests by extending the functions in the standard 'BDD' interface.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global define, Mocha*/ | |
/** | |
Provides simplified Gherkin style syntax for Mocha tests by extending the functions in the standard 'BDD' interface. | |
** See {@link http://mochajs.org/#bdd-interface} for Mocha documentation. | |
** Feature and Scenario act as a wrapper for 'describe' | |
** Given, When, Then, But & And act as a wrapper for 'it' | |
** Feature, Scenario, Given, When, Then, But & And functions are capitalised as otherwise some of them would conflict with CoffeeScript keywords. | |
@module bdd-feature | |
@author Matt Barker | |
@requires mocha | |
@example <caption>Writing tests</caption> | |
Feature('Barbarian life goals', function () { | |
Scenario('What is best in life?', function () { | |
var barbarian, | |
enemies; | |
Given('Conan the barbarian', function () { | |
barbarian = new Barbarian('Conan'); | |
}); | |
And('many enemies', function () { | |
enemies = new Army(100); | |
}); | |
When('crush your enemies', function () { | |
barbarian.crush(enemies); | |
}); | |
Then('see them driven before you', function () { | |
enemies.haveRunAway.should.be.true; | |
}); | |
And('hear the lamentations of their women', function () { | |
enemies.women.areLamenting.should.be.true; | |
}); | |
}); | |
}); | |
@example <caption>Running tests</caption> | |
var should = chai.should(); | |
mocha.setup('bdd-feature'); | |
require(['spec/my-test'], function () { | |
mocha.run(); | |
}); | |
*/ | |
define(['mocha'], function (mocha) { | |
'use strict'; | |
var Suite = Mocha.Suite, | |
Test = Mocha.Test; | |
// Existing functionality from the 'bdd' interface | |
function escapeRe(text) { | |
var matchOperators = /[|\\{}()[\]^$+*?.]/g; | |
if (typeof text !== 'string') { | |
throw new TypeError('Expected a string'); | |
} | |
return text.replace(matchOperators, '\\$&'); | |
} | |
function bddFeature(suite) { | |
var suites = [suite]; | |
suite.on('pre-require', function (context, file, mocha) { | |
// New functionality for 'bdd-feature' | |
/** | |
Create a step function. | |
@param {string} prefix - The text that the step should start with | |
@param {string} title - Descriptive text | |
@param {function} base - Base function from the 'bdd' interface | |
@param {function} callback - Callback function | |
@return {object} The suite if base=describe, the test if base=it | |
@private | |
@memberof module:bdd-feature | |
*/ | |
function createStep(prefix, title, base, callback) { | |
if (title.toLowerCase().indexOf(prefix.toLowerCase()) !== 0) { | |
title = prefix + title; | |
} | |
return base.apply(this, [title, callback]); | |
} | |
/** | |
Describe a feature. | |
The title will be prefixed with 'Feature: ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.Feature = function (title, callback) { | |
return createStep('Feature: ', title, context.describe, callback); | |
}; | |
/** | |
By appending .only() you may tell Mocha to run only the specified feature. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.Feature | |
@memberof module:bdd-feature | |
*/ | |
context.Feature.only = function (title, callback) { | |
return createStep('Feature: ', title, context.describe.only, callback); | |
}; | |
/** | |
By appending .skip() you may tell Mocha to ignore the feature. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.Feature | |
@memberof module:bdd-feature | |
*/ | |
context.Feature.skip = function (title, callback) { | |
return createStep('Feature: ', title, context.describe.skip, callback); | |
}; | |
/** | |
Describe a scenario. | |
The title will be prefixed with 'Scenario: ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.Scenario = function (title, callback) { | |
return createStep('Scenario: ', title, context.describe, callback); | |
}; | |
/** | |
By appending .only() you may tell Mocha to run only the specified scenario. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.Scenario | |
@memberof module:bdd-feature | |
*/ | |
context.Scenario.only = function (title, callback) { | |
return createStep('Scenario: ', title, context.describe.only, callback); | |
}; | |
/** | |
By appending .skip() you may tell Mocha to ignore the scenario. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.Scenario | |
@memberof module:bdd-feature | |
*/ | |
context.Scenario.skip = function (title, callback) { | |
return createStep('Scenario: ', title, context.describe.skip, callback); | |
}; | |
/** | |
Describe a 'given' step. | |
The title will be prefixed with 'Given ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.Given = function (title, callback) { | |
return createStep('Given ', title, context.it, callback); | |
}; | |
/** | |
Describe a 'when' step. | |
The title will be prefixed with 'When ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.When = function (title, callback) { | |
return createStep('When ', title, context.it, callback); | |
}; | |
/** | |
Describe a 'then' step. | |
The title will be prefixed with 'Then ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.Then = function (title, callback) { | |
return createStep('Then ', title, context.it, callback); | |
}; | |
/** | |
Describe a 'but' step. | |
The title will be prefixed with 'But ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.But = function (title, callback) { | |
return createStep('But ', title, context.it, callback); | |
}; | |
/** | |
By appending .skip() you may tell Mocha to ignore this step. | |
This only applies to 'and' & 'but' steps as 'given', 'when' & 'then' are required. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.But | |
@memberof module:bdd-feature | |
*/ | |
context.But.skip = function (title, callback) { | |
return createStep('But ', title, context.it.skip, callback); | |
}; | |
/** | |
Describe an 'and' step. | |
The title will be prefixed with 'And ' if it doesn't already start with it. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@memberof module:bdd-feature | |
*/ | |
context.And = function (title, callback) { | |
return createStep('And ', title, context.it, callback); | |
}; | |
/** | |
By appending .skip() you may tell Mocha to ignore this step. | |
This only applies to 'and' & 'but' steps as 'given', 'when' & 'then' are required. | |
@param {string} title - Descriptive text | |
@param {function} callback - Callback function | |
@see #context.And | |
@memberof module:bdd-feature | |
*/ | |
context.And.skip = function (title, callback) { | |
return createStep('And ', title, context.it.skip, callback); | |
}; | |
// Existing functionality from the 'bdd' interface | |
function runWithSuite(suite) { | |
return function run() { | |
suite.run(); | |
}; | |
} | |
context.run = mocha.options.delay && runWithSuite(suite); | |
context.before = function (title, callback) { | |
suites[0].beforeAll(title, callback); | |
}; | |
context.after = function (title, callback) { | |
suites[0].afterAll(title, callback); | |
}; | |
context.beforeEach = function (title, callback) { | |
suites[0].beforeEach(title, callback); | |
}; | |
context.afterEach = function (title, callback) { | |
suites[0].afterEach(title, callback); | |
}; | |
context.describe = context.context = function (title, callback) { | |
var suite = Suite.create(suites[0], title); | |
suite.file = file; | |
suites.unshift(suite); | |
callback.call(suite); | |
suites.shift(); | |
return suite; | |
}; | |
context.describe.only = function (title, callback) { | |
var suite = context.describe(title, callback); | |
mocha.grep(suite.fullTitle()); | |
return suite; | |
}; | |
context.xdescribe = context.xcontext = context.describe.skip = function (title, callback) { | |
var suite = Suite.create(suites[0], title); | |
suite.pending = true; | |
suites.unshift(suite); | |
callback.call(suite); | |
suites.shift(); | |
}; | |
context.it = function (title, callback) { | |
var suite = suites[0], | |
test; | |
if (suite.pending) { | |
callback = null; | |
} | |
test = new Test(title, callback); | |
test.file = file; | |
suite.addTest(test); | |
return test; | |
}; | |
context.it.only = function (title, callback) { | |
var test = context.it(title, callback), | |
reString = '^' + escapeRe(test.fullTitle()) + '$'; | |
mocha.grep(new RegExp(reString)); | |
return test; | |
}; | |
context.xit = context.xspecify = context.it.skip = function (title) { | |
context.it(title); | |
}; | |
}); | |
} | |
Mocha.interfaces['bdd-feature'] = bddFeature; | |
return mocha; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment