Use JWT token in multiple test cases mocha node-js - 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;
});

Related

Mocha and chai test for registration should not insert into DB

I am writing tests for an API built with Node and Express. I am trying to test the registration route using mocha and chai. But the test data for registration inserts into the database, which I don't want.
Is it possible to test registration and make sure it works without the dummy data inserting into the database?
Or better, how can I hook up the testing to a different database?
Thank you.
Just incase, here is the code for my test
describe('AUTH ROUTES', () => {
describe('POST /api/v1/auth/register', () => {
const correctUser = {
firstName: 'test',
lastName: 'test',
email: 'test#test.com',
password: '111'
};
const wrongUser = {
lastName: 'test',
password: '111'
};
it('It should REGISTER a user when complete detail is received', (done) => {
chai
.request(server)
.post('/api/v1/auth/register')
.send(correctUser)
.end((err, res) => {
res.should.have.status(SUCCESS_CODE);
res.body.should.be.a('object');
res.body.should.have.property('success').eq(true);
done();
});
});
it('It should NOT REGISTER a user when incomplete detail is received', (done) => {
chai
.request(server)
.post('/api/v1/auth/register')
.send(wrongUser)
.end((err, res) => {
res.should.have.status(BAD_REQUEST.code);
res.body.should.be.a('object');
res.body.should.have.property('errors');
done();
});
});
});
You should use afterEach function to drop the table after you run your beforeEach test.
You can stub every response given by your controller.

Chai-http is not checking second assertion when one inside one request

I am trying to get my token variable from /signing to provide it to the name change route. But the assertion is not always triggering. Can there be any better way to do this? Can I use async-await to solve this problem, if so, how?
describe("setName", function (done) {
it("/POST user setName", function (done) {
Users.remove({}, (err) => {
console.log(chalk.bgBlue(`Removing User`));
// done();
});
let user = {
"email": "tiwari.ai.harsh#gmail.com",
"password": "password",
"name": "Harsh Tiwari"
}
var requester = chai.request(app).keepOpen()
requester.post("/api/users/signin").send({
user
}).end((err_signin, res_signin) => {
let token = res_signin.body.user.token;
let name = "Name Changed"
requester.post("/api/users/setName").set({ authorization: `Token ${token}` }).send({
name
}).end((err, res) => {
res.should.have.status(200); <--------------------------- This is not working
});
done()
});
});
});
The current code will execute done before the requester.post("/api/users/setName") finish because it is an async execution.
To solve the issue, the done() should be specified after res.should.have.status(200);
describe('setName', function (done) {
// NOTE: I also moved remove function here to ensure user is removed correctly
before(function(done) {
Users.remove({}, (err) => {
console.log(chalk.bgBlue(`Removing User`));
done(); // NOTE: also specify done to tell mocha that async execution is finished
});
})
it('/POST user setName', function (done) {
let user = {
email: 'tiwari.ai.harsh#gmail.com',
password: 'password',
name: 'Harsh Tiwari',
};
var requester = chai.request(app).keepOpen();
requester
.post('/api/users/signin')
.send({
user,
})
.end((err_signin, res_signin) => {
let token = res_signin.body.user.token;
let name = 'Name Changed';
requester
.post('/api/users/setName')
.set({ authorization: `Token ${token}` })
.send({
name,
})
.end((err, res) => {
res.should.have.status(200);
done(); // NOTE: move here
});
});
});
});

mocha, chai testing for post in nodejs

I am new to unit testing in node.js with sequelize.js. I followed this tutorial to implement the api. It is working fine and I need to test it for unit testing.
First I tried to test post operation for User class. Following code is to be tested using mocha.
// create a user
app.post('/api/users', (req, res) => {
User.create(req.body)
.then(user => res.json(user))
})
My attempt is as below.
var index = require('../index');
describe('POST testing on user', function () {
it('should add a row', function (done) {
index.post('/api/users').send({ 'name': 'he' })
.end(function (err, res) {
chai.expect(res.status).to.equal(200);
done();
})
});
});
Then it will give this error saying index.post is not a function. Where should I get wrong and how can I correct it to execute the test case.
Your logic is quite wrong. It should be:
describe('/POST Create User', () => {
it('Create User Testing', (done) => {
let user = {
'name': 'he'
}
chai.request('http://localhost:3000')
.post('/api/users')
.send(user)
.end((err, res) => {
});
});
});
});

Scopes & Closures in Mocha/Chai Assertions

