In this challenge you will create a tests which verify the login process.
To test the login process, you first need to seed the database a user, then POST a username and password to the endpoint. The endpoint will return a JWT that you must verify using your JWT_SECRET.
To get started, create a /test/login.test.js
file. And add the require packages and setup to the start of the file.
const app = require('../server');
const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
const { TEST_MONGODB_URI, JWT_SECRET } = require('../config');
const User = require('../models/user');
const expect = chai.expect;
chai.use(chaiHttp);
Note the additional of the JWT_SECRET
. You will need this to verify the JWT returned from the /login
endpoint.
Next, you will create a describe block with Mocha before
, beforeEach
, afterEach
and after
hooks. And create fullname
, username
and password
variables with sample data which you will insert in to the DB and use to validate the login process.
The code in the hooks should look familiar, except for the beforeEach
hook which hashes the password before inserting the user into the database.
describe.only('Noteful API - Login', function () {
const fullname = 'Example User';
const username = 'exampleUser';
const password = 'password';
before(function () {
return mongoose.connect(TEST_MONGODB_URI)
.then(() => mongoose.connection.db.dropDatabase());
});
beforeEach(function () {
return User.hashPassword(password)
.then(digest => User.create({ fullname, username, password: digest }));
});
afterEach(function () {
return mongoose.connection.db.dropDatabase();
});
after(function () {
return mongoose.disconnect();
});
// TESTS GO HERE
});
Add the following test to your file.
The test POSTs the username
and password
to the endpoint. The endpoint should respond with a JWT which is then verified. Finally, the test compares the payload with the known user info. The payload should not contain a password
property, and the username
and fullname
should match the example user.
it('Should return a valid auth token', function () {
return chai.request(app)
.post('/api/login')
.send({ username, password })
.then(res => {
expect(res).to.have.status(200);
expect(res.body).to.be.an('object');
expect(res.body.authToken).to.be.a('string');
const payload = jwt.verify(res.body.authToken, JWT_SECRET);
expect(payload.user).to.not.have.property('password');
expect(payload.user.username).to.equal(username);
expect(payload.user.fullname).to.equal(fullname);
});
});
Now that you have a tested the positive a.k.a. "happy path" case, you need to test the negative (aka sad path), your challenge is to create tests for the negative a.k.a. "sad path" scenarios
it('Should reject requests with no credentials');
it('Should reject requests with incorrect usernames');
it('Should reject requests with incorrect passwords');
Finally, we're going to test the /api/refresh
endpoint. Here you'll need to create a JWT and add it to the Authorization header as part of the request.
Add another describe
block with the following code:
describe('/api/refresh', function () {
it('should return a valid auth token with a newer expiry date', function () {
const user = { username, fullname };
const token = jwt.sign({ user }, JWT_SECRET, { subject: username, expiresIn: '1m' });
const decoded = jwt.decode(token);
return chai.request(app)
.post('/api/refresh')
.set('Authorization', `Bearer ${token}`)
.then(res => {
expect(res).to.have.status(200);
expect(res.body).to.been.a('object');
const authToken = res.body.authToken;
expect(authToken).to.be.a('string');
const payload = jwt.verify(authToken, JWT_SECRET);
expect(payload.user).to.deep.equal({ username, fullname });
expect(payload.exp).to.be.greaterThan(decoded.exp);
});
});
});
Just like the /login
tests, now that you have a tested the positive a.k.a. "happy path" case, your challenge is to create tests for the negative a.k.a. "sad path" scenarios
it('should reject requests with no credentials');
it('should reject requests with an invalid token');
it('should reject requests with an expired token');