【问题标题】:Ensuring server app runs before mocha tests start确保服务器应用程序在 mocha 测试开始之前运行
【发布时间】:2016-11-08 10:46:18
【问题描述】:

这类似于 Ensuring Express App is running before each Mocha Test ,但指定的解决方案仍然不起作用 + 我正在使用 websocket 服务器

简而言之,我正在使用一个名为 socketcluster 的 websocket 框架,这是我的服务器文件

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

运行node server.js 启动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')
  })

}

我想测试服务器,但测试在服务器实际启动之前就已经完成(并且失败了)。有没有办法在继续测试之前强制服务器完全加载?这就是我目前所拥有的

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()
    })
  })
})

以上似乎不起作用。尽管还提供了 done() 调用,但服务器并未在 before 块中完全加载。

edit - 我尝试拆分 server.js 文件以根据其导入方式调用不同的服务器。

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()
}

在 test.js 中,我这样做了 - 但似乎仍然不起作用

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 - 通过从 server.js 文件返回一个承诺尝试另一种方式。还是不行

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
      }))
  }

在前面的钩子里

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

【问题讨论】:

    标签: javascript node.js express mocha.js


    【解决方案1】:

    您的server 模块没有回调,因此当您在beforeEach 方法中调用done() 时它无法准备好。

    首先,将您的app 导出到您的server 模块中。

    然后,执行以下操作:

    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);
    });
    

    这样,done() 将在 listen 回调中被调用,因此在您的测试中服务器将正确监听。然后,记得在测试结束后关闭它(如果一个或多个测试套件中需要服务器,这很有用)。

    【讨论】:

    • 感谢您的回答.. 但看起来listen 方法是在socketcluster 源代码中内置的某个地方。 :/ 看起来改变 node_modules 中的源是唯一的选择
    • 我对代码做了一些更改.. 可以以类似的方式实现解决方案吗?不过似乎仍然不起作用
    • 如果有多个测试文件,我应该在每个测试文件中使用before钩子吗?
    【解决方案2】:

    here 解释的解决方案对我有用,尤其是:

    在 server.js(或 app.js)的末尾:

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

    在 test.js 中:

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

    在这种情况下,app 在监听时会发送一个“app_started”事件,测试代码会等待它。提供的 URL 包含更多详细信息。

    希望对你有帮助!

    【讨论】:

    • 对我不起作用。在“before_all”钩子中给出Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
    • 我认为是因为发射器和 on 不在同一个变量上。 @尼克
    • 这对我有用,但我必须在发出事件时使用 setTimeout。
    【解决方案3】:

    您需要等到服务器实际侦听给定端口。 这可以通过在 server.js 中导出某种 init 函数来完成,该函数从 mocha 获取 done 回调。

    在你的 server.js 中

    let initCallback;
    
    [..]
    
    app.listen(port, function() {
      if (initCallback) {
        initCallback();
      }
    });
    
    
    exports = {
      init: function(cb) {
        initCallback = cb;
      }
    }
    

    在你的测试中

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

    另见:How to know when node.js express server is up and ready to use

    【讨论】:

    • 我对代码做了一些更改.. 可以以类似的方式实现解决方案吗?不过似乎仍然不起作用
    • SocketCluster 发出一个就绪事件,这应该可以解决问题。见:github.com/SocketCluster/socketcluster/blob/…
    【解决方案4】:

    我合并了前两个帖子,它对我有用。 首先,确保您的 app.js 或 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;
      }
    }

    接下来在你的 test.js 中你将需要这个

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

    我不是 javascript 方面的专家,但这对我有用。希望能帮助到你!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-27
      • 2021-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-08
      • 2020-03-22
      • 2017-02-17
      相关资源
      最近更新 更多