2012-12-22 19 views

答えて

42

これには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を使用することができます:セクションPersisting an agentを見てみましょう。

+2

この方法では、テストサーバーを実行する必要があります。それはSupertestのサーバーでも使用できますか? セッション・クッキーを使用していますが、動作しません。私はuser1.postからの応答を見て、Cookieにはユーザー情報が含まれていません。 –

+2

テスト・サーバーは必要ありません。通常のexpress app.jsを使用することができますあなたは[example](https://github.com/visionmedia/superagent/blob/master/test/node/agency.js)を見ましたか?テストを別のファイルに保存したい場合は、ヘッダーに 'require(../ app.js)'を入れてアプリを起動してください。 – zemirco

+3

私はそれが動作するようにしましたが、すでに実行されている開発サーバーを強制終了した場合に限ります。 supertestと私はそれをする必要はありません。どのようにしてそれをスーパーエージェントとうまく組み合わせるためのアイディアですか?おそらく、テスト環境のために別のポートを聞く? –

24

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();   
    }); 
+0

要求の2番目の呼び出しは決して実行されません。つまり、.endハンドラには決して到達しません。 – juanpaco

+4

これは、2番目のリクエストが最初の終了コールバックの内側に置かれていればうまく動作します。 – JayPea

+0

申し訳ありませんが、 'request.agent(app)'はアンディの答えに従って、手動でクッキーを設定するよりもはるかにエレガントです。 –

2

は、私はあなたがCookieSessionミドルウェアを使用していると仮定するつもりだ、これを試してみてください。

前述のように、目標はリクエストに渡すCookieの値を取得することです。しかし、何らかの理由で(少なくとも私のテストでは)、supertestは同じテストで2つのリクエストを起動しません。したがって、適切なクッキー値を取得する方法をリバースエンジニアリングする必要があります。まず、クッキーを構築するためにモジュールを必要とする必要があります:

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

はい、それは醜いです。私はそれらをテストファイルの一番上に置きます。

次に、クッキー値を作成する必要があります。私は、認証されたユーザーが必要となるテスト用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(現在は少なくとも現在)が現在のユーザー情報をセッションに挿入する方法です。

"j:""s:"の行は、Cookieベースのセッションを使用している場合、PassportがフォールバックするConnect CookieSessionミドルウェアから切り捨てられます。最後に、Cookieをシリアライズします。私は"session"をそこに入れました。それが私のCookieセッションミドルウェアをどのように設定したのかということです。また、App.config.cookieSecretは他の場所で定義されており、Express/Connect CookieSessionミドルウェアに渡す秘密でなければなりません。私はそれを後でアクセスできるように、Test.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.cookiesetへの呼び出しに注目してください。これにより、リクエストしたCookieを使用するようになります。

これで、ユーザーがログインしていると考えてアプリを偽装し、実際のサーバーを稼働させる必要はありません。

+0

また、要求ハンドラを直接テストして、いくつかのダミーのreqおよびresオブジェクトを渡すこともできます。もちろん、それはあなたのルーティングをテストしません。 – juanpaco

48

zeMircoが指摘するように、基盤となるsuperagentモジュールはセッションをサポートし、自動的にクッキーを管理します。ただし、文書化されていない機能を通じてsupertestsuperagent.agent()機能を使用することは可能です。

単に代わりrequire('supertest')('url')require('supertest').agent('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(); 
     } 
    }; 
}; 
+9

app.jsを '' 'request.agent(app);' 'に入れると、実行中のサーバなしで動作します。クール。 – shredding

+0

現在、このソリューションが機能しています。 –

8

、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(); 
    }); 
    }); 
}); 
+1

'req.status'ではなく' expect(res.status) 'でなければなりません。 –

5

申し訳ありませんが、どちらの解決方法も私にとってはうまくいかない。

supertest.agent()で、私は、私はsupertest-as-promisedのlibを使用することはできません、私は事前にサーバーを実行するために必要だappインスタンスを使用してhttp://127.0.0.1:portを指定し、しかも私はsupertestの期待(アサーション)を使用することはできませんすることはできませんし、 so on ...

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); 
    }); 
}; 

生産的な1日を過ごしましょう!

関連する問題