認証(ローカル戦略)およびMochaとSupertestでのテストにPassport.jsを使用しています。
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を維持します。ただし、文書化されていない機能を介して、supertest
からsuperagent.agent()
機能を使用することは可能です。
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を使用している場合、「ベアラートークン」メカニズムを利用し、仕様で次の例を使用できます。
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値を取得してリクエストに渡すことです。ただし、何らかの理由で(少なくとも私のテストでは)、スーパーテストは同じテストで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:"
行は、Cookieベースのセッションを使用している場合にPassportがフォールバックするConnect CookieSessionミドルウェアから取り出されます。最後に、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
}
"cookie"
とTest.cookie
を使用したset
の呼び出しに注意してください。これにより、リクエストで作成したCookieが使用されます。
これで、ユーザーがログインしていると考えるようになりました。実際のサーバーを実行し続ける必要はありません。