ThomasReggi ThomasReggi - 2 months ago 6
Javascript Question

Run async code before entire mocha test

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.

Answer

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.