摩卡失败 "timeout exceeded"

Mocha Failing with "timeout exceeded"

我是 Mocha 的新手,我正在尝试 运行 测试此代码:

"use strict";

process.env.NODE_ENV = 'test';

var assert = require('assert'),
    Browser = require('zombie'),
    xapp = require('../app'),
    app,
    User = require('../models/users').User,
    testMail = 'aaa@aaa.aaa',
    testPassword = 'aD1$#!_é',
    server;

before(function(done) {
    xapp(function(sapp) {
        app = sapp;
        server = app.listen(3000, done);
    });
});

after(function(done) {
    app.closeMongo(function() {
        server.close(done);
    });
});

function clearDb(done) {
    User.findOne({email: testMail}, function(err, user) {
        if(err) return done(err);
        if(!user) return done();
        else {
            user.remove(done);
        }
    });
}

describe('User signup', function() {
    this.timeout(3200);

    before(clearDb);

    describe('Homepage Form', function() {
        this.timeout(3200);
        it('should load the trial form', function(done) {
            Browser.visit('http://localhost:3000/', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                var form = browser.query('form[action="/users/signup"]');
                assert.notEqual(form, null, 'Form on homepage exists');
                assert.notEqual(browser.query("input[type=email]", form), null, 'has email input on page');
                done();
            });
        });

        it('should test the trial form', function(done) {
            Browser.visit('http://localhost:3000/', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                browser
                .fill('email', testMail)
                .pressButton('Sign up', function(err) {
                    if(err) return done(err);
                    assert.equal(browser.location.pathname, '/users/signup', 'Links to signup page');
                    assert.notEqual(browser.text('h1').indexOf('Sign up'), -1, 'Title page contains "Sign up"');
                    var form = browser.query('form#form-signup');
                    assert.notEqual(form, null, 'Form on signup page exists');
                    var emailInput = browser.query('input[type=email]#email', form);
                    assert.notEqual(emailInput, null, 'has email input on signup page');
                    assert.equal(emailInput.value, testMail, 'email input has entered value on homepage');
                    done();
                });
            });
        });
    });

    describe('Signup page form', function() {
        this.timeout(3200);
        it('should load the signup form', function(done) {
            Browser.visit('http://localhost:3000/users/signup', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                var form = browser.query('form[action="/users/signup"]#form-signup');
                assert.notEqual(form, null, 'Form on signup page exists');
                assert.equal(form.method, "post", "Form is POST");
                assert.notEqual(browser.query("input[type=email]#email", form), null, 'has email input on page');
                assert.notEqual(browser.query("input[type=password]#password", form), null, 'has password input on page');
                assert.notEqual(browser.query("input[type=password]#passwordConfirm", form), null, 'has password confirmation input on page');
                done();
            });
        });

        it('should sign up a test user', function(done) {
            Browser.visit('http://localhost:3000/users/signup', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                browser
                .fill('Email:', testMail)
                .fill('Password:', testPassword)
                .fill('Password confirmation:', testPassword)
                .pressButton('#form-signup button[type=submit]', function(err) {
                    if(err) return done(err);
                    assert.notEqual(browser.query('.alert-success'), null, 'Has success alert');
                    assert.notEqual(browser.text('.alert-success').indexOf('Sign up successful'), -1, 'Found the text "Sign up successful" in alert');
                    done();
                });
            });
        });

        it('shouldn\'t sign up the same email twice', function(done) {
            Browser.visit('http://localhost:3000/users/signup', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                browser
                .fill('Email:', testMail)
                .fill('Password:', testPassword)
                .fill('Password confirmation:', testPassword)
                .pressButton('#form-signup button[type=submit]', function(err) {
                    if(err) return done(err);
                    assert.equal(browser.location.pathname, '/users/signup', 'Still on the signup page');
                    assert.notEqual(browser.query('.alert-danger'), null, 'Has danger alert');
                    assert.notEqual(browser.text('.alert-danger').indexOf('This email address already exists!'), -1, 'Found the text "This email address already exists!" in alert');
                    done();
                });
            });
        });
    });
});

