【问题标题】:How to setup Mocha tests with Node.js and Passport如何使用 Node.js 和 Passport 设置 Mocha 测试
【发布时间】:2013-07-07 12:01:33
【问题描述】:

在使用 Node.js (CompoundJS + PassportJS) 构建的应用程序中,如何在锁定并需要登录的控制器上运行 Mocha 测试?我曾尝试使用 Superagent,但运气不佳,要使用它,服务器需要运行才能运行测试。我已经非常接近这种方法,但不想让服务器运行来运行单元测试。

我还尝试包含护照并使用request.login 方法,但最终我一直收到错误passport.initialize() 中间件未使用。

我正在尝试使用生成的 CompoundJS 测试,这些测试在涉及身份验证之前运行良好。默认的 CompoundJS 测试运行一个 init.js 文件,它可以很好地处理身份验证并以某种方式提供给每个控制器测试:

require('should');
global.getApp = function(done) {
    var app = require('compound').createServer()
    app.renderedViews = [];
    app.flashedMessages = {};

    // Monkeypatch app#render so that it exposes the rendered view files
    app._render = app.render;
    app.render = function(viewName, opts, fn) {
        app.renderedViews.push(viewName);

        // Deep-copy flash messages
        var flashes = opts.request.session.flash;
        for (var type in flashes) {
            app.flashedMessages[type] = [];
            for (var i in flashes[type]) {
                app.flashedMessages[type].push(flashes[type][i]);
            }
        }

        return app._render.apply(this, arguments);
    }

    // Check whether a view has been rendered
    app.didRender = function(viewRegex) {
        var didRender = false;
        app.renderedViews.forEach(function(renderedView) {
            if (renderedView.match(viewRegex)) {
                didRender = true;
            }
        });
        return didRender;
    }

    // Check whether a flash has been called
    app.didFlash = function(type) {
        return !!(app.flashedMessages[type]);
    }

    return app;
};

controllers/users_controller_test.js

var app,
    compound,
    request = require('supertest'),
    sinon = require('sinon');

/** 
 * TODO: User CREATION and EDITs should be tested, with PASSPORT
 * functionality.
 */

function UserStub() {
    return {
        displayName: '',
        email: ''
    };
}

describe('UserController', function() {
    beforeEach(function(done) {
        app = getApp();
        compound = app.compound;
        compound.on('ready', function() {
            done();
        });
    });

    /**
     * GET /users
     * Should render users/index.ejs
     */
    it('should render "index" template on GET /users', function(done) {
        request(app)
            .get('/users')
            .end(function(err, res) {
                res.statusCode.should.equal(200);
                app.didRender(/users\/index\.ejs$/i).should.be.true;
                done();
            });
    });

    /*
     * GET /users/:id
     * Should render users/index.ejs
     */
    it('should access User#find and render "show" template on GET /users/:id',
        function(done) {
            var User = app.models.User;

            // Mock User#find
            User.find = sinon.spy(function(id, callback) {
                callback(null, new User);
            });

            request(app)
                .get('/users/42')
                .end(function(err, res) {
                    res.statusCode.should.equal(200);
                    User.find.calledWith('42').should.be.true;
                    app.didRender(/users\/show\.ejs$/i).should.be.true;

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

这些都以AssertionError: expected 403 to equal 200AssertionError: expected false to be true 失败

【问题讨论】:

    标签: node.js mocha.js passport.js compoundjs


    【解决方案1】:

    我结合使用了 mocking passport.initialize、测试助手和复合配置事件的侦听器。

    这提供了两件事:

    1. DRY - 在控制器测试中重复使用 beforeEach 代码。
    2. 不显眼的测试 - 模拟 passport.initialize,因此我不必根据测试修改配置。

    在 test/init.js 中我添加了模拟 passport.initialize** 的方法:

    ** 在以下位置找到它:

    http://hackerpreneurialism.com/post/48344246498/node-js-testing-mocking-authenticated-passport-js

    // Fake user login with passport.
    app.mockPassportInitialize = function () {
        var passport = require('passport');
        passport.initialize = function () {
            return function (req, res, next) {
                passport = this;
                passport._key = 'passport';
                passport._userProperty = 'user';
                passport.serializeUser = function(user, done) {
                    return done(null, user.id);
                };
                passport.deserializeUser = function(user, done) {
                    return done(null, user);
                };
                req._passport = {
                    instance: passport
                };
                req._passport.session = {
                    user: new app.models.User({ id: 1, name: 'Joe Rogan' })
                };
    
                return next();
            };
        };
    };
    

    然后我添加了一个 helpers.js 文件以在每个控制器中调用:

    module.exports = {
        prepApp: function (done) {
            var app = getApp();
            compound = app.compound;
            compound.on('configure', function () { app.mockPassportInitialize(); });
            compound.on('ready', function () { done(); });
            return app;
        }
    };
    

    这将在每个控制器的beforeEach 中调用:

    describe('UserController', function () {
        beforeEach(function (done) {
            app = require('../helpers.js').prepApp(done);
        });
        [...]
    });
    

    【讨论】:

    • 感谢在第一个控制器测试运行时出现错误:{ [Error: connect ECONNREFUSED] code: 'ECONNREFUSED', errno: 'ECONNREFUSED', syscall: 'connect' }
    • 确保使用init.js运行mocha:mocha test/init.js test/controllers/users_controller.test.js
    • 另外,验证 prepApp 函数是否被调用,console.log('In prepApp'); 行位于 prepApp 的顶部。
    • 是的,使用 mocha test/init.js test/controllers/accounts_controller.test.js 运行仍然给我同样的错误......无法真正产生任何不同的东西。我在顶部得到“In PrepApp”一次,然后我看到我的服务器启动,然后得到堆栈跟踪。
    猜你喜欢
    • 2017-08-03
    • 2016-11-15
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    相关资源
    最近更新 更多