2012-12-22 8 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? Я использую сеансовые куки (с паспортом), и он не работает, я смотрю на ответ от user1.post, а cookie не содержит информации пользователя –

+2

, вам не нужен тестовый сервер. Вы можете использовать свой обычный экспресс app.js. Вы посмотрели на [пример] (https://github.com/visionmedia/superagent/blob/master/test/node/agency.js)? Если вы хотите сохранить тесты в отдельном файле, поместите 'require (../ app.js)' в заголовок, чтобы запустить приложение. – zemirco

+3

Я получил его на работу, но только если я убью сервер разработки, который уже работает. с величайшим я не должен этого делать. любые идеи, как заставить его хорошо играть с суперагентом? возможно, слушают другой порт для тестовой среды? –

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

Извините за downvote, но 'request.agent (app)', в соответствии с ответом Энди, намного элегантнее, чем вручную настраивать файлы cookie. –

2

Я буду считать, что вы используете 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. Это заставит запрос использовать куки-файл, который мы создали.

А теперь вы подделать ваше приложение, думая, что пользователь вошел в систему, и вы не должны держать фактический ход сервера.

+0

В качестве альтернативы вы можете просто проверить свой обработчик запросов напрямую, передав ему некоторые фиктивные объекты req и res.Это, конечно же, не будет проверять вашу маршрутизацию. – juanpaco

48

Как 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(); 
     } 
    }; 
}; 
+9

Если вы поместите приложение app.js в '' 'request.agent (приложение),' '' оно работает без работающего сервера. Классная вещь. – 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

Вероятно, должен быть 'ожидать (res.status)', а не 'req.status'. –

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

Имейте продуктивный день!

Смежные вопросы