I am having an issue persisting the correct cookies when trying to test an endpoint that requires authentication.
When I test an endpoint that requires a user to be logged in, I would expect to receive a http status of 201 success, but am receiving a 403 forbidden.
Here is an overview of what my test spec file is doing:
- I create a mocha
describe function with a before() and after() and inside those callbacks, I start my server and then add a dummy user and some dummy content in my test mongoose database.
- My first
it() function uses agent to make a connection to the endpoint without signing in and that test expect(403) is correct.
- My second
it() function then uses agent to attempt to sign in with the credentials for the dummy user I created earlier. I expect(200) to pass, which it does. I also console.log(res.headers[set-cookie]) and I see the output is as follows:
connect.sid=s%3Aze-bIOV3kWJc6TdjWMhxqnmcregTXBKZ.HIACLrWQwReMqj8YVLSXkjAPhBEwT0EuUJfkgeC%2BfpU; Domain=localhost; Path=/'
- The problem arises with my third
it() function, where I want to make a call to an endpoint that requires a user to be logged in. What I would expect to see here is expect(201), but instead get expect(403) suggesting to me that the user is not logged in, and the cookie is invalid. Indeed, when I log the value of the cookie as above I see the following, which is completely different:
connect.sid=s%3AVStxZsDf_RxxDj50c4kmvzebKeMGz51N.Y0qojAAqf8Uw92vGv5u941FArM57P%2FXEG10dsSsx2bc; Domain=localhost; Path=/'
This is the contents of my spec file for testing these endpoints:
'use strict';
let app = require('../../../server/app.js'),
testutils = require('../testutils.js'),
request = require('supertest');
describe('POST /answer/:id/comment', function() {
let answer_id,
server,
agent;
before(function(done) {
app().then(function(result) {
server = result.server;
agent = request.agent(server);
testutils.addUser()
.then(testutils.addQuestion)
.then(testutils.addAnswer)
.then(function(answer) {
answer_id = answer._id;
done();
});
});
});
after(function(done) {
testutils.mongoClear();
done();
});
it('should return a json encoded error message with a http status of 403 for a logged out user.', function(done) {
agent
.post('/answer/' + answer_id + '/comment')
.expect('Content-Type', /json/)
.expect(403)
.expect({info: 'You need to be signed in to comment.'}, done);
});
it('should then log a user in and save a cookie', function(done) {
agent
.post('/user/login')
.send({email: 'test@test.te', authkey: 'password1'})
.expect('set-cookie', /connect.sid/)
.expect(200)
.end(function(err, res) {
console.log({
cookie: '/user/login ' + res.headers['set-cookie']
});
if(err) return done(err);
done();
});
});
it('should then be able to post a comment for an answer given a logged in user with the correct role', function(done) {
agent
.post('/answer/' + answer_id + '/comment')
.expect(201)
.end(function(err, res) {
console.log({
cookie: '/answer/:id/comment ' + res.headers['set-cookie']
});
if(err) return done(err);
done();
});
});
});
A brief description of before() and after()
before(function(done) {
app().then(function(result) {
server = result.server;
agent = request.agent(server);
testutils.addUser()
.then(testutils.addQuestion)
.then(testutils.addAnswer)
.then(function(answer) {
answer_id = answer._id;
done();
});
});
});
after(function(done) {
testutils.mongoClear();
done();
});
What I am doing inside before() is ensuring that the express() server has booted, that mongoose has started and that my dummy data has been inserted to the test database - all before any of these tests are started. This seems to be working fine and from my understanding, the before function should run to completion.
I am also assigning request.agent to a running instance of my express() server.
Finally, once everything is set up as expected, the first it test starts running and completes with the expected result, so it passes.
The second test runs as expected and passes.
The Third test fails because a 403 is returned where a 201 status would be expected. When looking closely at the cookie strings between the two tests, I see that they are completely different. This has been highlighted in this StackOverflow post.
Here is what I have tried:
- I wanted to make sure that everything that was needed was ready before any tests ran, including making sure that Mongoose was running, the express server was running and that all the dummy data needed was inserted.
- I place a console log message inside the
/user/login endpoint to see if the session data was being set and it was. For reference, this is what the endpoint looks like.
app.post('/user/login', (req, res) => {
user.checkUserCredentials(req.body)
.then((result) => {
if(!result.isactive) {
res.status(403).json({
info: 'Could not sign you in because your account has been deactivated.'
});
return;
}
user.setUserCookie(req, res, result);
console.log(req.session); // This shows the user id correctly so I know it is working
res.status(200).json({
info: 'Login successful.',
user: result
});
})
.catch((error) => {
res.status(403).json({
info: 'Login unsuccessful.',
error: error
});
});
});
- Inside the second test, I tried saving the cookies following some users suggestions, as follows:
.end(function(err, res) {
if(err) return done(err);
agent.saveCookies(res);
done();
});
- I then tried to retrieve that cookie in testing the endpoint that requires the user to be logged in, as follows:
it('should allow the user to post something', function(done) {
let call = agent.post('/need/to/be/signed/in');
agent.attachCookies(call);
call
.send({some: 'Content'})
.expect(201)
.end(function(err, res) {
if(err) return done(err);
done();
});
});
For reference, I am also using the express-session module and inside my app.js file I have the following.
app.use(session({
secret: 'dummysecret',
resave: false,
saveUninitialized: true,
httpOnly: true,
store: new connectMongo({
mongooseConnection: mongoose.connection
}),
cookie: {
httpOnly: false,
maxAge: null,
domain: app.config.cookieDomain,
secure: app.config.httpsEnabled
}
}));
I'm out of ideas as to what could be causing this. I have trawled through issues and discussion fora and tried many things to get it working, but to no avail. Could the code above be causing the issue?
I am having an issue persisting the correct cookies when trying to test an endpoint that requires authentication.
When I test an endpoint that requires a user to be logged in, I would expect to receive a http status of 201 success, but am receiving a 403 forbidden.
Here is an overview of what my test spec file is doing:
describefunction with abefore()andafter()and inside those callbacks, I start my server and then add a dummy user and some dummy content in my test mongoose database.it()function usesagentto make a connection to the endpoint without signing in and that test expect(403) is correct.it()function then usesagentto attempt to sign in with the credentials for the dummy user I created earlier. Iexpect(200)to pass, which it does. I alsoconsole.log(res.headers[set-cookie])and I see the output is as follows:it()function, where I want to make a call to an endpoint that requires a user to be logged in. What I would expect to see here isexpect(201), but instead getexpect(403)suggesting to me that the user is not logged in, and the cookie is invalid. Indeed, when I log the value of the cookie as above I see the following, which is completely different:This is the contents of my spec file for testing these endpoints:
A brief description of before() and after()
What I am doing inside
before()is ensuring that theexpress()server has booted, that mongoose has started and that my dummy data has been inserted to the test database - all before any of these tests are started. This seems to be working fine and from my understanding, thebeforefunction should run to completion.I am also assigning
request.agentto a running instance of myexpress()server.Finally, once everything is set up as expected, the first
ittest starts running and completes with the expected result, so it passes.The second test runs as expected and passes.
The Third test fails because a 403 is returned where a 201 status would be expected. When looking closely at the cookie strings between the two tests, I see that they are completely different. This has been highlighted in this StackOverflow post.
Here is what I have tried:
/user/loginendpoint to see if the session data was being set and it was. For reference, this is what the endpoint looks like.For reference, I am also using the
express-sessionmodule and inside myapp.jsfile I have the following.I'm out of ideas as to what could be causing this. I have trawled through issues and discussion fora and tried many things to get it working, but to no avail. Could the code above be causing the issue?