Ensuring server app runs before mocha tests start

主宰稳场 提交于 2019-12-23 07:19:07

问题


This is similar to Ensuring Express App is running before each Mocha Test , but the specified solution still isnt working + i'm using a websocket server

in short , i'm using a websocket framework called socketcluster and this is my server file

import {SocketCluster} from 'socketcluster';

const socketCluster = new SocketCluster({
  workers:1,
  brokers:1,
  port: 3000,
  appName:null,
  initController: __dirname + '/init.js',
  workerController: __dirname + '/worker.js',
  brokerController: __dirname + '/broker.js',
  socketChannelLimit: 1000,
  crashWorkerOnError: true
})

export default socketCluster

running node server.js starts the worker process specified in worker.js

export const run = (worker) => {
  console.log(' >> worker PID: ',process.pid);

  const app = express();

  const httpServer = worker.httpServer;
  const scServer = worker.scServer;

  app.use(cookieParser())

  httpServer.on('request', app);

  app.get('/',(req,res) => {
    console.log('recieved')
    res.send('Hello world')
  })

}

I want to test the server , but the tests are finishing (and failing) way before the server actually starts. is there a way i can force the server to fully load before going ahead with tests? this is what i have so far

describe('Express server',() =>{

  beforeEach((done) => {
    require('../../server/server')
    done()
  })

  it('should return "Hello World"',(done) => {
    http.get('http://127.0.0.1:3000',(res) => {
      expect(res).to.contain('wtf world')
      done()
    })
  })
})

the above doesnt seem to work. the server doesnt fully load in the before block despite providing the done() call as well.

edit - i've tried splitting the server.js file to invoke a different server based on how its imported.

const main = () => {
  console.log('main server')
  new SocketCluster({
    workers:1,
    brokers:1,
    port: 3000,
    appName:null,
    initController: __dirname + '/init.js',
    workerController: __dirname + '/worker.js',
    brokerController: __dirname + '/broker.js',
    socketChannelLimit: 1000,
    crashWorkerOnError: true
  })
}

export const test = (port,done) => {
  console.log('testing server')
  new SocketCluster({
    workers:1,
    brokers:1,
    port: port,
    appName:null,
    initController: __dirname + '/init.js',
    workerController: __dirname + '/worker.js',
    brokerController: __dirname + '/broker.js',
    socketChannelLimit: 1000,
    crashWorkerOnError: true
  })
  done()
}

if (require.main === module){
  main()
}

and in test.js , i do this - still doesnt seem to work though

import {expect} from 'chai';
import {test} from '../../server/server'


describe('Express server',() =>{

  before(function(done){
    test(3000,done)
  })

  it('should return "Hello World"',(done) => {
    http.get('http://127.0.0.1:3000',(res) => {
      expect(res).to.contain('world')
      done()
    })
  })
})

edit:2 - trie another way by returning a promise from the server.js file. still doesnt work

export const test = (port) => {
  console.log('testing server')
  return Promise.resolve(new SocketCluster({
        workers:1,
        brokers:1,
        port: port,
        appName:null,
        initController: __dirname + '/init.js',
        workerController: __dirname + '/worker.js',
        brokerController: __dirname + '/broker.js',
        socketChannelLimit: 1000,
        crashWorkerOnError: true
      }))
  }

and in the before hook

 before(function(done,port){
    test(3000).then(function(){
      console.log('arguments: ',arguments)
      done()
    })
  })

回答1:


Your server module doesn't have a callback, so it could not be ready when you call done() in your beforeEach method.

First, export your app in your server module.

Then, do something like:

const app = require('../../server/server').app;
let server; 

before(done => {
  server = app.listen(3000, done);
});

/** 
   ...
   your tests here
   ...
**/

/** and, if you need to close the server after the test **/

after(done => {
  server.close(done);
});

This way, done() will be called in the listen callback, so in your tests the server will be listening correctly. Then, remember to close it after tests end (useful if server is required in one or more test suites).




回答2:


The solution explained here worked for me, in particular:

At the end of server.js ( or app.js ):

app.listen( port, ip, function()
{
  console.log( 'Server running on http://%s:%s', ip, port )
  app.emit( "app_started" )
})
module.exports = app

and in test.js:

var server = require( '../server' )
before( done =>
{
  server.on( "app_started", function()
  {
    done()
  })
})

In this case, app sends an "app_started" event when it is listening, and the test code waits for it. The provided URL contains more details.

Hope it helps !




回答3:


You need to wait until the server actually listens on the given port. This could be accomplished by exporting some kind of init function in your server.js, which takes the done callback from mocha.

In your server.js

let initCallback;

[..]

app.listen(port, function() {
  if (initCallback) {
    initCallback();
  }
});


exports = {
  init: function(cb) {
    initCallback = cb;
  }
}

In your test

beforeEach((done) => {
  require('../../server/server').init(done)
})

Also see: How to know when node.js express server is up and ready to use




回答4:


I combined the first two posts and it worked for mine. First, make sure you have init code in your app.js or server.js

// put this in the beginning of your app.js/server.js
let initCallback;

//put this in the end of your app.js/server.js
if (initCallback) {
  // if this file was called with init function then initCallback will be used as call back for listen
  app.listen(app.get('port'),"0.0.0.0",(initCallback)=>{
    console.log("Server started on port "+app.get('port'));
  });
}
else{
// if this file was not called with init function then we dont need call back for listen
app.listen(app.get('port'),"0.0.0.0",()=>{
  console.log("Server started on port "+app.get('port'));
});
}

//now export the init function so initCallback can be changed to something else when called "init"
module.exports = {
  init: function(cb) {
    initCallback = cb;
  }
}

Next in your test.js you will need this

//beginning of your code
const app = require("../../server/server").app;
before(done => {
  require("../app").init();
  done();
});



//end of your code
  after(done => {
  done();
});

I am no expert in javascript but this works for me. Hope it helps!



来源:https://stackoverflow.com/questions/38223053/ensuring-server-app-runs-before-mocha-tests-start

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!