¿Cómo autenticar las solicitudes de Supertest con Passport?

Estoy usando Passport.js para la autenticación (estrategia local) y las pruebas con Mocha y Supertest.

¿Cómo puedo crear una sesión y realizar solicitudes autenticadas con Supertest?

Deberías usar superagente para eso. Es un módulo de nivel inferior y es utilizado por supertest . Echa un vistazo a la sección Persistir a un agente :

 var request = require('superagent'); var user1 = request.agent(); user1 .post('http://localhost:4000/signin') .send({ user: '[email protected]', password: 'password' }) .end(function(err, res) { // user1 will manage its own cookies // res.redirects contains an Array of redirects }); 

Ahora puedes usar user1 para hacer solicitudes autenticadas.

Como señala zeMirco, el módulo superagent subyacente admite sesiones, manteniendo automáticamente las cookies para usted. Sin embargo, es posible utilizar la funcionalidad superagent.agent() desde supertest , a través de una función no documentada.

Simplemente use require('supertest').agent('url') lugar de require('supertest')('url') :

 var request = require('supertest'); var server = request.agent('http://localhost:3000'); describe('GET /api/getDir', function(){ it('login', loginUser()); it('uri that requires user to be logged in', function(done){ server .get('/api/getDir') .expect(200) .end(function(err, res){ if (err) return done(err); console.log(res.body); done() }); }); }); function loginUser() { return function(done) { server .post('/login') .send({ username: 'admin', password: 'admin' }) .expect(302) .expect('Location', '/') .end(onResponse); function onResponse(err, res) { if (err) return done(err); return done(); } }; }; 

Prueba esto,

  var request=require('supertest'); var cookie; request(app) .post('/login') .send({ email: "[email protected]", password:'password' }) .end(function(err,res){ res.should.have.status(200); cookie = res.headers['set-cookie']; done(); }); // // and use the cookie on the next request request(app) .get('/v1/your/path') .set('cookie', cookie) .end(function(err,res){ res.should.have.status(200); done(); }); 

Como una adición a la respuesta de Andy, para que Supertest inicie su servidor, puede hacerlo de la siguiente manera:

 var request = require('supertest'); /** * `../server` should point to your main server bootstrap file, * which has your express app exported. For example: * * var app = express(); * module.exports = app; */ var server = require('../server'); // Using request.agent() is the key var agent = request.agent(server); describe('Sessions', function() { it('Should create a session', function(done) { agent.post('/api/session') .send({ username: 'user', password: 'pass' }) .end(function(err, res) { expect(req.status).to.equal(201); done(); }); }); it('Should return the current session', function(done) { agent.get('/api/session').end(function(err, res) { expect(req.status).to.equal(200); done(); }); }); }); 

Lo siento, pero ninguna de las soluciones sugeridas no funciona para mí.

Con supertest.agent() no puedo usar la instancia de la app , debo ejecutar el servidor de antemano y especificar el http://127.0.0.1:port y, además, no puedo usar las expectativas (aserciones) de supertest. no se puede usar la supertest-as-promised y así sucesivamente …

El caso de las cookies no funcionará para mí en absoluto.

Entonces, mi solución es:

Si está utilizando Passport.js , utiliza el mecanismo de “token de portador” y puede usar los siguientes ejemplos en sus especificaciones:

 var request = require('supertest'); var should = require('should'); var app = require('../server/app.js'); // your server.js file describe('Some auth-required API', function () { var token; before(function (done) { request(app) .post('/auth/local') .send({ email: '[email protected]', password: 'the secret' }) .end(function (err, res) { if (err) { return done(err); } res.body.should.to.have.property('token'); token = res.body.token; done(); }); }); it('should respond with status code 200 and so on...', function (done) { request(app) .get('/api/v2/blah-blah') .set('authorization', 'Bearer ' + token) // 1) using the authorization header .expect(200) .expect('Content-Type', /json/) .end(function (err, res) { if (err) { return done(err); } // some `res.body` assertions... done(); }); }); it('should respond with status code 200 and so on...', function (done) { request(app) .get('/api/v2/blah-blah') .query({access_token: token}) // 2) using the query string .expect(200) .expect('Content-Type', /json/) .end(function (err, res) { if (err) { return done(err); } // some `res.body` assertions... done(); }); }); }); 

Es posible que desee tener una función de ayuda para autenticar a los usuarios:

test/auth-helper.js

 'use strict'; var request = require('supertest'); var app = require('app.js'); /** * Authenticate a test user. * * @param {User} user * @param {function(err:Error, token:String)} callback */ exports.authenticate = function (user, callback) { request(app) .post('/auth/local') .send({ email: user.email, password: user.password }) .end(function (err, res) { if (err) { return callback(err); } callback(null, res.body.token); }); }; 

¡Tenga un día productivo!

Voy a asumir que estás usando el software intermedio CookieSession.

Como mencionó Grub, su objective es obtener un valor de cookie para pasar a su solicitud. Sin embargo, por cualquier motivo (al menos en mi prueba), supertest no disparará 2 solicitudes en la misma prueba. Por lo tanto, tenemos que aplicar ingeniería inversa sobre cómo obtener el valor de cookie correcto. Primero, necesitarás los módulos para construir tu cookie:

 var Cookie = require("express/node_modules/connect/lib/middleware/session/cookie") , cookieSignature = require("express/node_modules/cookie-signature") 

Sí, eso es feo. Los puse en la parte superior de mi archivo de prueba.

A continuación, necesitamos construir el valor de la cookie. beforeEach esto en un beforeEach para las pruebas que requerirían un usuario autenticado:

 var cookie = new Cookie() , session = { passport: { user: Test.user.id } } var val = "j:" + JSON.stringify(session) val = 's:' + cookieSignature.sign(val, App.config.cookieSecret) Test.cookie = cookie.serialize("session",val) 

Test.user.id se definió previamente en la parte de mi cadena beforeEach que definía al usuario al que iba a “iniciar sesión”. La estructura de la session es la forma en que Passport (al menos actualmente) inserta la información del usuario actual en su sesión.

Las líneas var val con "j:" y "s:" se eliminan del middleware Connect CookieSession que Passport utilizará si está utilizando sesiones basadas en cookies. Por último, serializamos la cookie. Pongo "session" ahí, porque así es como configuré mi middleware de sesión de cookies. Además, App.config.cookieSecret se define en otra parte, y debe ser el secreto que usted pasa a su middleware Express / Connect CookieSession. Lo Test.cookie en Test.cookie para poder acceder más tarde.

Ahora, en la prueba real, necesitas usar esa cookie. Por ejemplo, tengo la siguiente prueba:

 it("should logout a user", function(done) { r = request(App.app) .del(App.Test.versionedPath("/logout")) .set("cookie", Test.cookie) // ... other sets and expectations and your .end } 

Observe la llamada para set con "cookie" y Test.cookie . Eso hará que la solicitud utilice la cookie que construimos.

Y ahora ha engañado a su aplicación para que piense que el usuario está conectado y no tiene que mantener funcionando un servidor real.