I'm looking for a way to run async code before the entire mocha test.
Here's an example of a test that uses an array of arguments & expectations and loops over all of the items in this array to produce function assertions.
var assert = require('assert')
/* global describe, it*/
var fn = function (value) {
return value + ' ' + 'pancake'
}
var tests = [
{
'arg': 'kitty',
'expect': 'kitty pancake'
},
{
'arg': 'doggy',
'expect': 'doggy pancake'
},
]
describe('example', function () {
tests.forEach(function (test) {
it('should return ' + test.expect, function (){
var value = fn(test.arg)
assert.equal(value, test.expect)
})
})
})
Now, my question is how would this work if the tests value came from a promise, like this:
var assert = require('assert')
var Promise = require('bluebird')
/* global describe, it*/
var fn = function (value) {
return value + ' ' + 'pancake'
}
function getTests () {
return Promise.resolve('kitty pancake')
.delay(500)
.then(function (value) {
return [
{
'arg': 'kitty',
'expect': value
},
{
'arg': 'doggy',
'expect': 'doggy pancake'
}
]
})
}
getTests().then(function (tests) {
describe('example', function () {
tests.forEach(function (test) {
it('should return ' + test.expect, function (){
var value = fn(test.arg)
assert.equal(value, test.expect)
})
})
})
})
also tried:
describe('example', function () {
getTests().then(function (tests) {
tests.forEach(function (test) {
it('should return ' + test.expect, function (){
var value = fn(test.arg)
assert.equal(value, test.expect)
})
})
})
})
However in this example none of the tests run because mocha doesn't recognize the describe statement because it's within a promise.
before
/ beforeEach
won't do anything to help with a test in the format anyway unless the was a beforeTest
hook that would supply mocha with the knowledge that there's an async operation that needs to be run before the entire test.
Writing Asynchronous Tests with Mocha. To indicate that a test is asynchronous in Mocha, you simply pass a callback as the first argument to the it() method: it('should be asynchronous', function(done) { setTimeout(function() { done(); }, 500); });
Mocha will run tests sequentially, waiting for each to finish before starting the next one.
You can skip tests by placing an x in front of the describe or it block, or placing a . skip after it. describe('feature 1', function() {}); describe.
As an alternative to Daniel Perez's method you can also use the command line switch --delay
and start the tests on the first run()
call. By delaying the run()
asynchronously you can register describe
s and it
s asynchronously beforehand. Note, though, that you can only call run()
once, i.e. only in one test file. Thus I've created an async test runner in ./test/
and each async test in ./testAsync/
:
// ./test/asyncRunner.js
"use strict";
const allAsyncPaths = [
"test-featureA",
"test-featureB",
].map(a => "../testAsync/" + a);
const allAsyncTestFunctions = allAsyncPaths.map(require);
Promise.resolve({
}).then(function() {
const allPromises = allAsyncTestFunctions.map(a => a());
return Promise.all(allPromises);
}).then(function() {
run(); // mocha waits for run() because of --delay flag
}).catch(function(err) {
console.error(err);
});
and
// ./testAsync/test-featureA.js
"use strict";
function asyncTestRegistrator() {
return Promise.resolve({
}).then(function() {
return getTestsAsync();
}).then(function(tests) {
describe('example', function () {
tests.forEach(function (test) {
it('should return ' + test.expect, function (){
var value = fn(test.arg);
assert.equal(value, test.expect);
});
});
});
}
module.exports = asyncTestRegistrator;
I am not sure if there is any easy way to do this, but you could try to run Mocha programatically.
Here is a little dirty version of what this could look like, just to show the idea.
data.js
var Promise = require('bluebird')
module.exports.tests = []
function getTests () {
return Promise.resolve('kitty pancake')
.delay(500)
.then(function (value) {
module.exports.tests = [
{
'arg': 'kitty',
'expect': value
},
{
'arg': 'doggy',
'expect': 'doggy pancake'
}
]
})
}
module.exports.getTests = getTests
test-launcher.js
var Mocha = require('mocha'),
fs = require('fs'),
path = require('path')
// First, you need to instantiate a Mocha instance.
var mocha = new Mocha()
// Then, you need to use the method "addFile" on the mocha
// object for each file.
// Here is an example:
fs.readdirSync('test').filter(function(file){
// Only keep the .js files
return file.substr(-3) === '.js'
}).forEach(function(file){
// Use the method "addFile" to add the file to mocha
mocha.addFile(
path.join('test', file)
)
})
// make sure your tests are loaded before running the tests
require('./data').getTests().then(function () {
// Now, you can run the tests.
mocha.run(function(failures){
process.on('exit', function () {
process.exit(failures)
})
})
})
test/index.js
var assert = require('assert')
var tests = require('../data').tests
var fn = function (value) {
return value + ' ' + 'pancake'
}
describe('test', function () {
describe('example', function () {
tests.forEach(function (test) {
it('should return ' + test.expect, function (){
var value = fn(test.arg)
assert.equal(value, test.expect)
})
})
})
})
You can then run you rests by running test-launcher.js
.
I would use the async/await with delay option as below:
setTimeout(async () => {
//get tests async
const tests = await getTests()
describe('example', async () => {
tests.forEach((test) => {
it(`test name: ${test.name} `, () => {
console.log(test.name)
})
})
})
run()
}, 1000)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With