From 82262344b84e6421e97d3be28211144ffd99a07c Mon Sep 17 00:00:00 2001 From: Mathanraj Date: Sun, 21 Jan 2024 02:06:19 +0530 Subject: [PATCH] Solve issue #8 : Added test for Auth routes --- server/app.js | 11 +- server/config/connect.js | 22 +-- server/controllers/auth.js | 244 ++++++++++++++------------ server/package.json | 6 +- server/tests/integration/auth.test.js | 125 +++++++++++++ 5 files changed, 276 insertions(+), 132 deletions(-) create mode 100644 server/tests/integration/auth.test.js diff --git a/server/app.js b/server/app.js index 12721c3..02de847 100644 --- a/server/app.js +++ b/server/app.js @@ -25,8 +25,11 @@ app.use(Routes); /** * connect to db then start server - */ -dbConnect(() => app.listen(process.env.PORT, () => - console.log(`Server is running on port ${process.env.PORT}`) -)) +// */ +dbConnect(() => { + app.listen(process.env.PORT, () => { + console.log(`Server is running on port ${process.env.PORT}`); + }); +}); +module.exports = app; diff --git a/server/config/connect.js b/server/config/connect.js index 0a33498..15a56a4 100644 --- a/server/config/connect.js +++ b/server/config/connect.js @@ -1,16 +1,16 @@ const mongoose = require("mongoose"); const dbConnect = async (callback) => { - try { - mongoose.set('strictQuery', false) - const connect = await mongoose.connect(process.env.MONGO_URL); - if (connect) { - console.log("DB is successfully connected"); - callback(); //start the server - } - } catch (error) { - console.error("Error connecting to the database:", error); + try { + mongoose.set("strictQuery", false); + const connect = await mongoose.connect(process.env.MONGO_URL); + if (connect) { + console.log("DB is successfully connected"); + callback(); //start the server } -} + } catch (error) { + console.error("Error connecting to the database:", error); + } +}; -module.exports = dbConnect; \ No newline at end of file +module.exports = dbConnect; diff --git a/server/controllers/auth.js b/server/controllers/auth.js index 2d6d28c..2f82efc 100644 --- a/server/controllers/auth.js +++ b/server/controllers/auth.js @@ -1,101 +1,110 @@ -const User = require('../model/user.js') -const bcrypt = require("bcrypt") -const jwt = require('jsonwebtoken') // authentication, login , authorization - is he an admin or not? -const passwordReset = require('../model/passwordReset.js'); -const mailer = require('../helper/mailer'); -require('dotenv').config() +const User = require("../model/user.js"); +const bcrypt = require("bcrypt"); +const jwt = require("jsonwebtoken"); // authentication, login , authorization - is he an admin or not? +const passwordReset = require("../model/passwordReset.js"); +const mailer = require("../helper/mailer"); +require("dotenv").config(); // register/signup exports.register = async (req, res) => { - try { - const isExisting = await User.findOne({ email: req.body.email }) - if (isExisting) { - throw new Error("Already an account with this email. Try a new one!") - } - const hashedPassword = await bcrypt.hash(req.body.password, 10); - const newUser = await User.create({ ...req.body, password: hashedPassword }) - const { password, ...others } = newUser._doc - const token = jwt.sign({ id: newUser._id, isAdmin: newUser.isAdmin }, process.env.JWT_SECRET, { expiresIn: "5h" }) - - return res.status(201).json({ others, token }) - } catch (error) { - return res.status(500).json(error.message) + try { + const isExisting = await User.findOne({ email: req.body.email }); + if (isExisting) { + throw new Error("Already an account with this email. Try a new one!"); } -} + const hashedPassword = await bcrypt.hash(req.body.password, 10); + const newUser = await User.create({ + ...req.body, + password: hashedPassword, + }); + const { password, ...others } = newUser._doc; + const token = jwt.sign( + { id: newUser._id, isAdmin: newUser.isAdmin }, + process.env.JWT_SECRET, + { expiresIn: "5h" } + ); + + return res.status(201).json({ others, token }); + } catch (error) { + return res.status(500).json(error.message); + } +}; // login exports.login = async (req, res) => { - try { - const user = await User.findOne({ email: req.body.email }) - if (!user) { - throw new Error("User credentials are wrong!") - } + try { + const user = await User.findOne({ email: req.body.email }); + if (!user) { + throw new Error("User credentials are wrong!"); + } - const comparePass = await bcrypt.compare(req.body.password, user.password) - if (!comparePass) { - throw new Error("User credentials are wrong!") - } + const comparePass = await bcrypt.compare(req.body.password, user.password); + if (!comparePass) { + throw new Error("User credentials are wrong!"); + } - const { password, ...others } = user._doc - const token = jwt.sign({ id: user._id, isAdmin: user.isAdmin }, process.env.JWT_SECRET, { expiresIn: "5h" }) + const { password, ...others } = user._doc; + const token = jwt.sign( + { id: user._id, isAdmin: user.isAdmin }, + process.env.JWT_SECRET, + { expiresIn: "5h" } + ); - return res.status(200).json({ others, token }) - } catch (error) { - return res.status(500).json(error.message) - } -} + return res.status(200).json({ others, token }); + } catch (error) { + return res.status(500).json(error.message); + } +}; //forgot-password -exports.forgotPassword = async(req,res)=>{ - try { - console.log("Forgot password request body: ",req.body); - const { email } = req.body; - const userData = await User.findOne({email}); - console.log("Email: ", email); - console.log("User data: ", userData); - if(!userData) - { - return res.status(400).json({ - success: false, - msg: "Email doesn't exists!", - }); - } - const randomString = Math.random().toString(36).slice(-8); - const msg= `

