Search code examples
node.jsexpressmocha.jscouchbasesupertest

Ensure express app is running before starting mocha tests


I built an API for a couchbase database, using express and node.js. My problem is that when I run my tests some of them fail, because the server is not fully running. I found a solution here https://mrvautin.com/ensure-express-app-started-before-tests on how to solve this issue. The article stated that in order to solve this issue, you have to add an event emitter in your server file like this

app.listen(app_port, app_host, function () {
    console.log('App has started');
    app.emit("appStarted");
});

and then add this, in your test file

before(function (done) {
    app.on("appStarted", function(){
        done();
    });
});

I have tried this, here is my implementation

Server File

app.listen(config['server']['port'], function(){
    app.emit("appStarted");
    logger.info("Listening")
})

Test File

before(function(done){
    app.on("appStarted", function(){
        done();
    })
});

I keep on getting the following error

  1) "before all" hook in "{root}":
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
      at listOnTimeout (internal/timers.js:549:17)
      at processTimers (internal/timers.js:492:7)

The article is from 2016, so I was thinking that maybe the syntax has been deprecated. I was wondering if someone could please help point me in the right direction?


Solution

  • You can add the below condition, more info see "Accessing the main module".

    if (require.main === module) {
         // this module was run directly from the command line as in node xxx.js
    } else {
         // this module was not run directly from the command line and probably loaded by something else
    }
    

    E.g.

    index.ts:

    import express from 'express';
    
    const app = express();
    const port = 3000;
    
    app.get('/', (req, res) => {
      res.sendStatus(200);
    });
    
    if (require.main === module) {
      app.listen(port, () => {
        console.log('App has started');
      });
    }
    
    export { app, port };
    

    index.test.ts:

    import { app, port } from './';
    import http from 'http';
    import request from 'supertest';
    
    describe('63822664', () => {
      let server: http.Server;
      before((done) => {
        server = app.listen(port, () => {
          console.log('App has started');
          done();
        });
      });
      after((done) => {
        server.close(done);
        console.log('App has closed');
      });
      it('should pass', () => {
        return request(server)
          .get('/')
          .expect(200);
      });
    });
    

    integration test result:

    (node:22869) ExperimentalWarning: The fs.promises API is experimental
      63822664
    App has started
        ✓ should pass
    App has closed
    
    
      1 passing (26ms)