I'm writing some tests for an express app and I am wondering how to properly access a variable in one assertion block from another. The variable I am trying to access is this.token = res.body.token
Whenever I try to access it, it comes up undefined (other than when accessing it within the beforeEach block). How can I access this variable? I need to use the token to set the headers in my test for my POST request.
Code:
describe('CRUD: tests the GET & POST routes', () => {
beforeEach(done => {
chai.request('localhost:3000')
.post('/app/signup')
.send({ email: 'meow#test.com', password: 'testpass' })
.end((err, res) => {
if (err) return console.log(err);
this.token = res.body.token; // this variable holds a token when accessed within this scope (tested it with node debugger)
done();
});
});
it('should create with a new cat with a POST request', (done) => {
chai.request('localhost:3000')
.post('/app/cats')
.set('token', this.token) // when accessed here, it is undefined...
.send({ username: 'cat_user' })
.end((err, res) => {
expect(err).to.eql(null);
expect(res).to.have.status(200);
expect(res.body.name).to.eql('test cat');
expect(res.body).to.have.property('_id');
done();
});
});
EDIT: Here is a screenshot of my terminal in node debug mode. As you can see, when it hits the first debugger break and _token is accessed, it contains the token. In the next debugger break, however, it comes up empty... (maybe that means something else in the debugger?)
You can move your variable to the scope of your describe.
describe('CRUD: tests the GET & POST routes', () => {
let _token;
beforeEach(done => {
chai.request('localhost:3000')
.post('/app/signup')
.send({ email: 'meow#test.com', password: 'testpass' })
.end((err, res) => {
if (err) return console.log(err);
_token = res.body.token; // this variable holds a token when accessed within this scope (tested it with node debugger)
done();
});
});
it('should create with a new cat with a POST request', (done) => {
chai.request('localhost:3000')
.post('/app/cats')
.set('token', _token) // when accessed here, it is undefined...
.send({ username: 'cat_user' })
.end((err, res) => {
expect(err).to.eql(null);
expect(res).to.have.status(200);
expect(res.body.name).to.eql('test cat');
expect(res.body).to.have.property('_id');
done();
});
});
You should read this to understand this: http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/

Why am I getting a 401 response in my tests?

I am trying to test a route with authentication in my Node / Express / Mongoose back-end.
Here's the test file
var should = require('should');
var _ = require('lodash');
var async = require('async');
var app = require('../../../../app');
var request = require('supertest');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Firm = mongoose.model('Firm');
var firm, user, userPassword, createdFirm, loggedInUser;
describe('GET /api/firms', function(){
beforeEach(function (done) {
firm = new Firm({
company: 'My test company',
corporateMail: 'test.com'
});
userPassword = 'password';
user = new User({
fistname: 'Fake User',
lastname: 'Fake User',
email: 'test#test.com',
job: 'Partner',
firmName:firm.company,
password:userPassword,
isActivated:true,
_firmId:firm._id
});
function createFirm(cb){
request(app)
.post('/api/firms')
.send(firm)
.expect(201)
.end(function(err, res){
if ( err ) throw err;
createdFirm = res.body;
cb();
});
}
function createUser(cb){
request(app)
.post('/api/common/users')
.send(user)
.expect(200)
.end(function(err, res){
createdUser = res.body;
if ( err ) throw err;
cb();
});
};
async.series([function(cb){
createFirm(cb);
}, function(cb){
createUser(cb);
}], done);
});
afterEach(function (done) {
firm.remove();
user.remove();
done();
});
it('should respond with 401 error', function(done) {
request(app)
.get('/api/firms')
.expect(401)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
it('should login', function(done) {
request(app)
.post('/auth/local')
.send({email:user.email, password:user.password})
.expect(200)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
it('should respond with 200 after login', function(done) {
request(app)
.get('/api/firms')
.expect(200)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
});
In the workflow the firm object is created first and then returns its Id so I can create the user with the firmId as a reference.
I would like to test the /api/firms route after the user is authenticated but in spite of my various attempts (using superagent, logging in the before section) I always get a 401 response in the last should section instead of an expected 200.
Actually the important thing to keep in mind is, as KJ3 said, how the authentication is set up. In my case I forgot to mention that I was using jwt. The way it works is the following, you supply a username and a password and the server returns a token created with jwt.
So it makes sense to send the token back for each request in the tests.
The way to achieve this is first by storing the token after authentication in the before section
function createUser(cb){
request(app)
.post('/api/users')
.send(user)
.expect(200)
.end(function(err, res){
if ( err ) throw err;
authToken = res.body.token;
cb();
});
};
Then by adding .set in the request with the token in the correct format ('Bearer ' + token , which is defined in the authentication service):
it('should respond with 200', function(done) {
var authToken = 'Bearer ' + createdUser.token;
request(app)
.get('/api/firms')
.set('Authorization', authToken)
.expect(200)
.end(function(err, res) {
if (err) return done(err);
done();
});
});
In the case the test sends a 200 back, which is expected and sends a 401 if the .set(...) is commented out.
Good news is that this is achieved with supertest, so no need to add anything, less good news is that you need to add the .set(...) to each test request.
If you were to go through the last 2 tests in a browser, depending on how you have it setup, yes it would work thanks to cookies and sessions, but here the /api/firms test is independent of the auth/local test. So a 401 is the correct response.
It really depends on how your auth is setup, but you need to authenticate on the /api/firms test too. Either by sending the credentials again (every single one of my mocha tests authenticates each time) or implement sessions into the tests, see this SO post for some direction.

Resources