I'm getting a 404 HTTP error for the second test (should return 200 on sign-in and login pages) when testing my app with the code below :
const request = require('supertest');
const express = require('express');
const app = require('../app');
// test jwt middleware
describe('jwt middleware', () => {
it('should return 401 if no token provided', async () => {
const res = await request(app).get('/income/category/')
expect(res.statusCode).toBe(401)
});
it('should return 200 on sign-in and login pages', async () => {
let res = await request(app).post('/user/sign-in/').send({username: "test", password: "test"})
expect(res.statusCode).toBe(200)
res = await request(app).post('/user/login/').send({username: "test", password: "test"})
expect(res.statusCode).toBe(200)
})
});
The thing I don't understand is that the app work correctly if I run it with *npm run dev *but when I run npm run test which run *"export NODE_ENV=test && jest --forceExit --runInBand" *it's broken.
Here is the route code for the user/sign-in and user/log-in :
const express = require('express');
const router = express.Router();
const {getDB} = require("../config/database");
const {hash, compare} = require("bcrypt");
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
// get config vars
dotenv.config();
router.post('/sign-in', async (req, res) => {
const db = getDB();
// check username and password are provided
if (!req.body.username || !req.body.password) {
return res.status(400).json({message: "Username and password required."})
}
// check user doesn't already exist
console.log(db)
const user = await db.collection('user').findOne({username: req.body.username})
if (user) {
return res.status(409).json({message: "User already exists."})
}
try {
// hash password
const hashedPassword = await hash(req.body.password, 10)
// insert user into database
await db.collection('user').insertOne({
username: req.body.username,
password: hashedPassword
})
} catch (e) {
return res.status(500).json({message: "Error creating user."})
}
// return response
res.json({message: "User created."})
});
router.post('/login', async (req, res) => {
const db = getDB();
try {
/*
Check if the user exists in the database.
If the user doesn't exist, return a 404 error
*/
const user = await db.collection('user').findOne({username: req.body.username});
if (!user) {
return res.status(404).send('Cannot find user');
}
// Use bcrypt to compare the incoming password with the hashed password in the database
if (await compare(req.body.password, user.password)) {
res.json({token: jwt.sign({id: user['_id']}, process.env.TOKEN_SECRET, {expiresIn: '1800s'})});
} else {
res.json({message: 'Incorrect password'});
}
} catch (e) {
res.status(500).send();
}
});
module.exports = router;
I thought the problem was a wrong URL, but I get into my JWT middleware and the request URL is correct, so it returns next() :
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
// get config vars
dotenv.config();
module.exports = (req, res, next) => {
// don't check for token on sign-in or login
if (req.url === '/user/sign-in/' || req.url === '/user/login/') {
return next()
}
// The user must be logged in to access any other route
if (!req.headers['authorization']) {
return res.status(401).json({message: "Unauthorized"})
}
// check token is valid
const jwtToken = req.headers['authorization'];
jwt.verify(jwtToken, process.env.TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(401)
req.userId = user.id
next()
})
}