2016-07-29 49 views
2

Ich habe einige Logik in meiner lokalen Login-Strategie für Pass, die ich Unit-Test mit Stubs/Mocks (weil es eine externe API ruft) will, aber ich kann nicht scheinen in die Funktion zu testen es.Wie Unit Pass lokalen Strategie testen? (Sinon, Proxyquire)

Hier ist meine test.js Datei:

var expect = require('chai').expect; 
var sinon = require('sinon'); 
var proxyquire = require('proxyquire'); 
require('../config/passport.js'); 

describe('it should get user account from the API', function() { 
    it('should be able to access passport authenticate', function(){ 
     var reqUserObject = { 
      body: { user_name: 'fakeymcfakeypants', password: '123Skidoo' } 
     } 
     var requestPromiseStub = sinon.stub(); 

     requestPromiseStub.onCall(0).returns(Promise.resolve('{"userId": 138}')) 
       .onCall(1).returns(Promise.resolve('{"userName": "fakeymcfakeypants", "status": 0}')) 

     var passportTest = proxyquire('passport', { 
      'request-promise': requestPromiseStub 
      }); 

     var passportStub = sinon.stub(passportTest, "authenticate"); 

     var response = passportStub.calledWith('localLogin', reqUserObject); 
     console.log(response); 
     expect.response.to.be.true; 


    }); 

    }); 

Und das Setup für die Funktion in config/passport.js:

var rp = require('request-promise'); 
var passport = require("passport"); 
var LocalStrategy = require('passport-local').Strategy; 


module.exports = function (passport, LocalStrategy) { 

    passport.use('localLogin', new LocalStrategy({ 
     usernameField : 'user[user_name]', 
     passwordField : 'user[password]'}, 
    function(username, password, done) { 
     //logic blah blah blah here, uses two request-promise calls 
     return done(null, username); 
    }) 
) 
} 

Soweit ich das beurteilen kann, die passport.authenticate Methode wird nicht aufgerufen (es gibt immer false zurück). Wenn ich Proxyquire entferne und nur Pass & config/pass.js 'normalerweise' benötige, ist die Antwort auch falsch.

Ich weiß, das ist ein bisschen kompliziert, so dass alle anderen Vorschläge, wie dies zu testen wäre sehr geschätzt werden!

EDITING CURRENT Code hinzufügen:

var expect = require('chai').expect; 
var chai = require('chai'); 
var sinon = require('sinon'); 
var proxyquire = require('proxyquire'); 
var passport = require('passport'); 
var sinonChai = require('sinon-chai'); 
var async = require('async'); 

chai.use(sinonChai); 

describe('canary test: passport', function(){ 
     it('should pass this canary test', function(){ 
      expect(true).to.be.true; 
     }); 
    }); 

describe('it should get user account from the API', function() { 
    var authSpy; 
    var requestPromiseStub; 
    var passportResponse; 
    var userResponse; 

    beforeEach(function() { 
     this.sandbox = sinon.sandbox.create() 
     authSpy = sinon.spy(passport, 'authenticate'); 

    }) 

    afterEach(function() { 
     this.sandbox.restore() 
    }) 


    it('should be able to access passport authenticate', function(){  
     var mockReq = { 
       body: { 
       username: 'fakeymcfakeypants', 
       password: '123Skidoo' 
       }, 
      logIn: function() {} 
      }; 

     var mockRes = { 
      }; 

     requestPromiseStub = sinon.stub(); 

     next = sinon.stub(); 

     requestPromiseStub.onCall(0).returns(Promise.resolve({userId: 138, statusCode: 200})) 
       .onCall(1).returns(Promise.resolve({userName: 'fakeymcfakeypants', status : 0})) 

     var overrides = { 
      'request-promise': requestPromiseStub, 
      'authenticate': {authenticate: authSpy} 
     }; 

     proxyquire('../config/passport.js', overrides)(); 

     //added 'next' here as authenticate expects it: https://github.com/jaredhanson/passport/blob/master/lib/middleware/authenticate.js#L81 
     //passport should return either a username, or false, not sure how to access that? 

     passport.authenticate('localLogin')(mockReq, mockRes, next); 

     // if I comment out the 'logIn' function above and make an explicit function here I can see the username being returned, but of course it's inside the function closure: 

     passport.authenticate('localLogin', function(err, user){ 
     // I can see here that the username is correct: 
     console.log(user) 
    })(mockReq, mockRes, next); 

     expect(requestPromiseStub).to.have.been.called; 


    }); 

    }); 

Ich bin ziemlich sicher, ich etwas wirklich einfach & dumm bin mit Blick auf, aber ich kann nicht scheinen, normaler callbacky Wrapper mit der Syntax des Passes zur Arbeit zu kommen .authentifizieren. :(

Antwort

1

config/passport.js

var rp = require('request-promise'); 
 
var passport = require('passport'); 
 
var LocalStrategy = require('passport-local').Strategy; 
 

 
module.exports = function() { 
 
    passport.use('local', new LocalStrategy({ 
 
    usernameField: 'username', 
 
    passwordField: 'password' 
 
    }, 
 
    function (username, password, done) { 
 
    console.log('logic blah blah blah here, uses two request-promise calls'); 
 
    return done(null, username); 
 
    })); 
 
};

test.js

var chai = require('chai'); 
 
var expect = require('chai').expect; 
 
var sinon = require('sinon'); 
 
var proxyquire = require('proxyquire'); 
 
var passport = require('passport'); 
 
var sinonChai = require('sinon-chai'); 
 

 
chai.use(sinonChai); 
 

 
describe('it should get user account from the API', function() { 
 
    it('should be able to access passport authenticate', function() { 
 
    // configure request and response 
 
    var mockReq = { 
 
     body: { 
 
     username: 'johndoe', 
 
     password: 'secret' 
 
     }, 
 
     logIn: function() {} 
 
    }; 
 

 
    var mockRes = {}; 
 

 
    // configure request-promise 
 
    var requestPromiseStub = sinon.stub(); 
 

 
    requestPromiseStub 
 
     .onCall(0).returns(Promise.resolve({ 
 
     userId: 138 
 
     })) 
 
     .onCall(1).returns(Promise.resolve({ 
 
     userName: 'johndoe', 
 
     status: 0 
 
     })); 
 

 
    var overrides = { 
 
     'request-promise': requestPromiseStub 
 
    }; 
 
    proxyquire('./passport.js', overrides)(); 
 
    passport.authenticate('local')(mockReq, mockRes); 
 

 
    // ASSERTS HERE 
 
    //expect(requestPromiseStub).to.have.been.called(); 
 
}); 
 
});

+0

Sie so viel Dank! Dieses * fast * arbeitet für mich. .. :) Was ist die 'logIn: function() {}' in der mockReq für? Und wie teste ich die zurückgegebenen Werte von pass.authenticate? (Es soll einen Benutzer zurückgeben.) – esperluette

+0

ist es eine Pass-Funktion durch den Pass injiziert. Siehe https://github.com/jaredhanson/passport/blob/master/lib/http/request.js Wenn Sie req.logIn entfernen, schlägt es fehl. –

+0

Bitte erläutern Sie "Und wie teste ich die zurückgegebenen Werte von pass.authenticate?" –