Hi ${userData.username}, please click here to reset your password.

` - const PasswordReset = await passwordReset({ - user_id: userData._id, - token: randomString - }) - await PasswordReset.save(); - mailer.sendMail(userData.email, "Reset Password", msg); - return res.status(201).json({ - success: true, - msg: 'Reset Password Link sent to your mail, please check!' - }) - } catch (error) { - return res.status(400).json({ - success: false, - msg: error.message - }); +exports.forgotPassword = async (req, res) => { + try { + console.log("Forgot password request body: ", req.body); + const { email } = req.body; + const userData = await User.findOne({ email }); + console.log("Email: ", email); + console.log("User data: ", userData); + if (!userData) { + return res.status(400).json({ + success: false, + msg: "Email doesn't exists!", + }); } -} + const randomString = Math.random().toString(36).slice(-8); + const msg = `

Hi ${userData.username}, please click here to reset your password.

`; + const PasswordReset = await passwordReset({ + user_id: userData._id, + token: randomString, + }); + await PasswordReset.save(); + mailer.sendMail(userData.email, "Reset Password", msg); + return res.status(201).json({ + success: true, + msg: "Reset Password Link sent to your mail, please check!", + }); + } catch (error) { + return res.status(400).json({ + success: false, + msg: error.message, + }); + } +}; // reset-password -exports.resetPassword = async(req,res)=>{ - try { - const {token} = req.query.token; - console.log("Token: ",token); - const resetData = await passwordReset.findOne({token: req.query.token}); - console.log("Reset data: ",resetData); - if(!resetData) - { - return res.status(404) - } - return res.status(200).json({resetData}) - } catch (error) { - return res.status(404).json(error.message) +exports.resetPassword = async (req, res) => { + try { + const { token } = req.query; + console.log("Token: ", token); + const resetData = await passwordReset.findOne({ token: req.query.token }); + console.log("Reset data: ", resetData); + if (!resetData) { + return res.status(404).send("invalid token"); } -} + return res.status(200).json({ resetData }); + } catch (error) { + return res.status(404).json(error.message); + } +}; // exports.updatePassword = async(req,res)=> { // try { @@ -104,7 +113,7 @@ exports.resetPassword = async(req,res)=>{ // const {c_password}=req.body.c_password; // console.log("Confirm Password: ",c_password); - + // if(password!=c_password) // { // return res.status(401).json({msg: "Passwords aren't matching"}) @@ -125,38 +134,41 @@ exports.resetPassword = async(req,res)=>{ // } catch (error) { // console.log('Error in updating the password : ', error); // return res.status(404).json({msg: "Error"}); -// } +// } // } -exports.updatePassword = async(req,res)=> { - try { - const {password,c_password} = req.body; - let {token}= req.query - token = decodeURIComponent(token) - console.log(token); - console.log(password) - console.log(c_password); - // const resetData = await passwordReset.findOne({user_id}); - const resetData = await passwordReset.findOne({token: token}); - console.log("Reset Data: ",resetData); - // if(password!=c_password) - // { - // return res.status(401).json({msg: "Passwords aren't matching"}) - // } - const hashedPassword=await bcrypt.hash(c_password,10); - await User.findByIdAndUpdate({_id: resetData.user_id},{ - $set:{ - password: hashedPassword - } - }) - const userData = await User.findById({_id: resetData.user_id}); - console.log("User Data: ",userData); - const msg= `

Dear ${userData.username}, This is to confirm that the password for your account has been successfully changed.

` - mailer.sendMail(userData.email,"Password updated successful",msg); - await passwordReset.deleteMany({_id: resetData.user_id}) - return res.status(200).json({ msg: "Password updated successfully" }); - } catch (error) { - console.log('Error in updating the password : ', error); - return res.status(404).json({msg: "Error"}); - } -} \ No newline at end of file +exports.updatePassword = async (req, res) => { + try { + const { password, c_password } = req.body; + let { token } = req.query; + token = decodeURIComponent(token); + console.log(token); + console.log(password); + console.log(c_password); + // const resetData = await passwordReset.findOne({user_id}); + const resetData = await passwordReset.findOne({ token: token }); + console.log("Reset Data: ", resetData); + // if(password!=c_password) + // { + // return res.status(401).json({msg: "Passwords aren't matching"}) + // } + const hashedPassword = await bcrypt.hash(c_password, 10); + await User.findByIdAndUpdate( + { _id: resetData.user_id }, + { + $set: { + password: hashedPassword, + }, + } + ); + const userData = await User.findById({ _id: resetData.user_id }); + console.log("User Data: ", userData); + const msg = `

