Я использую Passport.js для аутентификации (локальная стратегия) и тестирования с помощью Mocha и Supertest.
Как создать сеанс и выполнить аутентифицированные запросы с помощью Supertest?
Я использую Passport.js для аутентификации (локальная стратегия) и тестирования с помощью Mocha и Supertest.
Как создать сеанс и выполнить аутентифицированные запросы с помощью Supertest?
Вам следует использовать superagent. Это модуль нижнего уровня и используется supertest
. Взгляните на раздел Сохранение агента:
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
});
Теперь вы можете использовать user1
для выполнения аутентифицированных запросов.
Как указывает zeMirco, базовый модуль superagent
поддерживает сеансы, автоматически поддерживая файлы cookie для вас. Тем не менее, можно использовать функциональность superagent.agent()
от supertest
через недокументированную функцию.
Просто используйте require('supertest').agent('url')
вместо 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();
}
};
};
Попробуйте это,
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();
});
В качестве дополнения к Andy ответьте, чтобы иметь Supertest запуск вашего сервера для вас, вы можете сделать это следующим образом:
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();
});
});
});
Извините, но ни одно из предлагаемых решений для меня не работает.
С supertest.agent()
Я не могу использовать экземпляр app
, мне нужно заранее запустить сервер и указать http://127.0.0.1:port
, и, кроме того, я не могу использовать супер-ожидания (утверждения), я не могу используйте supertest-as-promised
lib и т.д....
Случай cookies
не будет работать для меня вообще.
Итак, мое решение:
Если вы используете Passport.js, в нем используется механизм маркера Bearer, и вы можете использовать следующие примеры в своих спецификациях:
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();
});
});
});
Возможно, у вас есть вспомогательная функция для аутентификации пользователей:
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);
});
};
Иметь продуктивный день!
Я предполагаю, что вы используете промежуточное ПО CookieSession.
Как указано в grub, ваша цель - получить значение cookie для передачи вашего запроса. Однако по какой-либо причине (по крайней мере, в моем тестировании), supertest не будет запускать 2 запроса в одном тесте. Итак, мы должны перепроектировать, как получить правильное значение cookie. Во-первых, вам понадобятся модули для создания вашего файла cookie:
var Cookie = require("express/node_modules/connect/lib/middleware/session/cookie")
, cookieSignature = require("express/node_modules/cookie-signature")
Да, это уродливо. Я помещал их в верхнюю часть тестового файла.
Затем нам нужно построить значение cookie. Я поместил это в beforeEach
для тестов, для которых требуется аутентифицированный пользователь:
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
ранее был определен в части моей цепи beforeEach
, которая определила пользователя, которого я собирался "войти". Структура session
заключается в том, как Passport (по крайней мере в настоящее время) вставляет текущую пользовательскую информацию в ваш сеанс.
Строки var val
с "j:"
и "s:"
вырваны из промежуточного программного обеспечения Connect CookieSession, которое Passport отменит, если вы используете сеансы на основе файлов cookie. Наконец, мы сериализуем файл cookie. Я помещал там "session"
, потому что так, как я настроил промежуточное ПО сеанса cookie. Кроме того, App.config.cookieSecret
определяется в другом месте, и это должен быть секрет, который вы передаете своему промежуточному программному обеспечению Express/Connect CookieSession. Я вложил его в Test.cookie
, чтобы потом получить доступ к нему.
Теперь, в фактическом тесте, вам нужно использовать этот файл cookie. Например, у меня есть следующий тест:
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
}
Обратите внимание на вызов set
с помощью "cookie"
и Test.cookie
. Это заставит запрос использовать куки файл, который мы создали.
И теперь вы подделали свое приложение, думая, что пользователь вошел в систему, и вам не нужно поддерживать фактический сервер.