describe('User login', function() {
    this.timeout(2500);

    after(clearDb);

    describe('Homepage form', function() {
        this.timeout(3200);
        it('should appear when we click login', function(done) {
            Browser.visit('http://localhost:3000/', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                assert.equal(browser.query('form[action="/users/login"]'), null, 'No login form should be visible before we click on login');
                browser.clickLink('Login', function(err) {
                    if(err) return done(err);
                    var form = browser.query('form[action="/users/login"]');
                    assert.notEqual(form, null, 'Login form should be visible after click on login');
                    assert.notEqual(browser.query('input[type=email]#email'), null, 'Has email input');
                    assert.notEqual(browser.query('a', form), null, 'Forgot your password?');
                    assert.notEqual(browser.query('input[type=password]#password'), null, 'Has password input');
                    done();
                });
            });
        });

        it('should not work with wrong credentials', function(done) {
        this.timeout(3200);
            Browser.visit('http://localhost:3000/', function(err, browser) {
                if(err) return done(err);
                assert.ok(browser.success, "page loaded");
                browser.clickLink('Login', function(err) {
                    if(err) return done(err);
                    browser
                    .fill('Email:', testMail)
                    .fill('Password:', (testPassword + 'a'))
                    .pressButton('Login', function(err) {
                        if(err) return done(err);
                        assert.equal(browser.location.pathname, '/users/login');
                        assert.notEqual(browser.query('.alert-danger'), null, "Has danger alert");
                        assert.notEqual(browser.text('.alert-danger').indexOf('Invalid email or password.'), -1, 'alert contain error message "Invalid email or password."');
                        done();
                    });
                });
            });
        });
    });

    describe('Login form', function() {
        this.timeout(3200);
        it('should login with valid credentials', function(done) {
            Browser.visit('http://localhost:3000/users/login', function(err, browser) {
                if(err) return done(err);   
                assert.ok(browser.success, "page loaded");
                browser
                .fill('#form-signin input[type=email]', testMail)
                .fill('#form-signin input[type=password]', testPassword)
                .pressButton('Sign in', function(err) {
                    if(err) return done(err);
                    assert.equal(browser.location.pathname, '/');
                    assert.notEqual(browser.query('.alert-success'), null, "Has success alert");
                    assert.equal(browser.text('.alert-success'), '×Close You are now logged in.');
                    assert.notEqual(browser.link('Dashboard'), null, 'Has dashboard link');
                    assert.notEqual(browser.link('Log out'), null, 'Has log out link');
                    done();
                });
            });
        });
    });
});

这是我正在使用的命令:

$ mocha -b -R spec -s 1000

失败并显示此消息:

  1) "before all" hook

  0 passing (2s)
  1 failing

  1)  "before all" hook:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/usr/local/lib/node_modules/mocha/lib/runnable.js:159:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

能帮我看看这是什么原因吗?

我知道如果我更改测试的超时 运行ner:

$ mocha -b -R spec -s 1000 -t 3000

测试有效。但是我想知道这个错误的真正原因。

谢谢!

你得到你得到的错误是因为你的顶级 before 钩子比默认的 2000 毫秒超时延迟到 运行。如果您不知道:before 表示 "execute this before all tests in this suite",这就是为什么错误消息会提到 "before all" 挂钩。

它在您执行 $ mocha -b -R spec -s 1000 -t 3000 时有效,因为您已将超时增加到 3000 毫秒。您的 before 钩子中的代码需要 2 到 3 秒才能 运行。您可以将此设置放在 test/mocha.opts 中,使其永久化。

使用 BeforeEach 而不是 Before

问题是,server.listen 正在阻塞,因此回调中的 done 语句在所有测试完成并调用 server.close 之前不会执行。

防止违反默认时间限制的简单(和恕我直言)更清洁的解决方案是 start/stop 每个测试的服务器。

变化:

before(function(done) {
    xapp(function(sapp) {
        app = sapp;
        server = app.listen(3000, done);
    });
});

after(function(done) {
    app.closeMongo(function() {
        server.close(done);
    });
});

收件人:

beforeEach(function(done) {
    xapp(function(sapp) {
        app = sapp;
        server = app.listen(3000, done);
    });
});

afterEach(function(done) {
    app.closeMongo(function() {
        server.close(done);
    });
});

任何测试都不应 运行 超过 2000 毫秒,除非出现问题。

另一个可能更好的解决方案是使用专门设计用于测试 API 调用的测试框架。