From 9db1bb3c9df3399e6d8e5ab99cc343b9780ef55d Mon Sep 17 00:00:00 2001 From: Sean Date: Sat, 10 Aug 2024 07:43:11 -0400 Subject: [PATCH 1/3] CHE-201 Initial tests written --- .../getUserById/getUserById.test.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 server/controllers/userController/getUserById/getUserById.test.ts diff --git a/server/controllers/userController/getUserById/getUserById.test.ts b/server/controllers/userController/getUserById/getUserById.test.ts new file mode 100644 index 0000000..377ec9c --- /dev/null +++ b/server/controllers/userController/getUserById/getUserById.test.ts @@ -0,0 +1,59 @@ +import app from '../../../app'; +import request, { Response } from 'supertest'; +import User from '../../../models/userModel'; +import { IUser } from '../../../types/user'; + +const testUserId = 'testUserId123'; +const invalidUserId = 'invalidUserId123'; +const nonExistentUserId = '5f8f8c44b54764421b7156c4'; + +const createUser = async () => { + const user = await User.create({ + _id: testUserId, + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@codehammers.com', + password: 'password123', + }); + return user; +}; + +describe('Tests for userController.getUserById', () => { + const baseUrl = '/api/users'; + + describe('Get User By Id Failure Tests', () => { + beforeEach(async () => { + await User.deleteMany(); + }); + + it('🧪 Fails if userId is invalid', async () => { + const response = await request(app).get(`${baseUrl}/${invalidUserId}`).send(); + + expect(response.status).toEqual(401); + expect(response.body.msg).toEqual('User not found!'); + }); + + it('🧪 Fails if user is not found', async () => { + const response = await request(app).get(`${baseUrl}/${nonExistentUserId}`).send(); + + expect(response.status).toEqual(401); + expect(response.body.msg).toEqual('User not found!'); + }); + }); + + describe('Get User By Id Success Tests', () => { + let successResponse: Response; + + beforeEach(async () => { + await User.deleteMany(); + await createUser(); + successResponse = await request(app).get(`${baseUrl}/${testUserId}`).send(); + }); + + it('🧪 Retrieves the user successfully with a 200 status', async () => { + expect(successResponse.status).toEqual(200); + expect(successResponse.body._id).toEqual(testUserId); + expect(successResponse.body.email).toEqual('john.doe@codehammers.com'); + }); + }); +}); From a9b6aa97690103a09da1fb4b375c2db8e66e8a2a Mon Sep 17 00:00:00 2001 From: Sean Date: Sat, 10 Aug 2024 08:40:26 -0400 Subject: [PATCH 2/3] CHE-201 Refactored tests to account for protect middleware and added userId validation to getUserById --- .../getUserById/getUserById.test.ts | 46 +++++++++++++------ .../userController/getUserById/getUserById.ts | 5 +- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/server/controllers/userController/getUserById/getUserById.test.ts b/server/controllers/userController/getUserById/getUserById.test.ts index 377ec9c..a1a9965 100644 --- a/server/controllers/userController/getUserById/getUserById.test.ts +++ b/server/controllers/userController/getUserById/getUserById.test.ts @@ -1,15 +1,14 @@ import app from '../../../app'; import request, { Response } from 'supertest'; import User from '../../../models/userModel'; -import { IUser } from '../../../types/user'; -const testUserId = 'testUserId123'; const invalidUserId = 'invalidUserId123'; const nonExistentUserId = '5f8f8c44b54764421b7156c4'; +const testEmail = 'john.doe@codehammers.com'; +const testPassword = 'password123'; const createUser = async () => { const user = await User.create({ - _id: testUserId, firstName: 'John', lastName: 'Doe', email: 'john.doe@codehammers.com', @@ -18,23 +17,40 @@ const createUser = async () => { return user; }; +const loginAndGetCookie = async () => { + const response = await request(app) + .post('/api/users/login') + .send({ email: testEmail, password: testPassword }); + return response.headers['set-cookie']; +}; + describe('Tests for userController.getUserById', () => { const baseUrl = '/api/users'; describe('Get User By Id Failure Tests', () => { + let authCookie: string; + beforeEach(async () => { await User.deleteMany(); + await createUser(); + authCookie = await loginAndGetCookie(); }); it('🧪 Fails if userId is invalid', async () => { - const response = await request(app).get(`${baseUrl}/${invalidUserId}`).send(); + const response = await request(app) + .get(`${baseUrl}/${invalidUserId}`) + .set('Cookie', authCookie) + .send(); - expect(response.status).toEqual(401); - expect(response.body.msg).toEqual('User not found!'); + expect(response.status).toEqual(400); + expect(response.body.msg).toEqual('Invalid user ID format'); }); it('🧪 Fails if user is not found', async () => { - const response = await request(app).get(`${baseUrl}/${nonExistentUserId}`).send(); + const response = await request(app) + .get(`${baseUrl}/${nonExistentUserId}`) + .set('Cookie', authCookie) + .send(); expect(response.status).toEqual(401); expect(response.body.msg).toEqual('User not found!'); @@ -43,16 +59,18 @@ describe('Tests for userController.getUserById', () => { describe('Get User By Id Success Tests', () => { let successResponse: Response; - - beforeEach(async () => { - await User.deleteMany(); - await createUser(); - successResponse = await request(app).get(`${baseUrl}/${testUserId}`).send(); - }); + let authCookie: string; it('🧪 Retrieves the user successfully with a 200 status', async () => { + await User.deleteMany(); + const user = await createUser(); + authCookie = await loginAndGetCookie(); + successResponse = await request(app) + .get(`${baseUrl}/${user.id}`) + .set('Cookie', authCookie) + .send(); expect(successResponse.status).toEqual(200); - expect(successResponse.body._id).toEqual(testUserId); + expect(successResponse.body._id).toEqual(user.id); expect(successResponse.body.email).toEqual('john.doe@codehammers.com'); }); }); diff --git a/server/controllers/userController/getUserById/getUserById.ts b/server/controllers/userController/getUserById/getUserById.ts index 47bd5aa..33218e8 100644 --- a/server/controllers/userController/getUserById/getUserById.ts +++ b/server/controllers/userController/getUserById/getUserById.ts @@ -1,3 +1,4 @@ +import mongoose from 'mongoose'; import User from '../../../models/userModel'; import { Request, Response, NextFunction } from 'express'; import { UserType } from '../../../types/user'; @@ -7,7 +8,9 @@ import { UserType } from '../../../types/user'; // ACCESS Private const getUserById = async (req: Request, res: Response, next: NextFunction) => { const { userId } = req.params; - + if (!mongoose.Types.ObjectId.isValid(userId)) { + return res.status(400).json({ msg: 'Invalid user ID format' }); + } try { const user: UserType | null = await User.findOne({ _id: userId }); From 0b3499ce99be4f874100c5362c453e74832fee3c Mon Sep 17 00:00:00 2001 From: Sean Date: Sat, 10 Aug 2024 09:55:22 -0400 Subject: [PATCH 3/3] CHE-201 Refactord target and test files to use custom error handlers --- .../getUserById/getUserById.test.ts | 7 ++--- .../userController/getUserById/getUserById.ts | 26 +++++++------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/server/controllers/userController/getUserById/getUserById.test.ts b/server/controllers/userController/getUserById/getUserById.test.ts index a1a9965..ee29c77 100644 --- a/server/controllers/userController/getUserById/getUserById.test.ts +++ b/server/controllers/userController/getUserById/getUserById.test.ts @@ -43,7 +43,8 @@ describe('Tests for userController.getUserById', () => { .send(); expect(response.status).toEqual(400); - expect(response.body.msg).toEqual('Invalid user ID format'); + expect(response.body[0].message).toEqual('Invalid user ID format'); + expect(response.body[0].field).toEqual('user ID'); }); it('🧪 Fails if user is not found', async () => { @@ -52,8 +53,8 @@ describe('Tests for userController.getUserById', () => { .set('Cookie', authCookie) .send(); - expect(response.status).toEqual(401); - expect(response.body.msg).toEqual('User not found!'); + expect(response.status).toEqual(404); + expect(response.body[0].message).toEqual('Not Found'); }); }); diff --git a/server/controllers/userController/getUserById/getUserById.ts b/server/controllers/userController/getUserById/getUserById.ts index 33218e8..640ef2d 100644 --- a/server/controllers/userController/getUserById/getUserById.ts +++ b/server/controllers/userController/getUserById/getUserById.ts @@ -1,31 +1,25 @@ import mongoose from 'mongoose'; import User from '../../../models/userModel'; -import { Request, Response, NextFunction } from 'express'; +import { Request, Response } from 'express'; +import { NotFoundError, ValidationError, RequestValidationError } from '../../../errors'; import { UserType } from '../../../types/user'; // ENDPOINT GET api/users/:userId // PURPOSE Get user by id // ACCESS Private -const getUserById = async (req: Request, res: Response, next: NextFunction) => { +const getUserById = async (req: Request, res: Response) => { const { userId } = req.params; if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).json({ msg: 'Invalid user ID format' }); + throw new RequestValidationError([new ValidationError('Invalid user ID format', 'user ID')]); } - try { - const user: UserType | null = await User.findOne({ _id: userId }); - if (!user) { - return res.status(401).json({ msg: 'User not found!' }); //TODO Move to global error handler - } - res.locals.user = user; - return res.status(200).json(res.locals.user); - } catch (error) { - return next({ - log: 'Express error in getUserById Middleware', - status: 500, - message: { err: 'An error occurred during retrieval' }, - }); + const user: UserType | null = await User.findOne({ _id: userId }); + + if (!user) { + throw new NotFoundError(); } + res.locals.user = user; + return res.status(200).json(res.locals.user); }; export default getUserById;