Dear ${userData.username}, This is to confirm that the password for your account has been successfully changed.

`; + mailer.sendMail(userData.email, "Password updated successful", msg); + await passwordReset.deleteMany({ _id: resetData.user_id }); + return res.status(200).json({ msg: "Password updated successfully" }); + } catch (error) { + console.log("Error in updating the password : ", error); + return res.status(404).json({ msg: "Error" }); + } +}; diff --git a/server/package.json b/server/package.json index fd2a673..10303d2 100644 --- a/server/package.json +++ b/server/package.json @@ -5,7 +5,7 @@ "main": "app.js", "scripts": { "start": "nodemon app.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest --watchAll --verbose" }, "author": "Anup Khismatrao", "license": "MIT", @@ -14,11 +14,15 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "jest": "^29.7.0", "jsonwebtoken": "^9.0.2", "mongoose": "^7.4.1", "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.8", "nodemon": "^3.0.1" + }, + "devDependencies": { + "supertest": "^6.3.4" } } diff --git a/server/tests/integration/auth.test.js b/server/tests/integration/auth.test.js new file mode 100644 index 0000000..84b08e9 --- /dev/null +++ b/server/tests/integration/auth.test.js @@ -0,0 +1,125 @@ +const request = require("supertest"); +// let server; +let server = require("../../app"); +const user = require("../../model/user"); +const passwordReset = require("../../model/passwordReset"); +describe("/auth", () => { + describe("/register", () => { + it("should return a statuscode of 201 if new user", async () => { + await user.deleteOne({ email: "ccccccccccccccccccccc" }); + const result = await request(server).post("/auth/register").send({ + email: "ccccccccccccccccccccc", + username: "dddddcccccddddddddddd", + phone: "1234565567899867", + password: "cccccccccccccc", + isAdmin: false, + }); + expect(result.statusCode).toBe(201); + }); + + it("should return a statuscode of 500 user already exists", async () => { + const result = await request(server).post("/auth/register").send({ + email: "dddddddddddddddddddddd", + username: "dddddddddddddddd", + phone: "123456556789", + password: "ddddddddddddddd", + isAdmin: false, + }); + expect(result.statusCode).toBe(500); + }); + }); + + describe("/login", () => { + it("should log in a user and return a token", async () => { + const loginResult = await request(server).post("/auth/login").send({ + email: "ccccccccccccccccccccc", + password: "cccccccccccccc", + }); + + expect(loginResult.statusCode).toBe(200); + }); + + it("should return a status code 500 for incorrect credentials", async () => { + const result = await request(server).post("/auth/login").send({ + email: "nonexistentuser@example.com", + password: "incorrectpassword", + }); + + expect(result.statusCode).toBe(500); + expect(result.body).toBe("User credentials are wrong!"); + }); + }); + + describe("/reset-password", () => { + it("should return reset data for a valid token", async () => { + const { token } = await passwordReset.findOne({}); + const result = await request(server).get( + `/auth/reset-password?token=${token}` + ); + + expect(result.statusCode).toBe(200); + }); + + it("should return 404 for an invalid token", async () => { + const invalidToken = "invalid_token"; + const result = await request(server).get( + `/auth/reset-password?token=${invalidToken}` + ); + expect(result.statusCode).toBe(404); + }); + + // Add more test cases as needed + }); + + describe("/forgot-password", () => { + it("should send a reset password link for a valid email", async () => { + // Assuming you have a user document with a valid email in your database + + const result = await request(server).post("/auth/forgot-password").send({ + email: "dddddddddddddddddddddd", + }); + + expect(result.statusCode).toBe(201); + // Add more assertions as needed + }); + + it("should return 400 for an invalid email", async () => { + const result = await request(server).post("/auth/forgot-password").send({ + email: "zzzzzzz", + }); + + expect(result.statusCode).toBe(400); + // Add more assertions as needed + }); + + // Add more test cases as needed + }); + + describe("/reset-password", () => { + it("should update the user's password with a valid token and matching passwords", async () => { + const { token } = await passwordReset.findOne({}); + + const result = await request(server) + .post(`/auth/reset-password?token=${token}`) + .send({ + password: "ooooooccoo", + c_password: "nnnnddnnnn", + }); + + expect(result.statusCode).toBe(200); + }); + + it("should return 404 for an invalid token", async () => { + const invalidToken = "invalid_token"; + + const result = await request(server) + .post(`/auth/reset-password?token=${invalidToken}`) + .send({ + password: "new_password", + c_password: "new_password", + }); + + expect(result.statusCode).toBe(404); + }); + }); +});