2012-12-22 56 views

回答

42

您應該使用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進行認證的請求。

+2

使用此方法我需要運行測試服務器。有可能與Supertest的服務器一起使用嗎? 我使用會話cookie(帶Passport)並且不起作用,我查看user1.post的響應,並且cookie不包含用戶信息 –

+2

您不需要測試服務器。你可以使用你的普通快遞app.js.你有沒有看看[示例](https://github.com/visionmedia/superagent/blob/master/test/node/agency.js)?如果你想把測試保存在一個單獨的文件中,把'require(../ app.js)'放到標題中來啓動你的應用程序。 – zemirco

+3

我得到它的工作,但只有當我殺死已經運行的開發服務器。超級棒,我不必那樣做。任何想法如何使它與superagent很好地發揮?也許聽一個不同的端口用於測試環境? –

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

第二次請求調用不會觸發。即,.end處理程序永遠不會到達。 – juanpaco

+4

如果第二個請求放置在第一個結束回調中,這很好。 – JayPea

+0

很抱歉,根據Andy的回答,request.agent(app)'比手動設置cookie要優雅得多。 –

2

我會假設你正在使用的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中間件中剝離出來,如果您使用的是基於Cookie的會話,Passport將回退。最後,我們序列化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。這會導致請求使用我們構造的cookie。

現在你已經僞裝你的應用程序,認爲用戶已登錄,並且你不必保持實際的服務器運行。

+0

或者,您可以直接測試您的請求處理程序,並將其傳遞給一些虛擬請求和res對象。當然,這不會測試你的路由。 – juanpaco

48

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

應該是'expect(res.status)'而不是'req.status'。 – 2015-12-09 21:50:17

5

對不起,但建議的解決方案都不適合我。

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

祝您有個美好的一天!