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

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

Related

What is the proper way to test routes secured with jwt token?

While the following test passes I feel I'm doing this wrong. Am I expected to log in every time i need to test a secure route? I've tried passing global vars around after i get the initial token but passing vars i'm finding extremely counter intuitive. Passing variables in a before() call presents me same issue as passing / accessing global vars inside nested promises.
describe('Users', function(done) {
var testToken = 'my-test-token'
it('logs in', function(done) { // <= Pass in done callback
var rT = 'tttttt'
chai.request(urlroot)
.post('/login')
.type('form')
.send({ email: 'test_user_1#this.com', password: '9999' })
.end(function(err, res) {
expect(res).to.have.status(200);
expect(res.body.token).to.be.a('string');
done()
});
});
it('gets all users', function(done) { // <= Pass in done callback
// console.log(urlroot + '/users');
chai.request(urlroot)
.post('/login')
.type('form')
.send({ email: 'test_user_1#this.com', password: '9999' })
.end(function(err, res) {
chai.request(urlapi)
.get('/users?secret_token='+res.body.token)
.end(function(err, res){
console.log('data', res.body);
// expect(res.body).to.be.json()
})
});
});
});
What I do is use before() method to call my authenticate service to get the token in the same way that the aplication would, and store into a variable.
Something like:
var token = "";
before(async () => {
//Get token
token = "Bearer " + await getToken();
});
Then, in every test you want to use the credentials use .set()
it('...', function (done) {
chai
.request(url)
.set("Authorization", token) //Call .set() before .get()
.get("/users")
//...
})

Testing JWT Authentication Using Mocha and Chai

I'm stuck writing a test for my get endpoint which requires a token of the admin to return a list of users.
Here is my user endpoint:
app.get("/users", (req,res) => {
const payload = req.payload
if (payload && payload.user === "admin") {
User.find({}, (err, users) => {
if(!err) {
res.status(200).send(users)
} else { res.status(500).send(err) }
})
} else { res.status(500).send("Authentication Error!)}
}
Here's my jwt middleware:
module.exports = {
validateToken: (req, res, next) => {
const authorizationHeader = req.headers.authorization;
let result;
if (authorizationHeader) {
const token = req.headers.authorization.split(" ")[1]; // Bearer <token>
const options = {
expiresIn: "2d",
issuer: "clint maruti"
};
try {
// verify makes sure that the token hasn't expired and has been issued by us
result = jwt.verify(token, process.env.JWT_SECRET, options);
// Let's pass back the decoded token to the request object
req.decoded = result;
// We call next to pass execution to the subsequent middleware
next();
} catch (err) {
// Throw an error just in case anything goes wrong with verification
throw new Error(err)
}
} else {
result = {
error: 'Authentication error. Token required.',
status: 401
}
res.status(401).send(result)
}
}
};
Here's my sample test:
let User = require("../models/users");
// Require dev dependencies
let chai = require("chai");
let chaiHttp = require("chai-http");
let app = require("../app");
let should = chai.should();
chai.use(chaiHttp);
let defaultUser = {
name: "admin",
password: "admin#123"
};
let token;
// parent block
describe("User", () => {
beforeEach(done => {
chai
.request(app)
.post("/users")
.send(defaultUser)
.end((err, res) => {
res.should.have.status(200);
done();
});
});
beforeEach(done => {
chai
.request(app)
.post("/login")
.send(defaultUser)
.end((err, res) => {
token = res.body.token;
res.should.have.status(200);
done();
});
});
afterEach(done => {
// After each test we truncate the database
User.remove({}, err => {
done();
});
});
describe("/get users", () => {
it("should fetch all users successfully", done => {
chai
.request(app)
.set("Authentication", token)
.get("/users")
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a("object");
res.body.should.have.property("users");
done();
});
});
});
});
Problem:
My test is giving me an assertion error 500 instead of 200 of the status code, I have written 2 beforeEach functions. One, to register the admin and the other one to Login the admin and get the token. I wonder if this is what is bringing the error? Please help
I found the answer here:
How to send Headers ('Authorization','Bearer token') in Mocha Test cases
You have to set { Authorization: "Bearer" + token } instead of "Authentication", token
You have to call .set after .get
describe("/get users", () => {
it("should fetch all users successfully", (done) => {
chai
.request(app)
.get("/users")
.set({ Authorization: `Bearer ${token}` })
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a("object");
res.body.should.have.property("users");
done();
});
});
});
chai-http has auth function to send the Authorization Bearer token.
Accroding to chai-http code on Github, token can be pass using:
.auth(accessToken, { type: 'bearer' })
An example provided on the similar Question:
https://stackoverflow.com/a/66106588/4067905

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

integration tests, can't return an array NodeJS/Mocha

Hey I want return an array in integration tests,
I have a function in which tables are retrieved. Function expect object req.user._id, so I create it, next I create integration test, but when i run I have return empty object, could someone tell me what I have to do to get returned array?
function :
.get('/boards-list', function (req, res) {
Board.find({ 'users': req.user._id })
.then((board) => {
res.json(board);
})
.catch((err) => {
res.status(404).json('Nie można pobrać tablic.')
})
})
mocha :
describe('/boards-list', () => {
it('it should GET all the boards', (done) => {
var req = {};
req.user = {};
req.user._id = "ObjectId('5a8db5d449c0572dbc60548c')";
chai.request(server)
.get('/boards-list')
.send(req)
.end((err, res) => {
console.log(res.body);
// res.should.have.status(200);
// res.body.should.be.a('array');
// res.body.length.should.be.eql(0);
done();
});
});
});
I think the problem is with the id you are passing:
req.user._id = "ObjectId('5a8db5d449c0572dbc60548c')";
Try to pass it like this:
req.user._id = "5a8db5d449c0572dbc60548c";

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/

Resources