Here is a workable, reusable way to test an expressjs/mongoose application. What we’re dealing with It assumes the following setup; i.e. what every project could be expected to have: expressjs project |- api |- app.js |- database.js |- test | test1.test.js | test2.test.js | ... Stripped down, your app will probably look something like this: app.js bodyParser = ( ) cors = ( ) express = ( ) database = ( ) app = express() app .use(cors()) .use(bodyParser.json()) .use(bodyParser.urlencoded({ : })) database .dbconnect() .on( , err => .log( )) app.get( , (req, res) => { res.send( ) }) app.listen( , () => .log( ) ) .exports = app const require "body-parser" const require "cors" const require "express" const require "./database" let // Pretty standard API app extended true // The article covers this later "error" console "Connection to database failed." // Standard route "/" async "Hello world" // other... better stuff here! 5000 console "Server started at port http://localhost:5000" module Yep! Vanilla expressjs! The bit to focus on is the line - an import which utilises a nice pattern to handle the Mongo connection implementation. Looking at the module imported will make sense of the call above: const database = require(“./database”) database.dbconnect() mongoose = ( ) { MONGODB_URL } = process.env { mongoose.connect(MONGODB_URL, { : , : , : , : , }) mongoose.connection } { mongoose.disconnect() } .exports = { dbconnect, dbclose } const require "mongoose" const // or some other source of the cnn str ( ) function dbconnect useNewUrlParser true useCreateIndex true useUnifiedTopology true useFindAndModify false return ( ) function dbclose return module So that’s where we are. Nothing special… a simple app running alongside a server using the library. expressjs MongoDB mongoose This article assumes you have an app already; we’re focused on testing it. The cluttered approach to testing an express API Let’s imagine how things might look in your tests right now. could look something like this: test1.test.js describe( , () => { before( () => { }) beforeEach( () => { }) after( () => { }) it( , done => { request(app) .post( ) .send({ : }) .end( { res.should.be.tested.thoroughly.here done() }) }) }) "testing POST /wizard" async //before stuff like setting up the app and mongoose server. async //beforeEach stuff clearing out the db. async //after stuff like shutting down the app and mongoose server. "tests wizard creation" "/wizard" name "wizard1" ( ) => err, res … not dissimilar, with a lot of repetitive garbage: test2.test.js describe( , () => { before( () => { }) beforeEach( () => { }) after( () => { }) it( , done => { chai .request(app) .post( ) .send({ : }) .end( { res.should.be.tested.thoroughly.here done() }) }) }) "testing POST /apprentice" async //before stuff like setting up the app and mongoose server. async //beforeEach stuff clearing out the db. async //after stuff like shutting down the app and mongoose server. "tests apprentice creation" "/apprentice" name "apprentice1" ( ) => err, res Repetitive and cluttered: If you agree, the purpose of this article is to look at a way of cleaning that all up. A good deal clearer First, we create a module; a single place we can put the repetitive clutter from all our tests. I will call this a “Test Suite”. To separate it visually from the actual tests, I would put it inside a folder, like so: suites project |- api |- app.js |- database.js |- tests |- test1.test.js |- test2.test.js |- suites |- mochaTestSuite.js Here is the scaffold of such a suite: .exports = { describe(testDescription, () => { before( () => { }) beforeEach( () => { }) after( () => { }) testsCallBack() }) } module ( ) => testDescription, testsCallBack async //before stuff like setting up the app and mongoose server. async //beforeEach stuff clearing out the db. async //after stuff like shutting down the app and mongoose server. The more eagle-eyed among you will have noticed it isn't much different from the two tests we already have. It has two parameters. A and a . description callback And this is how we intend to use it in, for example, : test1.test.js mochaTestSuite = ( ) mochaTestSuite( , () => { it( , done => { chai .request(app) .post( ) .send({ : }) .end( { res.should.be.tested.thoroughly.here done() }) }) }) // usual require stuff we will cover later const require "./suites/mochaTestSuite.js" "the test description" "tests wizard creation" "/wizard" name "wizard1" ( ) => err, res The same eagle-eyes will also have noticed we haven't done anything much more than replace the function (which was originally in test1 and test2) with the new call — then delete all those before/after calls. describe mochaTestSuite In fact, the two parameters - and the for the tests - work in the same way (in the test suite we’re writing) as they do in the bog standard function we normally use. description callback exactly describe A Finished Test Suite Rather than laboriously “then add this” and “then do this”… here is, without further preamble, a finished . mochaTestSuite chai = ( ) chaiHttp = ( ) mongoose = ( ) request = ( ) { MongoMemoryServer } = ( ) app = ( ) mongooseConnect = ( ) should = chai.should() chai.use(chaiHttp) .exports = { describe(testDescription, () => { signUpThenLogIn = { chai .request(app) .post( ) .send({ : , ...credentials, }) .set( , ) .set( , ) .end( { chai .request(app) .post( ) .send(credentials) .set( , ) .set( , ) .end( { should.not.exist(err) res.should.have.status( ) res.body.token.should.include( ) testCallBack(res.body.token) }) }) } clearDB = { ( i mongoose.connection.collections) { mongoose.connection.collections[i].deleteMany( {}) } } before( () => { mongoServer = MongoMemoryServer() mongoUri = mongoServer.getUri() process.env.MONGODB_URL = mongoUri mongooseConnect.dbconnect() }) beforeEach( () => { clearDB() }) after( () => { clearDB() mongooseConnect.dbclose() }) testsCallBack(signUpThenLogIn) }) } // test/suites/mochaTestSuite.js const require "chai" const require "chai-http" const require "mongoose" const require "supertest" const require "mongodb-memory-server" const require "../../api/app.js" const require "../../api/database" const module ( ) => testDescription, testsCallBack // Bonus utility const ( ) => credentials, testCallBack "/auth/Thing/signup" name "Wizard" "Content-Type" "application/json" "Accept" "application/json" ( ) => err, res "/auth/Thing/login" "Content-Type" "application/json" "Accept" "application/json" ( ) => err, res 200 "Bearer " // Database connector const => () for var in => () async let new const await await async await async await await // Run the tests inside this module. A little unpacking: See how the setup we saw in the intro to this article, really helps us here? api/database.js The before/after is straightforward: Start the mongoServer; connect to it/Stop it; close it. In we clear the database, putting the clearing code into another function we can “await”. beforeEach The important bit is the callback . What happens is this. When you call , your statements are wrapped into the callback function parameter we discussed earlier. first sets up the tests inside its own statement, running the necessary before and after statements, then it (duh) callsback the function you declared with one or more functions. testsCallBack mochaTestSuite it mochaTestSuite describe it I included a function, which I will explain shortly. The point here is to show how all sorts of reusable code can be put into the suite, decluttering your actual tests. signUpThenLogIn Usage Now we can declutter our tests like: chai = ( ) chaiHttp = ( ) request = ( ) mongoose = ( ) app = ( ) mochaSuite = ( ) should = chai.should() chai.use(chaiHttp) mochaTestSuite( , signUpThenLogIn => { it( , done => { chai .request(app) .post( ) .send({ : }) .end( { res.body.name.should.equal( ) res.should.be.thoroughly.tested.in.other.ways done() }) }) }) const require "chai" const require "chai-http" const require "supertest" const require "mongoose" const require "../api/app.js" const require "./suites/mochaSuite" const "testing POST /wizard" "creates Wizards" "/wizard" name "wizard1" ( ) => err, res "wizard1" Sweet. With all the before and after setup being handled by the suite, we can focus on testing functionality. The has two parameters, the and the function - which will (duh!) callback to run the actual tests inside itself, having setup the app and mongoose servers for them. mochaTestSuite description callback And that’s it really. But I promised to show you how the would work. Some of your requests may need to be authenticated and it helps to outsource that clutter as well. signUpAndLogInfunction In fact, it works in a similar way, except ’s parameter will be inside one of your it tests. signUpAndLoginIn callback mochaSuite = ( ) mochaTestSuite( , signUpThenLogIn => { it( , done => { signUpThenLogIn( { : , : }, token => { chai .request(app) .post( ) .send({ : }) .set( , token) .end( { res.body.name.should.equal( ) res.should.be.thoroughly.tested.in.other.ways done() }) } ) }) }) // requires as normal const require "./suites/mochaSuite" "testing POST /apprentice" "Logs in Wizard can create Apprentices" username "grandwizard" password "IShallPass" "/apprentice" name "apprentice1" // use the token "Authorization" ( ) => err, res "apprentice1" So… passes into the callback. mochaTestSuite signUpThenLogIn In your tests (which require auth) use the function by passing in two parameters (the and (surprise surprise) the to run the actual test post-login, using the token provided by the callback. credentials callback This would work for other types of login as well, not just token based login. This also shows you how other features can be added to the test suite to “outsource” the laborious, repetitive code that tests need just to get them prepped for actually running. Cleaner tests not only help with debugging but help other developers who might be looking at your tests to understand how to use your code. Core, Thanks! https://expressjs.com/ https://mochajs.org/ https://www.chaijs.com/ Photo by on Sieuwert Otterloo Unsplash