Я использую Passport.js для аутентификации (локальная стратегия) и тестирования с помощью Mocha и Supertest.Как аутентифицировать запросы Supertest с паспортом?
Как я могу создать сеанс и сделать проверку подлинности запросов с Supertest?
Я использую Passport.js для аутентификации (локальная стратегия) и тестирования с помощью Mocha и Supertest.Как аутентифицировать запросы Supertest с паспортом?
Как я могу создать сеанс и сделать проверку подлинности запросов с Supertest?
Вы должны использовать superagent для этого. Это модуль нижнего уровня и используется supertest
. Посмотрите на разделе Persisting an agent:
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
сделать проверку подлинности запросов.
Попробуйте это,
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();
});
Второй звонок для запроса никогда не срабатывает. То есть, обработчик .end никогда не достигается. – juanpaco
Это работает очень хорошо, если второй запрос помещается внутри первого обратного вызова. – JayPea
Извините за downvote, но 'request.agent (app)', в соответствии с ответом Энди, намного элегантнее, чем вручную настраивать файлы cookie. –
Я буду считать, что вы используете CookieSession промежуточное программное обеспечение.
Как уже упоминалось личинка, ваша цель состоит в том, чтобы получить значение куки, чтобы перейти к вашему запросу. Однако по какой-либо причине (по крайней мере, в моем тестировании), 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
. Это заставит запрос использовать куки-файл, который мы создали.
А теперь вы подделать ваше приложение, думая, что пользователь вошел в систему, и вы не должны держать фактический ход сервера.
В качестве альтернативы вы можете просто проверить свой обработчик запросов напрямую, передав ему некоторые фиктивные объекты req и res.Это, конечно же, не будет проверять вашу маршрутизацию. – juanpaco
Как zeMirco указывает, лежащий в основе superagent
модуль поддерживает сеансы, автоматически сохраняя куки для вас. Тем не менее, можно использовать функциональность 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();
}
};
};
Если вы поместите приложение app.js в '' 'request.agent (приложение),' '' оно работает без работающего сервера. Классная вещь. – shredding
В настоящее время это решение работает. –
В качестве дополнения к ответу Энди, чтобы иметь 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();
});
});
});
Вероятно, должен быть 'ожидать (res.status)', а не 'req.status'. –
Извините, но ни одно из предлагаемых решений не работает для меня.
С supertest.agent()
я не могу использовать экземпляр app
, я должен запустить сервер заранее и указать http://127.0.0.1:port
и, кроме того, я не могу использовать Supertest в ожидании (утверждения), я не могу использовать supertest-as-promised
LIB и и так далее ...
Корпус cookies
вообще не работает.
Итак, мое решение:
Если вы используете Passport.js, он использует механизм «Знаменосец маркер», и вы можете использовать следующие примеры в вашей спецификации:
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);
});
};
Имейте продуктивный день!
с этим методом Мне нужно запустить тестовый сервер. можно ли использовать его с сервером Supertest? Я использую сеансовые куки (с паспортом), и он не работает, я смотрю на ответ от user1.post, а cookie не содержит информации пользователя –
, вам не нужен тестовый сервер. Вы можете использовать свой обычный экспресс app.js. Вы посмотрели на [пример] (https://github.com/visionmedia/superagent/blob/master/test/node/agency.js)? Если вы хотите сохранить тесты в отдельном файле, поместите 'require (../ app.js)' в заголовок, чтобы запустить приложение. – zemirco
Я получил его на работу, но только если я убью сервер разработки, который уже работает. с величайшим я не должен этого делать. любые идеи, как заставить его хорошо играть с суперагентом? возможно, слушают другой порт для тестовой среды? –