агент супертеста, похоже, не сохраняет сеансы в приложении node.js express.js

Из всех документов и примеров, которые я прочитал, должно быть возможно сохранить сеанс в супертесте с использованием агента:

var app = require('../../../server'),
    should = require('should'),
    request = require('supertest'),
    mongoose = require('mongoose'),
    User = mongoose.model('User'),
    _ = require('lodash');

var user = {
    name: 'Sterling Archer',
    email: '[email protected]',
    password: 'guest'
};

describe('user.me', function() {

    var url = '/user';
    var agent = request.agent(app);
    var new_user = new User(user);
    new_user.save();

    it('should return a user object', function(done) {

        agent
            .post('/signin')
            .send(_.omit(user, 'name'))
            .expect(200).end(function(err, res) {
                console.log(res.headers['set-cookie']);
            });

        agent
            .get(url)
            .expect(200)
            .end(function(err, res) {
                should.not.exist(err);
                console.log(res.headers['set-cookie']);
                res.body.should.have.property('user');
                res.body.user.should.have.properties('name', 'email');
                done();
            });

    });
});

Сеанс должен сохраниться, поскольку каждый запрос выше использует один и тот же агент. Однако, похоже, это не так - выходные данные журналов set-cookie следующие:

[ 'connect.sid=s%3AsFl1DQ4oOxC8MNAm79mnnr9q.gMkp8iEWtG8XlZZ2rkmheBwxKAyLyhixqDUOkYftwzA; Path=/; HttpOnly' ]
[ 'connect.sid=s%3AEzfbPyRGMff7yBXc9OAX3vGT.Ze2YoxZzuB6F6OwOk7mvrk96yPP2G4MGV%2Bt1rVjTyS8; Path=/; HttpOnly' ]

Passport.js используется для аутентификации и сеансов. Я ожидал бы, что вышеупомянутый connect.sid будет постоянным для обоих запросов, но похоже, что при каждом вызове создается новый сеанс, поэтому агент не входит в систему при втором вызове, и объект пользователя не возвращается.

Когда я тестирую свое приложение вручную в браузере, connect.sid остается постоянным после входа в систему, и функциональность, которую я тестирую, работает.

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


person Matt    schedule 03.04.2014    source источник
comment
.set('Cookie',<sid>) метод при втором вызове агента, он работает?   -  person Gntem    schedule 04.04.2014
comment
Я пробовал установить файл cookie, потому что видел этот подход в некоторых других примерах. Однако в этом не должно быть необходимости и все равно не сработало; set () будет вызываться для второго агента до завершения первого вызова (поэтому значение cookie еще не будет доступно).   -  person Matt    schedule 07.04.2014


Ответы (2)


Вы отправляете второй запрос, не дожидаясь ответа на первый; если вы не дадите агенту время для получения заголовка Set-Cookie в ответе и не используете его значение в качестве заголовка Cookie в том же запросе, будет создан новый сеанс. Попробуйте так:

it('should return a user object', function(done) {

    agent
        .post('/signin')
        .send(_.omit(user, 'name'))
        .expect(200).end(function(err, res) {
            console.log(res.headers['set-cookie']);
            agent
                .get(url)
                .expect(200)
                .end(function(err, res) {
                    should.not.exist(err);
                    console.log(res.headers['set-cookie']); // Should print nothing.
                    res.body.should.have.property('user');
                    res.body.user.should.have.properties('name', 'email');
                    done();
                });
        });
});
person Esteban    schedule 04.04.2014
comment
Ваше предложение не сработало, но вы указали, что я упустил из виду асинхронный характер кода. Я пробовал это однажды раньше; хотя теперь я лучше понимаю, что происходит, я тоже не понимаю, почему это не работает! Опять же, регистрируются разные файлы cookie (даже если вы отметили, что они ничего не должны печатать). Однако я нашел решение, см. Ниже. - person Matt; 04.04.2014

Предложение Эстебана указывало на то, что я упускал из виду асинхронный характер кода. Возвращаясь к этому примеру, я понял, что упустил важность входа в систему в отдельном тесте; это решило мою проблему.

Хотя сейчас создаю зависимые тесты, от которых я не без ума.

var app = require('../../../server'),
    should = require('should'),
    request = require('supertest'),
    mongoose = require('mongoose'),
    User = mongoose.model('User'),
    _ = require('lodash');

var user = {
    name: 'Sterling Archer',
    email: '[email protected]',
    password: 'guest'
};

var agent = request.agent(app);

describe('User Controller', function() {

before(function(done) {
    var new_user = new User(user);
    new_user.save();
    done();
});

describe('user.signin', function() {

    var url = '/signin';

    it('should signin and return a user object', function(done) {
        agent
            .post(url)
            .send(_.omit(user, 'name'))
            .expect(200)
            .end(function(err, res) {
                should.not.exist(err);
                res.body.should.have.property('user');
                res.body.user.should.have.properties('name', 'email');
                done();
            });
    });
});

describe('user.me', function() {

    var url = '/user';

    it('should return a user object', function(done) {
        agent
            .get(url)
            .expect(200)
            .end(function(err, res) {
                should.not.exist(err);
                res.body.should.have.property('user');
                res.body.user.should.have.properties('name', 'email');
                done();
            });
    });
});

after(function(done) {
    User.remove().exec();
    done();
});
});
person Matt    schedule 04.04.2014
comment
Здорово, что у вас это работает! Думаю, я знаю, почему это сработало, но, к сожалению, сейчас у меня нет времени проверить это (подсказка: когда end вызывает ваш обратный вызов, агент не завершает управление заголовком set-cookie). Я бы улучшил ваше решение, добавив логин в before функцию вместо другого теста (хотя тестовый логин по-прежнему является хорошей идеей). - person Esteban; 08.04.2014
comment
Я только что обнаружил, что вы стали жертвой этой ошибки. К счастью, для его исправления был выпущен запрос на перенос. - person Esteban; 10.04.2014