how to write TDD to check cookies - node.js

i'm trying to test if the response containing any cookies by using this unit test :
describe("given user is found", () => {
it("should return 200 status , access token and refresh token", async () => {
const response = await request(app)
.post("/api/v1/auth/signIn")
.send({
email: "sandra#gmail.com",
password: "sandra",
})
.expect(200);
expect(response.cookie).toBe(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjEsImlhdCI6MTY2MDQ0NDg0MSwiZXhwIjoxNjYxMDQ5NjQxfQ.pniLcI6wXqWooQgO1oH4ZvDgoQ-ul3jVYytT8FpJEzU"
);
});
});
but it returns that it's undefinend and i concoluded that because the cookie parser is not there , so how can i test if access token is found or not??

Related

Use JWT token in multiple test cases mocha node-js

How I create a reusable function which gives me a JWT token, so I can execute my test cases in which token is required without calling the login function again and again in each test case file
account.js
describe("Account", () => {
var token;
describe("/POST Login", () => {
it("it should gives the token", (done) => {
chai.request(server)
.post('api/v1/account')
.set('Accept', 'application/json')
.send({ "email": "john#gmail.com", "password": "123456" })
.end((err, res) => {
res.should.have.status(200);
res.body.should.have.property("token");
token = res.body.token //----------------TOKEN SET
done();
});
});
});
describe("/GET account", () => {
it("it should get the user account", (done) => {
chai.request(server)
.get('api/v1/account')
.set('x-auth-token', token)
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
});
category
describe("Category", () => {
var token;
//Login function duplicate in both the files
describe("/POST Login", () => {
it("it should gives the token", (done) => {
chai.request(server)
.post('api/v1/account')
.set('Accept', 'application/json')
.send({ "email": "john#gmail.com", "password": "123456" })
.end((err, res) => {
res.should.have.status(200);
res.body.should.have.property("token");
token = res.body.token //----------------TOKEN SET
done();
});
});
});
describe("/GET category", () => {
it("it should get the user account", (done) => {
chai.request(server)
.get('api/v1/account')
.set('x-auth-token', token)
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
});
I want to get the token from other file and used in different cases. What is the best approach todo this?
I'm basing my response on the fact that you have mentioned unit tests. Usually, with a unit test, you're testing a small piece of functionality. This means, that you want to test a small piece of logic within a bigger component/piece of logic and you are not interested in testing other components (like for example in your case testing your API. What you usually want to test is how your logic should behave in the case you will receive a 200 success response from the API or what happens with your logic if you receive a 400 or 500. I would recommend to mock your API calls for your testing by using a library like nock:
https://www.npmjs.com/package/nock
The way that you are trying to implement it it might be a bit more complicated. If you want to do this kind of testing I wouldn't pick jest/mocha as test runners. I would prepare a postman collection (probably you already have that) and then I would utilise newman to run my collection and actually do the integration testing that you want. You can read further here: Running collections on the command line with Newman
There are different approaches as well, but the one above can be a good one.
Use a before hook that would always login users and generates a token that can be used in your new test file.
let token;
before('Login user', async () => {
const response = await chai.request(server)
.post('api/v1/account')
.set('Accept', 'application/json')
.send({ "email": "john#gmail.com", "password": "123456" })
token = res.body.token;
});

Testing services with mocha / chai: Error testing login

I'm writing tests for a login service. The test must pass if the login is correct. Before every test the bd is cleaned. So I first create a user and then try to login. The expected behavior is receive the status 200 in the response but instead I'm receiving status 401 which says I'm not creating the user correctly.
describe("Users", () => {
beforeEach(done => {
User.remove({}, () => {
done();
});
});
describe("/POST login", () => {
it("should return successful login", done => {
const user = new User({
username: "test",
email: "test#test.com",
password: "testpass"
});
const user2 = {
user: "test",
password: "testpass"
};
user.save(err => {
if (err) {
done();
}
chai.request(server)
.post("/users/login")
.send(user2)
.end((err, res) => {
expect(res).to.has.status(200);
done();
});
});
});
Test result:
Uncaught AssertionError: expected { Object (_events, _eventsCount, ...) } to have status code 200 but got 401
Any hint of what's going on here?

chai assertion always OK

I am trying to testing a node.js api with mocha and chai assertion.
My problem is that I always get a 'passed result'.
The test:
describe('TESTING /register', () => {
it('Should create a new account for chai-testing:chai-testing', () => {
let user = {
pseudo: "chai-testing",
mail: "chai#chai.com",
password: "chai-testing"
};
chai.request(server)
.post('/register')
.send(user)
.end((err, resp) => {
console.log(resp.body);
resp.body.should.have.property('success').eql(true);
done();
});
});
});
And the console output :
TESTING /register
✓ Should create a new account for chai-testing:chai-testing
chai-testing chai#chai.com chai-testing
1 passing (51ms)
{ favoris: [],
_id: 5abf6b5502c0f910439fec32,
pseudo: 'chai-testing',
mail: 'chai#chai.com',
password: '$2a$10$BPzQfp3wiDxU3mwgeXkG8Oh.B1ET8wTt5kg12oBwQ0obUxAyZQdLu',
admin: false,
__v: 0 }
POST /register 200 281.742 ms - 51
{ **success: false**, message: 'pseudo already taken' }
What I did do wrong in my test?
put there two assertion instead of this :
describe('TESTING /register', () => {
it('Should create a new account for chai-testing:chai-testing', () => {
let user = {
pseudo: "chai-testing",
mail: "chai#chai.com",
password: "chai-testing"
};
chai.request(server)
.post('/register')
.send(user)
.end((err, resp) => {
console.log(resp.body);
// if the resp has an attribute success then this
// assertion is true ( .eql(true) )
// that's why you get the test always passing
resp.body.should.have.property('success');
resp.body.success.should.eql(true);
done();
});
});
});

Passport authentication in Chai tests

This is my first project using passport and I am new to Node in general. I am having trouble getting an endpoint recognized as authorized when running integration tests using Chai. The endpoint is
protected by token authentication using the passport and jsonwebtoken libraries. Here are the other files imported to the tests;
const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
const should = chai.should();
const { Session } = require('../models/practiceSession' );
const {User} = require('../models/user');
const { app, runServer, closeServer } = require('../app');
const { TEST_DATABASE_URL } = require('../config/mainConfig');
const {secret} = require('../config/mainConfig');
const jwt = require('jsonwebtoken');
chai.use( chaiHttp );
Here is the test for the endpoint;
//test the session endpoints
it( 'should return a session with proper request', function(){
const user = new User({
name: 'random2',
email: 'random2#random.com',
password: 'Password2'
});
user.save( (err) => {
if (err){
console.log( err.message);
}
});
const token = jwt.sign({
id: user._id,
userName: user.name,
level: 0
}, secret, {
expiresIn: 60 * 60
});
console.log( "user id: ", user._id);
console.log( 'token is: ', token );
const practiceRequest = {
operation: "+",
number: "10", ///this will possible need to be sent as a number
min: "1",
max: "200"
};
return chai.request(app)
.post('/api/session')
.set('Authorization', 'Bearer ' + token)
.send( practiceRequest )
.then( (res) => {
res.should.have.status(201);
})
});
});
The two console.log statements confirm that the user is being created and has an _id property, and that a valid token is being
created (this was confirmed on jwt.io).
This is the code for the endpoint;
router.route("/session")
.post(passport.authenticate('jwt', { session: false }), jsonParser, ( req, res ) => {
console.log( req );
let practiceSession = [];
for ( let i = 0; i < req.body.number; i++ ){
let firstTerm = generateTerm( req.body.min, req.body.max );
let secondTerm = generateTerm( req.body.min, req.body.max );
const problem = {
operator: req.body.operation,
firstTerm,
secondTerm,
problem: `${ firstTerm } ${ req.body.operation } ${ secondTerm }`,
correctResponse: generateCorrectResponse( firstTerm, secondTerm, req.body.operation )
};
practiceSession.push( problem );
}
// save session into db sessions collection for use in the training-logic.js
Session
.create( {
userId: req.user._id,
problems: practiceSession
} )
.then(
session => res.status( 201 ).json( session) )
.catch( err => {
console.error( err );
res.status( 500 ).json( { message: 'Internal Server Error' } );
});
} );
The test of this endpoint fails with a 401 response and a simple Error: Unauthorized That is not a lot of information
and I don't know where to continue trouble shooting. My understanding is that this means the initial passport.authenticate
at the endpoint is not recognizing the token as valid, even though it has been confirmed as valid on the jwt.io site. Is there
additional information I should be including when generating the token? If so how?
I have looked at several other examples using passport; one,
two,
three but I did
not see how to apply any of these insights to my implementation.
Any help with this would be greatly appreciated. Thank you for your time.
UPDATE:
Based on the fact that a valid token is going up to the endpoint but it is still not being accepted I tried building a promise chain with an initial call to the user authentication endpoint and then used the token derived from there to test the session generation endpoint. This was the effort;
it( 'should return a session with proper request', function(){
let token;
return chai.request(app)
.post('/api/user/authenticate')
.send( {
email: 'random#random.com',
password: 'password2'
} )
.then( (res) => {
res.should.have.status(200);
res.should.be.json;
console.log( res.body );
token = res.body.token;
return token;
})
.catch( (err) => {
console.log( 'failed at user authentication' );
})
.then( ( err, data ) => {
console.log( 'token value is ', token );
chai.request( app )
.post( '/api/session' )
.set( 'Authorization', `${ token }` )
.send( {
operation: "+",
number: "10",
min: "1",
max: "200"
})
.then( res => {
console.log( 'second response is ', res );
res.should.have.status(201);
} )
.catch( err => {
console.log( 'second promise ', err.message );
})
})
});
It is still rejected as Unauthorized. Something is missing from the request being sent to the session endpoint from the test. The console.log( req ) in the session endpoint confirms that it is receiving an object that has a great deal of information added to it, compared to what is being sent from the promise chain in the test. I had to use the token variable in the outer scope to pass the value between the chai.request(app) commands. This is not the same data flow present in the working app. I am not sure how to test this; my understanding is that what I have tried so far does not give the endpoint enough data to validate the request.
Any help would be greatly appreciated. Thank you for your time.
SOLUTION
To follow up, a friend helped with this and gave me a solution that passed additional information back to the endpoint when
building the token. The final working model had a beforeEach() function that adds a dummy user to the test database, and then
assigns this user to a testUser variable in the outer scope, so it is accessible in the later test. In the actual test of the
endpoint this testUser variable is mapped to a full user schema and is used to build the token and test the endpoint. It works well since the endpoint has all the properties needed. Here is the code;
describe( 'End-point for practice session resources', function() {
let testUser;
let modelSession;
before( function() {
return runServer( TEST_DATABASE_URL );
});
beforeEach( function(done){
addUser()
.then( user => {
testUser = user;
done();
});
});
and the test;
it( 'should generate a session with the proper request (POST)', function(){
const token = jwt.sign({
id: testUser._id
}, secret, { expiresIn: 60 * 60 });
return chai.request( app )
.post( '/api/session' )
.set( 'Authorization', `Bearer ${ token }` )
.send( {
operation: "+",
number: "10",
min: "1",
max: "200"
})
.then( res => {
res.should.have.status(201);
} )
})
});
Hope this helps someone else down the road.

Supertest, test secure REST API

I am writing an integration test for a REST API protected by a jwt.
One API operation POST /user/token is returning a jwt given a username and a password and this token is then used for a list of operations such as:
GET /user/:id
Where the route is using jwt({secret: secret.secretToken}), so the token is included into the HTTP header Authorization.
When testing with supertest, I can have nested testing but I want to first get the token, then use this token for testing other operations.
POST /user/token => 12345
GET /user/:id, `Authorization Bearer 12345`
GET /user/:foo, `Authorization Bearer 12345`
How to avoid generating a new token for every operation testing (see below) but use only a single one generate by POST /user/token.
it('should get a valid token for user: user1', function(done) {
request(url)
.post('/user/token')
.send({ _id: user1._id, password: user1.password })
.expect(200) // created
.end(function(err, res) {
// test operation GET /user/:id
You want to perform single POST to /user/token and then use the token received in every test case? If so, then use the before hook of the test framework you are using (Mocha?) and store the token to a variable, e.g.
describe('My API tests', function() {
var token = null;
before(function(done) {
request(url)
.post('/user/token')
.send({ _id: user1._id, password: user1.password })
.end(function(err, res) {
token = res.body.token; // Or something
done();
});
});
it('should get a valid token for user: user1', function(done) {
request('/get/user')
.set('Authorization', 'Bearer ' + token)
.expect(200, done);
});
});
Need to set Authorization as 'Bearer ' + token
var token = null;
before(function(done) {
request(url)
.post('/user/token')
.send({ _id: user1._id, password: user1.password })
.end(function(err, res) {
token = res.body.token; // Or something
done();
});
});
it('should get a valid token for user: user1', function(done) {
request('/get/user')
.set('Authorization', 'Bearer ' + token)
.expect(200, done);
});

Resources