无论怎样,摩卡超时都超过了

时间:2015-02-27 21:07:10

标签: node.js asynchronous mongoose mocha supertest

我目前正在为mocha中的nodejs app编写测试。我的api调用要求我登录,所以我想创建一个包装器测试套件,创建一个测试用户,然后调用实际的测试套件。下面是代码的样子:

var request = require('supertest');

var config = require('../config/config');

var AdminUser = require('../models/Authmodel');



function configureAuth(test_suite) {
    var url = "localhost:" + config.port;

    var email = "test@test.com";
    var password = "test_password";

    var admin;
    var token;

    describe("Signup User", function() {
      it("should signup new user", function(done) {
        request(url)
          .post('/auth/signup')
          .send({
            email: email,
            password: password
          })
          .expect(200)
          .end(function(){
            done();
          });
      });

      it("should login the user", function(done) {
        request(url)
          .post('/auth/login')
          .send({
            email: email,
            password: password
          })
          .expect(200)
          .end(function(err,res){
            if(err)
              throw(err);
            res.body.should.have.property('token');
            token = res.body.token;
            done();
          });
      });

      it("should retrieve admin document", function(done) {
        AdminUser.findOne({email: email}, function(err, dbAdmin) {
          if(err)
            throw(err);
          admin = dbAdmin;
          done();
        });
      });
    });

    // Call the actual test suite, pass it the auth credentials.
    describe("Test Suite", function() {
        it("should run the test suite", function(done) {
            // No matter what the timeout is set to it still exceeds it
            this.timeout(5000);
            test_suite({
                email: email,
                password: password,
                token: token,
                admin: admin
            }, done);
        });
    });

    describe("Clear Admins", function() {
    it("should clear the admin table", function(done) {
      AdminUser.remove({email: email}, function(err) {
        if(err)
          throw(err);

        done();
      });
    });
  });

};

module.exports = configureAuth;

这是一个使用包装器的测试套件:

var request = require('supertest');

var config = require('../config/config');

// Wrapper that creates admin user to allow api calls
var ConfigureAuth = require('./ConfigureAuth');


// Test data
var templateForm = {...}
var submittedForm = {...}

ConfigureAuth(
  function(credentials, exit) {

    var url = "localhost:" + config.port;

    var templateFormId = null;
    describe("Form Templates", function() {
      describe('POST /api/form/template', function(){
        it('should save the template', function(done){
          request(url)
            .post('/api/form/template')
            .query({email: credentials.email, token: credentials.token})
            .send({
              _admin_id: credentials.admin._id,
              template: templateForm,
            })
            .end(function(err, res){
              templateFormId = res.body._id;
              res.body.should.have.property('_admin_id').and.be.equal(''+credentials.admin._id);
              res.body.should.have.property('template').and.be.instanceof(Object);
              done();
            });
        });
      });

      describe('GET /api/form/template/:id', function(){
        it('Should respond with template data', function(done){
          request(url)
            .get('/api/form/template/' + templateFormId)
            .query({email: credentials.email, token: credentials.token})
            .end(function(err, res){
              ...
              done();
            });
        });
      });

      describe('GET /api/form/template/company/:id', function(){
        it('Should respond with company template data', function(done){
          request(url)
            .get('/api/form/template/company/' + credentials.admin._id)
            .query({email: credentials.email, token: credentials.token})
            .end(function(err, res){
              ...
              done();
            });
        });
      });

      describe('DELETE /api/form/template/:template_id', function(){
        it('Should delete the template data', function(done){
          request(url)
            .delete('/api/form/template/' + templateFormId)
            .query({email: credentials.email, token: credentials.token})
            .end(function(err, res){
              ...
              done();
            });
        });
      });
    });


    describe("Submitted Forms", function() {
      describe('POST /api/form/patient', function(){
        it('should save submitted form', function(done){
          request(url)
            .post('/api/form/patient')
            .query({email: credentials.email, token: credentials.token})
            .send({
              _admin_id: credentials.admin._id,
              form: submittedForm,
              firstName: "Jimbo",
              lastName: "Cruise",
              patientEmail: "jcruise@tomcruise.com",
            })
            .end(function(err, res){
              ...
              submittedFormId = res.body._id;
              done();
            });
        });
      });

      describe('GET /api/form/:form_id', function(){
        it('should respond with submitted form data', function(done){
          request(url)
            .get('/api/form/patient/' + submittedFormId)
            .query({email: credentials.email, token: credentials.token})
            .end(function(err, res){
              res.body.should.have.property('_id');

              ...

              done();
            });
        });
      });
    });


    after(function() {
      exit();
    });
});

无论我给测试套件什么超时,它都会给出"错误:超过5000毫秒超时"。所有测试都通过,除了#34;它应该运行测试套件"。我还要注意,我有其他不使用包装器的测试文件。首先调用上面的测试套件,创建admin用户,测试套件超时,然后清除管理文档,然后继续进行其他测试。最后,它打印出围绕ConfigureAdmin函数的测试。

1 个答案:

答案 0 :(得分:1)

在你的包装器中,你有这个:

// Call the actual test suite, pass it the auth credentials.
describe("Test Suite", function() {
    it("should run the test suite", function(done) {
        // No matter what the timeout is set to it still exceeds it
        this.timeout(5000);
        test_suite({
            email: email,
            password: password,
            token: token,
            admin: admin
        }, done);
    });
});

test_suite功能包含对describeit的更多调用。 如果您这样做,Mocha不会引发任何错误,但它不会按照您预期的方式运行。 Mocha会执行以下测试:

  1. Mocha发现了测试。 describe调用使用Mocha注册新套件。他们的回调立即执行 it调用使用Mocha注册新测试。当Mocha运行测试时,它们的回调将被执行。挂钩调用(beforeafter等)也在使用Mocha注册挂钩,稍后执行,当Mocha运行测试时

  2. Mocha运行已注册的测试。

  3. 当您将describe置于it内时会出现问题:此describe 执行,而Mocha 注册一个新套件,但是当它注册时,执行流程之外所有describe回调。因此,这个新套件在匿名顶级套件(Mocha自动创建)上注册,从该顶级套件继承其超时值。看看这个例子:

    describe("top", function () {
        it("test", function () {
            this.timeout(5000);
            describe("inner", function () {
                it("inner test", function (done) {
                    setTimeout(function () {
                        done();
                    }, 6000);
                });
            });
        });
    
        describe("inner 2", function () {
            it("inner test 2", function () {});
        });
    
    });
    
    describe("top 2", function (){
        it("test 3", function () {});
    });
    

    如果你运行它,你会得到:

      top
        ✓ test 
        inner 2
          ✓ inner test 2 
    
      top 2
        ✓ test 3 
    
      inner
        1) inner test
    
    
      3 passing (2s)
      1 failing
    
      1) inner inner test:
         Error: timeout of 2000ms exceeded
         [... etc ...]
    

    请注意inner套件,即使它出现在JavaScript代码中的top内,也会在Mocha的报告中显示 。另一方面,(inner 2恰好出现在它应该的位置。)这就是我上面解释的:当Mocha注册这个套件时,执行流程超出top和{{ 1}} top 2来电。另请注意describe调用无效。

    如果您运行上面相同的代码但使用timeout,则测试将通过,因为默认超时值(包括Mocha创建的匿名套件)现在为7000.

    此外,您的套件目前需要在测试之间订购一定的订单。摩卡不是为此而设计的。设置测试的灯具应该在mocha --timeout 7000before挂钩中完成,并且应该在beforeEachafter中将其拆除。因此,这不仅仅是afterEach来自describe的问题。