Commit 59d4f7ea authored by Robert Knight's avatar Robert Knight

Add a helper function for writing parameterized JS tests

Mocha lacks built-in support [1] for writing parameterized tests and the
suggested solution [2] involves a bunch of boilerplate* which has IMO
resulted in different styles of parameterized tests in our codebase and
not having parameterized tests when they would be useful to attain more
complete coverage.

This adds a helper inspired by [3] for writing parameterized tests and
switches several existing places in our code to use it.

* Though less with ES2015 syntax.

[1] https://github.com/mochajs/mocha/issues/1454
[2] https://mochajs.org/#dynamically-generating-tests
[3] https://github.com/lawrencec/Unroll
parent 89afb494
......@@ -3,6 +3,7 @@
var angular = require('angular');
var util = require('./util');
var unroll = require('../../test/util').unroll;
describe('searchStatusBar', function () {
before(function () {
......@@ -25,21 +26,19 @@ describe('searchStatusBar', function () {
});
context('when there is a selection', function () {
var cases = [
var FIXTURES = [
{count: 0, message: 'Show all annotations'},
{count: 1, message: 'Show all annotations'},
{count: 10, message: 'Show all 10 annotations'},
];
cases.forEach(function (testCase) {
it('should display the "Show all annotations" message', function () {
unroll('should display the "Show all annotations" message when there are #count annotations', function (testCase) {
var elem = util.createDirective(document, 'searchStatusBar', {
selectionCount: 1,
totalCount: testCase.count
});
var clearBtn = elem[0].querySelector('button');
assert.include(clearBtn.textContent, testCase.message);
});
});
}, FIXTURES);
});
});
'use strict';
var commands = require('../markdown-commands');
var unroll = require('./util').unroll;
/**
* Convert a string containing '<sel>' and '</sel>' markers
......@@ -72,33 +73,30 @@ describe('markdown commands', function () {
});
describe('block formatting', function () {
var CASES = {
'adds formatting to blocks': {
var FIXTURES = [{
tag: 'adds formatting to blocks',
input: 'one\n<sel>two\nthree</sel>\nfour',
output: 'one\n> <sel>two\n> three</sel>\nfour',
},
'removes formatting from blocks': {
},{
tag: 'removes formatting from blocks',
input: 'one \n<sel>> two\n> three</sel>\nfour',
output: 'one \n<sel>two\nthree</sel>\nfour',
},
'preserves the selection': {
},{
tag: 'preserves the selection',
input: 'one <sel>two\nthree </sel>four',
output: '> one <sel>two\n> three </sel>four',
},
'inserts the block prefix before an empty selection': {
},{
tag: 'inserts the block prefix before an empty selection',
input: '<sel></sel>',
output: '> <sel></sel>',
}
};
}];
Object.keys(CASES).forEach(function (case_) {
it(case_, function () {
unroll('#tag', function (fixture) {
var output = commands.toggleBlockStyle(
parseState(CASES[case_].input), '> '
parseState(fixture.input), '> '
);
assert.equal(formatState(output), CASES[case_].output);
});
});
assert.equal(formatState(output), fixture.output);
}, FIXTURES);
});
describe('link formatting', function () {
......
......@@ -34,7 +34,7 @@ describe('media-embedder', function () {
var urls = [
'https://youtu.be/QCkm0lL-6lc',
'https://youtu.be/QCkm0lL-6lc/',
]
];
urls.forEach(function (url) {
var element = domElement('<a href="' + url + '">' + url + '</a>');
......@@ -55,7 +55,7 @@ describe('media-embedder', function () {
'https://vimeo.com/149000090/#fragment',
'https://vimeo.com/149000090?foo=bar&a=b',
'https://vimeo.com/149000090/?foo=bar&a=b',
]
];
urls.forEach(function (url) {
var element = domElement('<a href="' + url + '">' + url + '</a>');
......
......@@ -22,6 +22,61 @@ function noCallThru(stubs) {
return Object.assign(stubs, {'@noCallThru':true});
}
/**
* Helper for writing parameterized tests.
*
* This is a wrapper around the `it()` function for creating a Mocha test case
* which takes an array of fixture objects and calls it() once for each fixture,
* passing in the fixture object as an argument to the test function.
*
* Usage:
* unroll('should return #output with #input', function (fixture) {
* assert.equal(functionUnderTest(fixture.input), fixture.output);
* },[
* {input: 'foo', output: 'bar'}
* ]);
*
* Based on https://github.com/lawrencec/Unroll with the following changes:
*
* 1. Support for test functions that return promises
* 2. Mocha's `it()` is the only supported test function
* 3. Fixtures are objects rather than arrays
*
* @param {string} description - Description with optional '#key' placeholders
* which are replaced by the values of the corresponding key from each
* fixture object.
* @param {Function} testFn - Test function which can accept either `fixture`
* or `done, fixture` as arguments, where `done` is the callback for
* reporting completion of an async test and `fixture` is an object
* from the `fixtures` array.
* @param {Array<T>} fixtures - Array of fixture objects.
*/
function unroll(description, testFn, fixtures) {
fixtures.forEach(function (fixture) {
var caseDescription = Object.keys(fixture).reduce(function (desc, key) {
return desc.replace('#' + key, String(fixture[key]));
}, description);
it(caseDescription, function (done) {
if (testFn.length === 1) {
// Test case does not accept a 'done' callback argument, so we either
// call done() immediately if it returns a non-Promiselike object
// or when the Promise resolves otherwise
var result = testFn(fixture);
if (typeof result === 'object' && result.then) {
result.then(function () { done(); }, done);
} else {
done();
}
} else {
// Test case accepts a 'done' callback argument and takes responsibility
// for calling it when the test completes.
testFn(done, fixture);
}
});
});
}
module.exports = {
noCallThru: noCallThru,
unroll: unroll,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment