Reputation: 28338
I have a folder structure of:
- app
- config
- config.js // environment variables
- express.js // creates an express server
- passwords
- passwords.controller.js
- passwords.route.js
- passwords.test.js
- index.js // main app file
My index file loads the app asynchronously:
function initMongoose() {
...
return mongoose.connect(config.mongo.host, {useNewUrlParser: true, keepAlive: 1})
.then((connection) => {
// Password is a function which connects the Password schema to the given connection
Password(connection);
})
.catch((e) => {
throw new Error(`Unable to connect to database: ${config.mongo.host}`);
});
}
async init() {
await initMongoose();
const app = require('./config/express');
const routes = require('./index.route');
app.use('/api', routes);
...
app.listen(3000, () => {
console.log('server started');
});
}
module.exports = init();
My test files are constructed like this:
// Load the app async first then continue with the tests
require('../index').then((app) => {
after((done) => {
mongoose.models = {};
mongoose.modelSchemas = {};
mongoose.connection.close();
done();
});
describe('## Passwords API', () => {
...
});
});
I'm starting the tests like this:
"test": "cross-env NODE_ENV=test ./node_modules/.bin/mocha --ui bdd --reporter spec --colors server --recursive --full-trace"
Here's where the weirdness gets the better of me. Basically it loads passwords.controller.js
before anything else, this is because of the --recursive
option. This should not happen since index.js
needs to load first so it can connect to mongoose etc before any of the tests runs, if it doesn't then this snippet from passwords.controller.js
will throw MissingSchemaError: Schema hasn't been registered for model "Password".
since the model Password
haven't been setup at this point:
const Password = mongoose.connection.model('Password');
So I tried adding --require ./index.js
before the --recursive
option, this indeed loads other files before passwords.controller.js
but the latter still runs before index.js
have even finished.
The solutions here doesn't work because index.js
doesn't run first.
How can I modify my test
script to allow my index.js
to finish before I run any test files?
Upvotes: 1
Views: 2198
Reputation: 1066
describe('## Passwords API', function() {
let appInstance;
before((done) => {
require('index.js').then((app) => {
appInstance = app
done();
});
});
});
Ref: https://mochajs.org/#asynchronous-hooks
Another possible pattern is to have a special helper file. That act like a singleton or some sort of cache. This allows the server to be bootstrap only once and it is shared for all the test. Note that this can cause unwanted side-effects in your unit tests but can speed up tests that do not affect the app object.
For instance testUtil.js
let app = null;
async function getApp(){
if(app){
return app;
}
app = await require('index.js')
return app
}
module.export = {
getApp,
}
and in your test file
const helper = require('[your path]/testUtil.js')
describe('## Passwords API', function() {
let appInstance;
before((done) => {
helper.getApp().then((app) => {
appInstance = app
done();
});
});
});
I would also suggest putting all the tests in a separate folder (called maybe "tests"). This would ensure that only the tests are loaded by --recursive
. Another perk is that in production you can skip this folder
Upvotes: 1
Reputation: 13
You could technically run your index.js file and instead of using mocha via npm test (CLI) you could actually run your test with mocha programmatically after index.js. Mocha Programmatically example
import Mocha from 'mocha';
import fs from 'fs';
import path from 'path';
// Instantiate a Mocha instance.
const mocha = new Mocha();
const testDir = 'some/dir/test'
// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file) {
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file) {
mocha.addFile(
path.join(testDir, file)
);
});
// Run the tests.
mocha.run(function(failures) {
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
Upvotes: 0