From cf07e516788db86416329af97d7d2d97ce08e8aa Mon Sep 17 00:00:00 2001 From: Jordy Date: Thu, 2 May 2024 21:49:20 -0400 Subject: [PATCH 01/16] docs(tests): outline test cases for getUserNotifications --- .../notificationController/getUserNotifications.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 requirements/notificationController/getUserNotifications.md diff --git a/requirements/notificationController/getUserNotifications.md b/requirements/notificationController/getUserNotifications.md new file mode 100644 index 000000000..1b231ed36 --- /dev/null +++ b/requirements/notificationController/getUserNotifications.md @@ -0,0 +1,11 @@ +# GET User Notifications + +## Positive Cases + +1. ❌ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. + +## Negative Cases + +1. ❌ Returns error 403 if a normal user tries to access another user's notifications. +2. ❌ Returns error 400 if the userId is missing from the request. +3. ❌ Returns error 500 if there is an internal error while fetching notifications. From 3cb29ae4775503da91286ac6a6cec153055221d5 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 02:08:27 -0400 Subject: [PATCH 02/16] test(notificationController): add unit test for getUserNotifications Added four unit tests covering one positive case and three negative cases. Moved userId error handling to higher level in controller since it makes more sense to check if userId is not present before anything else. --- src/controllers/notificationController.js | 49 +++++++++++++---------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/controllers/notificationController.js b/src/controllers/notificationController.js index 98911c3f9..7377ad197 100644 --- a/src/controllers/notificationController.js +++ b/src/controllers/notificationController.js @@ -3,8 +3,8 @@ const LOGGER = require('../startup/logger'); /** * API endpoint for notifications service. - * @param {} Notification - * @returns + * @param {} Notification + * @returns */ const notificationController = function () { @@ -18,7 +18,10 @@ const notificationController = function () { const getUserNotifications = async function (req, res) { const { userId } = req.params; const { requestor } = req.body; - if (requestor.requestorId !== userId && (requestor.role !== 'Administrator' || requestor.role !== 'Owner')) { + if ( + requestor.requestorId !== userId && + (requestor.role !== 'Administrator' || requestor.role !== 'Owner') + ) { res.status(403).send({ error: 'Unauthorized request' }); return; } @@ -37,7 +40,7 @@ const notificationController = function () { } }; - /** + /** * This function allows the user to get unread notifications for themselves or * allows the admin/owner user to get unread notifications for a specific user. * @param {Object} req - The request with userID as request param. @@ -47,15 +50,17 @@ const notificationController = function () { const getUnreadUserNotifications = async function (req, res) { const { userId } = req.params; const { requestor } = req.body; - if (requestor.requestorId !== userId && (requestor.role !== 'Administrator' || requestor.role !== 'Owner')) { - res.status(403).send({ error: 'Unauthorized request' }); - return; - } - if (!userId) { res.status(400).send({ error: 'User ID is required' }); return; } + if ( + requestor.requestorId !== userId && + (requestor.role !== 'Administrator' || requestor.role !== 'Owner') + ) { + res.status(403).send({ error: 'Unauthorized request' }); + return; + } try { const result = await notificationService.getUnreadUserNotifications(userId); @@ -68,13 +73,13 @@ const notificationController = function () { /** * This function allows the admin/owner user to get all notifications that they have sent. - * @param {*} req - * @param {*} res - * @returns + * @param {*} req + * @param {*} res + * @returns */ const getSentNotifications = async function (req, res) { const { requestor } = req.body; - if ((requestor.role !== 'Administrator' || requestor.role !== 'Owner')) { + if (requestor.role !== 'Administrator' || requestor.role !== 'Owner') { res.status(403).send({ error: 'Unauthorized request' }); return; } @@ -88,12 +93,11 @@ const notificationController = function () { } }; - /** * This function allows the Administrator/Owner user to create a notification to specific user. * @param {*} req request with a JSON payload containing the message and recipient list. - * @param {*} res - * @returns + * @param {*} res + * @returns */ const createUserNotification = async function (req, res) { const { message, recipient } = req.body; @@ -121,8 +125,8 @@ const notificationController = function () { /** * This function allows the Administrator/Owner user to delete a notification. * @param {*} req request with the notification ID as a parameter. - * @param {*} res - * @returns + * @param {*} res + * @returns */ const deleteUserNotification = async function (req, res) { const { requestor } = req.body; @@ -144,8 +148,8 @@ const notificationController = function () { /** * This function allows the user to mark a notification as read. * @param {*} req request with the notification ID as a parameter. - * @param {*} res - * @returns + * @param {*} res + * @returns */ const markNotificationAsRead = async function (req, res) { const recipientId = req.body.requestor.requestorId; @@ -156,7 +160,10 @@ const notificationController = function () { } try { - const result = await notificationService.markNotificationAsRead(req.params.notificationId, recipientId); + const result = await notificationService.markNotificationAsRead( + req.params.notificationId, + recipientId, + ); res.status(200).send(result); } catch (err) { LOGGER.logException(err); From 5c240ea4b125f734778603f39c1dc778b747a576 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 02:27:25 -0400 Subject: [PATCH 03/16] test(notificationController): add initial tests for getUserNotifications Added 2 negative cases to the unit test suite. Refactored 'htmlContentSanitizer' file because I was getting module error. Also moved up the initial userId check in the notification controller. --- src/controllers/notificationController.js | 9 ++-- .../notificationController.spec.js | 41 +++++++++++++++++++ src/utilities/htmlContentSanitizer.js | 10 ++--- 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 src/controllers/notificationController.spec.js diff --git a/src/controllers/notificationController.js b/src/controllers/notificationController.js index 7377ad197..c6e78252e 100644 --- a/src/controllers/notificationController.js +++ b/src/controllers/notificationController.js @@ -18,6 +18,10 @@ const notificationController = function () { const getUserNotifications = async function (req, res) { const { userId } = req.params; const { requestor } = req.body; + if (!userId) { + res.status(400).send({ error: 'User ID is required' }); + return; + } if ( requestor.requestorId !== userId && (requestor.role !== 'Administrator' || requestor.role !== 'Owner') @@ -26,11 +30,6 @@ const notificationController = function () { return; } - if (!userId) { - res.status(400).send({ error: 'User ID is required' }); - return; - } - try { const result = await notificationService.getNotifications(userId); res.status(200).send(result); diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js new file mode 100644 index 000000000..bac330337 --- /dev/null +++ b/src/controllers/notificationController.spec.js @@ -0,0 +1,41 @@ +const notificationController = require('./notificationController'); +const Notification = require('../models/notification'); +const { mockReq, mockRes } = require('../test'); + +const makeSut = () => { + const { getUserNotifications } = notificationController(Notification); + + return { + getUserNotifications, + }; +}; + +describe('Notification controller tests', () => { + beforeEach(() => { + mockReq.params.userId = '65cf6c3706d8ac105827bb2e'; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('Notification Controller Unit Tests', () => { + test('Ensures getUserNotifications returns error 400 if userId is not provided', async () => { + const { getUserNotifications } = makeSut(); + mockReq.params.userId = ''; + await getUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'User ID is required' }); + }); + test('Ensures getUserNotifications returns error 403 if userId does not match requestorId', async () => { + const { getUserNotifications } = makeSut(); + mockReq.params = { userId: '65cf6c3706d8ac105827bb2e' }; + mockReq.body = { requestor: { requestorId: 'differentUserId', role: 'Administrator' } }; + await getUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + }); + }); +}); diff --git a/src/utilities/htmlContentSanitizer.js b/src/utilities/htmlContentSanitizer.js index df16bf4f9..005458773 100644 --- a/src/utilities/htmlContentSanitizer.js +++ b/src/utilities/htmlContentSanitizer.js @@ -1,8 +1,8 @@ const sanitizeHtml = require('sanitize-html'); -// Please refer to https://www.npmjs.com/package/sanitize-html?activeTab=readme for more information. - -// eslint-disable-next-line import/prefer-default-export -export const cleanHtml = (dirty) => sanitizeHtml(dirty, { +const cleanHtml = (dirty) => + sanitizeHtml(dirty, { allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']), -}); + }); + +module.exports = { cleanHtml }; From 3794fb881ef34f68c49ddc20b84a92bf4ef0d17f Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 02:39:50 -0400 Subject: [PATCH 04/16] test(notificationController): add postive case to test suite Added Positive case 200 for getUserNotifications. Furthermore, I updated the docs for the negative and postive cases. Still need to add one last negative to complete the suite. --- .../getUserNotifications.md | 6 ++--- .../notificationController.spec.js | 24 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/requirements/notificationController/getUserNotifications.md b/requirements/notificationController/getUserNotifications.md index 1b231ed36..3ae185e09 100644 --- a/requirements/notificationController/getUserNotifications.md +++ b/requirements/notificationController/getUserNotifications.md @@ -2,10 +2,10 @@ ## Positive Cases -1. ❌ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. +1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. ## Negative Cases -1. ❌ Returns error 403 if a normal user tries to access another user's notifications. -2. ❌ Returns error 400 if the userId is missing from the request. +1. ✅ Returns error 403 if userId does not match requestorId. +2. ✅ Returns error 400 if the userId is missing from the request. 3. ❌ Returns error 500 if there is an internal error while fetching notifications. diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index bac330337..121a036dc 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -1,5 +1,6 @@ const notificationController = require('./notificationController'); const Notification = require('../models/notification'); +const notificationService = require('../services/notificationService'); const { mockReq, mockRes } = require('../test'); const makeSut = () => { @@ -30,12 +31,33 @@ describe('Notification controller tests', () => { }); test('Ensures getUserNotifications returns error 403 if userId does not match requestorId', async () => { const { getUserNotifications } = makeSut(); - mockReq.params = { userId: '65cf6c3706d8ac105827bb2e' }; mockReq.body = { requestor: { requestorId: 'differentUserId', role: 'Administrator' } }; await getUserNotifications(mockReq, mockRes); expect(mockRes.status).toHaveBeenCalledWith(403); expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); }); + test('Ensures getUserNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { + const { getUserNotifications } = makeSut(); + const mockNotifications = [ + { id: '123', message: 'Notification Test 1' }, + { id: '123', message: 'Notification Test 2' }, + { id: '123', message: 'Notification Test 3' }, + ]; + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + + const mockService = jest.fn().mockResolvedValue(mockNotifications); + + notificationService.getNotifications = mockService; + + await getUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); + expect(mockService).toHaveBeenCalledWith(mockReq.params.userId); + }); }); }); From 66d294837a9b7403736c39b8dab16972d74a579c Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 02:47:49 -0400 Subject: [PATCH 05/16] test(notificationController): add last negative case to test suite Added negative case for getUserNotifications to check 'Internal Error' shows if there is an error in fetching process. Furthermore, I updated the docs for the negative case. Still need refactor the test suite. There is still a lot of repetition in my code --- .../getUserNotifications.md | 2 +- src/controllers/notificationController.spec.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/requirements/notificationController/getUserNotifications.md b/requirements/notificationController/getUserNotifications.md index 3ae185e09..13755151d 100644 --- a/requirements/notificationController/getUserNotifications.md +++ b/requirements/notificationController/getUserNotifications.md @@ -8,4 +8,4 @@ 1. ✅ Returns error 403 if userId does not match requestorId. 2. ✅ Returns error 400 if the userId is missing from the request. -3. ❌ Returns error 500 if there is an internal error while fetching notifications. +3. ✅ Returns error 500 if there is an internal error while fetching notifications. diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index 121a036dc..7bda5d8e8 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -59,5 +59,20 @@ describe('Notification controller tests', () => { expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); expect(mockService).toHaveBeenCalledWith(mockReq.params.userId); }); + test('Ensures getUserNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { + const { getUserNotifications } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.getNotifications = jest + .fn() + .mockRejectedValue(new Error('Internal Error')); + + await getUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); }); }); From 26c87a687a7b1c58c1f1aa187bc34e69d320c962 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 03:35:58 -0400 Subject: [PATCH 06/16] test(notificationController): add test suite for getUnreadUserNotifications Added all four test cases for getUnreadUserNotifications.This test suite is essentially the same as getUserNotifications. The controller bahaves the same way. Additionally, updated the docs for the test cases added in the suite. --- .../getUnreadUserNotifications.md | 11 ++++ .../notificationController.spec.js | 61 ++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 requirements/notificationController/getUnreadUserNotifications.md diff --git a/requirements/notificationController/getUnreadUserNotifications.md b/requirements/notificationController/getUnreadUserNotifications.md new file mode 100644 index 000000000..8a7f950f4 --- /dev/null +++ b/requirements/notificationController/getUnreadUserNotifications.md @@ -0,0 +1,11 @@ +# GET Unread User Notifications + +## Positive Cases + +1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. + +## Negative Cases + +1. ✅ Returns error 403 if userId does not match requestorId. +2. ✅ Returns error 400 if the userId is missing from the request. +3. ✅ Returns error 500 if there is an internal error while fetching unread notifications. diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index 7bda5d8e8..85e6f6d34 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -4,14 +4,15 @@ const notificationService = require('../services/notificationService'); const { mockReq, mockRes } = require('../test'); const makeSut = () => { - const { getUserNotifications } = notificationController(Notification); + const { getUserNotifications, getUnreadUserNotifications } = notificationController(Notification); return { getUserNotifications, + getUnreadUserNotifications, }; }; -describe('Notification controller tests', () => { +describe('Notification controller Unit Tests', () => { beforeEach(() => { mockReq.params.userId = '65cf6c3706d8ac105827bb2e'; }); @@ -20,7 +21,7 @@ describe('Notification controller tests', () => { jest.clearAllMocks(); }); - describe('Notification Controller Unit Tests', () => { + describe('getUserNotifications', () => { test('Ensures getUserNotifications returns error 400 if userId is not provided', async () => { const { getUserNotifications } = makeSut(); mockReq.params.userId = ''; @@ -75,4 +76,58 @@ describe('Notification controller tests', () => { expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); }); }); + + describe('getUnreadUserNotifications', () => { + test('Ensures getUnreadUserNotifications returns error 400 if userId is not provided', async () => { + const { getUnreadUserNotifications } = makeSut(); + mockReq.params.userId = ''; + await getUnreadUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'User ID is required' }); + }); + test('Ensures getUnreadUserNotifications returns error 403 if userId does not match requestorId', async () => { + const { getUnreadUserNotifications } = makeSut(); + mockReq.body = { requestor: { requestorId: 'differentUserId', role: 'Administrator' } }; + await getUnreadUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + }); + test('Ensures getUnreadUserNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { + const { getUnreadUserNotifications } = makeSut(); + const mockNotifications = [ + { id: '123', message: 'Notification Test 1' }, + { id: '123', message: 'Notification Test 2' }, + { id: '123', message: 'Notification Test 3' }, + ]; + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + + const mockService = jest.fn().mockResolvedValue(mockNotifications); + + notificationService.getUnreadUserNotifications = mockService; + + await getUnreadUserNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); + expect(mockService).toHaveBeenCalledWith(mockReq.params.userId); + }); + test('Ensures getUnreadUserNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { + const { getUnreadUserNotifications } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.getUnreadUserNotifications = jest + .fn() + .mockRejectedValue(new Error('Internal Server Error')); + await getUnreadUserNotifications(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); + }); }); From 933d51cee494f2da96ce8f0beb066497bd30e2e9 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 08:52:31 -0400 Subject: [PATCH 07/16] test(notificationController): add getSentNotifications tests Added four additional tests for getSentNotifications inside controller. I found a bug while working on this test. Because of how logical operators work in JavaScript, the logic that was set up inside the method would always return false. This is not intended behavior so I corrected it by using '&&' instead of '||'. This is on line 81 of the 'notificationsController' --- src/controllers/notificationController.js | 2 +- .../notificationController.spec.js | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/controllers/notificationController.js b/src/controllers/notificationController.js index c6e78252e..994e72937 100644 --- a/src/controllers/notificationController.js +++ b/src/controllers/notificationController.js @@ -78,7 +78,7 @@ const notificationController = function () { */ const getSentNotifications = async function (req, res) { const { requestor } = req.body; - if (requestor.role !== 'Administrator' || requestor.role !== 'Owner') { + if (requestor.role !== 'Administrator' && requestor.role !== 'Owner') { res.status(403).send({ error: 'Unauthorized request' }); return; } diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index 85e6f6d34..00d9aa5be 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -4,11 +4,13 @@ const notificationService = require('../services/notificationService'); const { mockReq, mockRes } = require('../test'); const makeSut = () => { - const { getUserNotifications, getUnreadUserNotifications } = notificationController(Notification); + const { getUserNotifications, getUnreadUserNotifications, getSentNotifications } = + notificationController(Notification); return { getUserNotifications, getUnreadUserNotifications, + getSentNotifications, }; }; @@ -130,4 +132,45 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); }); }); + describe('getSentNotifications', () => { + test('Ensures getSentNotifications returns error 403 if requestor role is not Administrator or Owner', async () => { + const { getSentNotifications } = makeSut(); + mockReq.body = { requestor: { role: 'randomRole' } }; + await getSentNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + }); + test('Ensures getSentNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { + const { getSentNotifications } = makeSut(); + const mockNotifications = []; + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + + const mockService = jest.fn().mockResolvedValue(mockNotifications); + notificationService.getSentNotifications = mockService; + + await getSentNotifications(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); + expect(mockService).toHaveBeenCalledWith(mockReq.body.requestor.requestorId); + }); + + test('Ensures getSentNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { + const { getSentNotifications } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.getSentNotifications = jest + .fn() + .mockRejectedValue(new Error('Internal Error')); + await getSentNotifications(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); + }); }); From 5fb588ddd4de050a15987f3da4ababf03818eb08 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 09:26:18 -0400 Subject: [PATCH 08/16] docs(tests): update test cases format for test suites --- .../notificationController/getSentNotifications.md | 14 ++++++++++++++ .../getUnreadUserNotifications.md | 10 +++++++--- .../notificationController/getUserNotifications.md | 10 +++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 requirements/notificationController/getSentNotifications.md diff --git a/requirements/notificationController/getSentNotifications.md b/requirements/notificationController/getSentNotifications.md new file mode 100644 index 000000000..c9d541fe7 --- /dev/null +++ b/requirements/notificationController/getSentNotifications.md @@ -0,0 +1,14 @@ +Check mark: ✅ +Cross Mark: ❌ + + +# GET Sent Notifications + +## Positive Cases + +1. ✅ Returns status 200 Successful Data Retrieval + +## Negative Cases + +1. ✅ Returns error 403 if requestor role is not Admin or Owner +2. ✅ Returns error 500 if there is an internal error while fetching notifications. diff --git a/requirements/notificationController/getUnreadUserNotifications.md b/requirements/notificationController/getUnreadUserNotifications.md index 8a7f950f4..a3321da76 100644 --- a/requirements/notificationController/getUnreadUserNotifications.md +++ b/requirements/notificationController/getUnreadUserNotifications.md @@ -1,11 +1,15 @@ -# GET Unread User Notifications +Check mark: ✅ +Cross Mark: ❌ -## Positive Cases -1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. +# GET Unread User Notifications ## Negative Cases 1. ✅ Returns error 403 if userId does not match requestorId. 2. ✅ Returns error 400 if the userId is missing from the request. 3. ✅ Returns error 500 if there is an internal error while fetching unread notifications. + +## Positive Cases + +1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. diff --git a/requirements/notificationController/getUserNotifications.md b/requirements/notificationController/getUserNotifications.md index 13755151d..d16eba504 100644 --- a/requirements/notificationController/getUserNotifications.md +++ b/requirements/notificationController/getUserNotifications.md @@ -1,11 +1,15 @@ -# GET User Notifications +Check mark: ✅ +Cross Mark: ❌ -## Positive Cases -1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. +# GET User Notifications ## Negative Cases 1. ✅ Returns error 403 if userId does not match requestorId. 2. ✅ Returns error 400 if the userId is missing from the request. 3. ✅ Returns error 500 if there is an internal error while fetching notifications. + +## Positive Cases + +1. ✅ Returns status 200 with notification data when a valid userId is provided by an Administrator or Owner querying another user's notifications. From 4aecf01d9519e313b1acbd8d76a88cdb425a8c7f Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 09:28:09 -0400 Subject: [PATCH 09/16] test(notificationController): update test description --- src/controllers/notificationController.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index 00d9aa5be..f24720e6e 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -133,7 +133,7 @@ describe('Notification controller Unit Tests', () => { }); }); describe('getSentNotifications', () => { - test('Ensures getSentNotifications returns error 403 if requestor role is not Administrator or Owner', async () => { + test('Ensures getSentNotifications returns error 403 if requestor role is neither Administrator or Owner', async () => { const { getSentNotifications } = makeSut(); mockReq.body = { requestor: { role: 'randomRole' } }; await getSentNotifications(mockReq, mockRes); From 9d74e37c863152e89b1c6f110af8e4ca7efe55c4 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 09:38:27 -0400 Subject: [PATCH 10/16] docs(tests): add test cases for create User Notification --- .../creatUserNotification.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 requirements/notificationController/creatUserNotification.md diff --git a/requirements/notificationController/creatUserNotification.md b/requirements/notificationController/creatUserNotification.md new file mode 100644 index 000000000..39a79ca9c --- /dev/null +++ b/requirements/notificationController/creatUserNotification.md @@ -0,0 +1,15 @@ +Check mark: ✅ +Cross Mark: ❌ + + +# Create User Notification + +## Negative Cases + +1. ❌ Returns error 403 if requestor role is not Admin or Owner +2. ❌ Returns error 400 if message and recipient are missing from request +3. ❌ Returns error 500 if there is an internal error while fetching unread notifications. + +## Positive Cases + +1. ❌ Returns status 200 when notification is successfully created with sender, recipient and message From f1b4b99e59f95daab1889b05ae6fce41f2d355c1 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 10:22:30 -0400 Subject: [PATCH 11/16] test(notificationsController): add two negative test cases Added two negative test cases that are for error handling. Came across the same bug again where inside the controller the operator '||' would make the method always throw a forbidden error. Changed the operator to '&&' which fixed this issue. --- src/controllers/notificationController.js | 2 +- .../notificationController.spec.js | 38 ++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/controllers/notificationController.js b/src/controllers/notificationController.js index 994e72937..1b5f02e32 100644 --- a/src/controllers/notificationController.js +++ b/src/controllers/notificationController.js @@ -102,7 +102,7 @@ const notificationController = function () { const { message, recipient } = req.body; const sender = req.requestor.requestorId; - if (req.body.requestor.role !== 'Administrator' || req.body.requestor.role !== 'Owner') { + if (req.body.requestor.role !== 'Administrator' && req.body.requestor.role !== 'Owner') { res.status(403).send({ error: 'Unauthorized request' }); return; } diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index f24720e6e..8a8f5a009 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -4,13 +4,18 @@ const notificationService = require('../services/notificationService'); const { mockReq, mockRes } = require('../test'); const makeSut = () => { - const { getUserNotifications, getUnreadUserNotifications, getSentNotifications } = - notificationController(Notification); + const { + getUserNotifications, + getUnreadUserNotifications, + getSentNotifications, + createUserNotification, + } = notificationController(Notification); return { getUserNotifications, getUnreadUserNotifications, getSentNotifications, + createUserNotification, }; }; @@ -173,4 +178,33 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); }); }); + describe('createUserNotification', () => { + test('Ensures createUserNotifications returns 403 when requestor role is not Admin or Owner', async () => { + const { createUserNotification } = makeSut(); + mockReq.body.requestor = { + role: 'randomRole', + }; + mockReq.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + }; + await createUserNotification(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + }); + test('Ensures createUserNotifications returns 400 if message or recipient is missing', async () => { + const { createUserNotification } = makeSut(); + mockReq.body = { + requestor: { + role: 'Administrator', + }, + message: '', + recipient: '', + }; + await createUserNotification(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Message and recipient are required' }); + }); + }); }); From 5223cfa862a568d336dfde022dc1aaa045a64b0a Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 10:24:12 -0400 Subject: [PATCH 12/16] docs(tests): update negative test cases for createUserNotification --- requirements/notificationController/creatUserNotification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/notificationController/creatUserNotification.md b/requirements/notificationController/creatUserNotification.md index 39a79ca9c..dc5ad7a8e 100644 --- a/requirements/notificationController/creatUserNotification.md +++ b/requirements/notificationController/creatUserNotification.md @@ -6,8 +6,8 @@ Cross Mark: ❌ ## Negative Cases -1. ❌ Returns error 403 if requestor role is not Admin or Owner -2. ❌ Returns error 400 if message and recipient are missing from request +1. ✅ Returns error 403 if requestor role is not Admin or Owner +2. ✅ Returns error 400 if message and recipient are missing from request 3. ❌ Returns error 500 if there is an internal error while fetching unread notifications. ## Positive Cases From e3380c8890aca278ce11e6d8b61ab81e2acb2e0d Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 19:12:08 -0400 Subject: [PATCH 13/16] test(notificationController): finish tests for createUserNotification Added remaining test cases and updated requirements docs. Still need to add 'deleteUserNotifications' and 'markNotificationAsRead'. Aiming to complete them tonight --- .../creatUserNotification.md | 4 +- .../notificationController.spec.js | 46 +++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/requirements/notificationController/creatUserNotification.md b/requirements/notificationController/creatUserNotification.md index dc5ad7a8e..bbe81bee8 100644 --- a/requirements/notificationController/creatUserNotification.md +++ b/requirements/notificationController/creatUserNotification.md @@ -8,8 +8,8 @@ Cross Mark: ❌ 1. ✅ Returns error 403 if requestor role is not Admin or Owner 2. ✅ Returns error 400 if message and recipient are missing from request -3. ❌ Returns error 500 if there is an internal error while fetching unread notifications. +3. ✅ Returns error 500 if there is an internal error while fetching unread notifications. ## Positive Cases -1. ❌ Returns status 200 when notification is successfully created with sender, recipient and message +1. ✅ Returns status 200 when notification is successfully created with sender, recipient and message diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index 8a8f5a009..bd9dd27b4 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -164,7 +164,7 @@ describe('Notification controller Unit Tests', () => { expect(mockService).toHaveBeenCalledWith(mockReq.body.requestor.requestorId); }); - test('Ensures getSentNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { + test('Ensures getSentNotification returns error 500 if there is an internal error while fetching notifications.', async () => { const { getSentNotifications } = makeSut(); mockReq.body.requestor = { requestorId: '65cf6c3706d8ac105827bb2e', @@ -179,7 +179,7 @@ describe('Notification controller Unit Tests', () => { }); }); describe('createUserNotification', () => { - test('Ensures createUserNotifications returns 403 when requestor role is not Admin or Owner', async () => { + test('Ensures createUserNotification returns error 403 when requestor role is not Admin or Owner', async () => { const { createUserNotification } = makeSut(); mockReq.body.requestor = { role: 'randomRole', @@ -192,7 +192,7 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.status).toHaveBeenCalledWith(403); expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); }); - test('Ensures createUserNotifications returns 400 if message or recipient is missing', async () => { + test('Ensures createUserNotification returns error 400 if message or recipient is missing', async () => { const { createUserNotification } = makeSut(); mockReq.body = { requestor: { @@ -206,5 +206,45 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.status).toHaveBeenCalledWith(400); expect(mockRes.send).toHaveBeenCalledWith({ error: 'Message and recipient are required' }); }); + test('Ensures createUserNotification returns 200 and notification data when notification is created successfully', async () => { + const { createUserNotification } = makeSut(); + const mockNotification = { + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + sender: '5a7e21f00317bc1538def4b7' + }; + mockReq.body = { + requestor: { + role: 'Administrator', + }, + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + }; + mockReq.requestor = { + requestorId: '5a7e21f00317bc1538def4b7' + }; + + const mockService = jest.fn().mockResolvedValue(mockNotification); + notificationService.createNotification = mockService; + + await createUserNotification(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotification); + expect(mockService).toHaveBeenCalledWith(mockReq.requestor.requestorId, mockReq.body.recipient, mockReq.body.message); + }); + test('Ensures createUserNotification returns error 500 if there is an internal error while creating a notification.', async () => { + const { createUserNotification } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.createNotification = jest + .fn() + .mockRejectedValue({ error: 'Internal Error' }); + await createUserNotification(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); }); }); From 54fad49fb25c0ebeb7905bc9fa9547601ff58445 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 20:31:00 -0400 Subject: [PATCH 14/16] docs(tests): add covered test cases for delete and mark notification --- .../deleteUserNotification.md | 14 ++++++++++++++ .../markNotificationAsRead.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 requirements/notificationController/deleteUserNotification.md create mode 100644 requirements/notificationController/markNotificationAsRead.md diff --git a/requirements/notificationController/deleteUserNotification.md b/requirements/notificationController/deleteUserNotification.md new file mode 100644 index 000000000..f9cdabb80 --- /dev/null +++ b/requirements/notificationController/deleteUserNotification.md @@ -0,0 +1,14 @@ +Check mark: ✅ +Cross Mark: ❌ + + +# Delete User Notification + +## Negative Cases + +1. ✅ Returns error 403 if requestor role is not Admin or Owner. +2. ✅ Returns error 500 if there is an internal error while deleting notification. + +## Positive Cases + +1. ✅ Returns status 200 when notification is successfully deleted. diff --git a/requirements/notificationController/markNotificationAsRead.md b/requirements/notificationController/markNotificationAsRead.md new file mode 100644 index 000000000..3971e9086 --- /dev/null +++ b/requirements/notificationController/markNotificationAsRead.md @@ -0,0 +1,14 @@ +Check mark: ✅ +Cross Mark: ❌ + + +# Mark Notification as Read + +## Negative Cases + +1. ✅ Returns error 400 if recipientId is missing. +2. ✅ Returns error 500 if there is an internal error while reading notification. + +## Positive Cases + +1. ✅ Returns status 200 when notification is successfully read. From a8e00fa7ed40c0f1a49289dd70d2bfe57e3825e0 Mon Sep 17 00:00:00 2001 From: Jordy Date: Fri, 3 May 2024 20:34:03 -0400 Subject: [PATCH 15/16] test(notificationController): add delete and mark notification test suites Added the remaining tests for marking notification as read and deleting notification. Also, fix more bugs in the controller with the operator not evaluating the function correctly. Next steps are to refactor my tests and trim repeated code --- src/controllers/notificationController.js | 2 +- .../notificationController.spec.js | 117 +++++++++++++++++- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/controllers/notificationController.js b/src/controllers/notificationController.js index 1b5f02e32..e15f0d989 100644 --- a/src/controllers/notificationController.js +++ b/src/controllers/notificationController.js @@ -130,7 +130,7 @@ const notificationController = function () { const deleteUserNotification = async function (req, res) { const { requestor } = req.body; - if (requestor.role !== 'Administrator' || requestor.role !== 'Owner') { + if (requestor.role !== 'Administrator' && requestor.role !== 'Owner') { res.status(403).send({ error: 'Unauthorized request' }); return; } diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index bd9dd27b4..e628b098b 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -9,6 +9,8 @@ const makeSut = () => { getUnreadUserNotifications, getSentNotifications, createUserNotification, + deleteUserNotification, + markNotificationAsRead, } = notificationController(Notification); return { @@ -16,6 +18,8 @@ const makeSut = () => { getUnreadUserNotifications, getSentNotifications, createUserNotification, + deleteUserNotification, + markNotificationAsRead, }; }; @@ -211,7 +215,7 @@ describe('Notification controller Unit Tests', () => { const mockNotification = { message: 'Notification Test', recipient: '65cf6c3706d8ac105827bb2e', - sender: '5a7e21f00317bc1538def4b7' + sender: '5a7e21f00317bc1538def4b7', }; mockReq.body = { requestor: { @@ -221,7 +225,7 @@ describe('Notification controller Unit Tests', () => { recipient: '65cf6c3706d8ac105827bb2e', }; mockReq.requestor = { - requestorId: '5a7e21f00317bc1538def4b7' + requestorId: '5a7e21f00317bc1538def4b7', }; const mockService = jest.fn().mockResolvedValue(mockNotification); @@ -231,7 +235,11 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.status).toHaveBeenCalledWith(200); expect(mockRes.send).toHaveBeenCalledWith(mockNotification); - expect(mockService).toHaveBeenCalledWith(mockReq.requestor.requestorId, mockReq.body.recipient, mockReq.body.message); + expect(mockService).toHaveBeenCalledWith( + mockReq.requestor.requestorId, + mockReq.body.recipient, + mockReq.body.message, + ); }); test('Ensures createUserNotification returns error 500 if there is an internal error while creating a notification.', async () => { const { createUserNotification } = makeSut(); @@ -247,4 +255,107 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); }); }); + describe('deleteUserNotification', () => { + test('Ensures deleteUserNotification returns error 403 when requestor role is not Admin or Owner', async () => { + const { deleteUserNotification } = makeSut(); + mockReq.body.requestor.role = 'randomRole' + await deleteUserNotification(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + }); + test('Ensures deleteUserNotification returns 200 and deletes notification', async () => { + const { deleteUserNotification } = makeSut(); + const mockNotification = { + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + sender: '5a7e21f00317bc1538def4b7', + }; + mockReq.body = { + requestor: { + role: 'Administrator', + }, + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + }; + mockReq.requestor = { + requestorId: '5a7e21f00317bc1538def4b7', + }; + + const mockService = jest.fn().mockResolvedValue(mockNotification); + notificationService.deleteNotification = mockService; + + await deleteUserNotification(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotification); + expect(mockService).toHaveBeenCalledWith(mockReq.params.notificationId); + }); + test('Ensures deleteUserNotification returns error 500 if there is an internal error while deleting a notification.', async () => { + const { deleteUserNotification } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.deleteNotification = jest + .fn() + .mockRejectedValue({ error: 'Internal Error' }); + await deleteUserNotification(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); + }); + describe('markNotificationsAsRead', () => { + test('Ensures markNotificationAsRead returns 400 if recipientId is missing',() => { + const { markNotificationAsRead } = makeSut(); + mockReq.body.requestor.requestorId = ''; + markNotificationAsRead(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Recipient ID is required' }); + }) + test('Ensures markNotificationAsRead returns 200 and marks notification as read', async () => { + const { markNotificationAsRead } = makeSut(); + const mockNotification = { + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + sender: '5a7e21f00317bc1538def4b7', + }; + mockReq.body = { + requestor: { + role: 'Administrator', + }, + message: 'Notification Test', + recipient: '65cf6c3706d8ac105827bb2e', + }; + mockReq.body.requestor = { + requestorId: '5a7e21f00317bc1538def4b7', + }; + mockReq.params = { + notificationId: '12345' + }; + + const mockService = jest.fn().mockResolvedValue(mockNotification); + notificationService.markNotificationAsRead = mockService; + + await markNotificationAsRead(mockReq, mockRes); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith(mockNotification); + expect(mockService).toHaveBeenCalledWith(mockReq.params.notificationId,mockReq.body.requestor.requestorId); + }); + test('Ensures markNotificationAsRead returns 500 if there is an internal error while marking notification as read.', async () => { + const { markNotificationAsRead } = makeSut(); + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; + notificationService.markNotificationAsRead = jest + .fn() + .mockRejectedValue({ error: 'Internal Error' }); + await markNotificationAsRead(mockReq, mockRes); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + }); + + }) }); From 603f0eed86c79ab73611e0dd714698b611e725ea Mon Sep 17 00:00:00 2001 From: Jordy Date: Sat, 4 May 2024 00:39:50 -0400 Subject: [PATCH 16/16] test(notificationController): refactor tests for better readability Made use of Diegos 'assertResMock' helper function to slim down some of the tests. --- .../notificationController.spec.js | 170 +++++++----------- 1 file changed, 61 insertions(+), 109 deletions(-) diff --git a/src/controllers/notificationController.spec.js b/src/controllers/notificationController.spec.js index e628b098b..2a7662122 100644 --- a/src/controllers/notificationController.spec.js +++ b/src/controllers/notificationController.spec.js @@ -1,7 +1,7 @@ const notificationController = require('./notificationController'); const Notification = require('../models/notification'); const notificationService = require('../services/notificationService'); -const { mockReq, mockRes } = require('../test'); +const { mockReq, mockRes, assertResMock } = require('../test'); const makeSut = () => { const { @@ -26,6 +26,11 @@ const makeSut = () => { describe('Notification controller Unit Tests', () => { beforeEach(() => { mockReq.params.userId = '65cf6c3706d8ac105827bb2e'; + mockReq.body.requestor.role = 'Administrator'; + mockReq.body.requestor = { + requestorId: '65cf6c3706d8ac105827bb2e', + role: 'Administrator', + }; }); afterEach(() => { @@ -35,19 +40,17 @@ describe('Notification controller Unit Tests', () => { describe('getUserNotifications', () => { test('Ensures getUserNotifications returns error 400 if userId is not provided', async () => { const { getUserNotifications } = makeSut(); + const errorMsg = { error: 'User ID is required' }; mockReq.params.userId = ''; - await getUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(400); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'User ID is required' }); + const response = await getUserNotifications(mockReq, mockRes); + assertResMock(400, errorMsg, response, mockRes); }); test('Ensures getUserNotifications returns error 403 if userId does not match requestorId', async () => { const { getUserNotifications } = makeSut(); - mockReq.body = { requestor: { requestorId: 'differentUserId', role: 'Administrator' } }; - await getUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + const errorMsg = { error: 'Unauthorized request' }; + mockReq.body.requestor.requestorId = 'differentUserId'; + const response = await getUserNotifications(mockReq, mockRes); + assertResMock(403, errorMsg, response, mockRes); }); test('Ensures getUserNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { const { getUserNotifications } = makeSut(); @@ -56,54 +59,35 @@ describe('Notification controller Unit Tests', () => { { id: '123', message: 'Notification Test 2' }, { id: '123', message: 'Notification Test 3' }, ]; - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - const mockService = jest.fn().mockResolvedValue(mockNotifications); - notificationService.getNotifications = mockService; - - await getUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); - expect(mockService).toHaveBeenCalledWith(mockReq.params.userId); + const response = await getUserNotifications(mockReq, mockRes); + assertResMock(200, mockNotifications, response, mockRes); }); test('Ensures getUserNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { const { getUserNotifications } = makeSut(); - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - notificationService.getNotifications = jest - .fn() - .mockRejectedValue(new Error('Internal Error')); - - await getUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(500); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + const errorMsg = { error: 'Internal Error' }; + const mockService = jest.fn().mockRejectedValue(errorMsg); + notificationService.getNotifications = mockService; + const response = await getUserNotifications(mockReq, mockRes); + assertResMock(500, errorMsg, response, mockRes); }); }); describe('getUnreadUserNotifications', () => { test('Ensures getUnreadUserNotifications returns error 400 if userId is not provided', async () => { const { getUnreadUserNotifications } = makeSut(); + const errorMsg = { error: 'User ID is required' }; mockReq.params.userId = ''; - await getUnreadUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(400); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'User ID is required' }); + const response = await getUnreadUserNotifications(mockReq, mockRes); + assertResMock(400, errorMsg, response, mockRes); }); test('Ensures getUnreadUserNotifications returns error 403 if userId does not match requestorId', async () => { const { getUnreadUserNotifications } = makeSut(); - mockReq.body = { requestor: { requestorId: 'differentUserId', role: 'Administrator' } }; - await getUnreadUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + const errorMsg = { error: 'Unauthorized request' }; + mockReq.body.requestor.requestorId = 'differentUserId' + const response = await getUnreadUserNotifications(mockReq, mockRes); + assertResMock(403, errorMsg, response, mockRes); }); test('Ensures getUnreadUserNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { const { getUnreadUserNotifications } = makeSut(); @@ -112,92 +96,60 @@ describe('Notification controller Unit Tests', () => { { id: '123', message: 'Notification Test 2' }, { id: '123', message: 'Notification Test 3' }, ]; - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - const mockService = jest.fn().mockResolvedValue(mockNotifications); - notificationService.getUnreadUserNotifications = mockService; - - await getUnreadUserNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); - expect(mockService).toHaveBeenCalledWith(mockReq.params.userId); + const response = await getUnreadUserNotifications(mockReq, mockRes); + assertResMock(200, mockNotifications, response, mockRes); }); test('Ensures getUnreadUserNotifications returns error 500 if there is an internal error while fetching notifications.', async () => { const { getUnreadUserNotifications } = makeSut(); - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - notificationService.getUnreadUserNotifications = jest - .fn() - .mockRejectedValue(new Error('Internal Server Error')); - await getUnreadUserNotifications(mockReq, mockRes); - expect(mockRes.status).toHaveBeenCalledWith(500); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + const errorMsg = { error: 'Internal Error' }; + const mockService = jest.fn().mockRejectedValue(errorMsg); + notificationService.getUnreadUserNotifications = mockService; + const response = await getUnreadUserNotifications(mockReq, mockRes); + assertResMock(500, errorMsg, response, mockRes); }); }); describe('getSentNotifications', () => { test('Ensures getSentNotifications returns error 403 if requestor role is neither Administrator or Owner', async () => { const { getSentNotifications } = makeSut(); - mockReq.body = { requestor: { role: 'randomRole' } }; - await getSentNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + const errorMsg = { error: 'Unauthorized request' }; + mockReq.body.requestor.role = 'randomRole' + const response = await getSentNotifications(mockReq, mockRes); + assertResMock(403, errorMsg, response, mockRes); }); test('Ensures getSentNotifications returns 200 and notifications data when notifications are fetched successfully', async () => { const { getSentNotifications } = makeSut(); const mockNotifications = []; - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - const mockService = jest.fn().mockResolvedValue(mockNotifications); notificationService.getSentNotifications = mockService; - - await getSentNotifications(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith(mockNotifications); - expect(mockService).toHaveBeenCalledWith(mockReq.body.requestor.requestorId); + const response = await getSentNotifications(mockReq, mockRes); + assertResMock(200, mockNotifications, response, mockRes); }); test('Ensures getSentNotification returns error 500 if there is an internal error while fetching notifications.', async () => { const { getSentNotifications } = makeSut(); - mockReq.body.requestor = { - requestorId: '65cf6c3706d8ac105827bb2e', - role: 'Administrator', - }; - notificationService.getSentNotifications = jest - .fn() - .mockRejectedValue(new Error('Internal Error')); - await getSentNotifications(mockReq, mockRes); - expect(mockRes.status).toHaveBeenCalledWith(500); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); + const errorMsg = { error: 'Internal Error' }; + const mockService = jest.fn().mockRejectedValue(errorMsg); + notificationService.getSentNotifications = mockService; + const response = await getSentNotifications(mockReq, mockRes); + assertResMock(500, errorMsg, response, mockRes); }); }); describe('createUserNotification', () => { test('Ensures createUserNotification returns error 403 when requestor role is not Admin or Owner', async () => { const { createUserNotification } = makeSut(); - mockReq.body.requestor = { - role: 'randomRole', - }; + const errorMsg = { error: 'Unauthorized request' }; + mockReq.body.requestor.role = 'randomRole' mockReq.requestor = { requestorId: '65cf6c3706d8ac105827bb2e', }; - await createUserNotification(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Unauthorized request' }); + const response = await createUserNotification(mockReq, mockRes); + assertResMock(403, errorMsg, response, mockRes); }); test('Ensures createUserNotification returns error 400 if message or recipient is missing', async () => { const { createUserNotification } = makeSut(); + const errorMsg = { error: 'Message and recipient are required' }; mockReq.body = { requestor: { role: 'Administrator', @@ -205,10 +157,8 @@ describe('Notification controller Unit Tests', () => { message: '', recipient: '', }; - await createUserNotification(mockReq, mockRes); - - expect(mockRes.status).toHaveBeenCalledWith(400); - expect(mockRes.send).toHaveBeenCalledWith({ error: 'Message and recipient are required' }); + const response = await createUserNotification(mockReq, mockRes); + assertResMock(400, errorMsg, response, mockRes); }); test('Ensures createUserNotification returns 200 and notification data when notification is created successfully', async () => { const { createUserNotification } = makeSut(); @@ -258,7 +208,7 @@ describe('Notification controller Unit Tests', () => { describe('deleteUserNotification', () => { test('Ensures deleteUserNotification returns error 403 when requestor role is not Admin or Owner', async () => { const { deleteUserNotification } = makeSut(); - mockReq.body.requestor.role = 'randomRole' + mockReq.body.requestor.role = 'randomRole'; await deleteUserNotification(mockReq, mockRes); expect(mockRes.status).toHaveBeenCalledWith(403); @@ -306,13 +256,13 @@ describe('Notification controller Unit Tests', () => { }); }); describe('markNotificationsAsRead', () => { - test('Ensures markNotificationAsRead returns 400 if recipientId is missing',() => { + test('Ensures markNotificationAsRead returns 400 if recipientId is missing', () => { const { markNotificationAsRead } = makeSut(); mockReq.body.requestor.requestorId = ''; markNotificationAsRead(mockReq, mockRes); expect(mockRes.status).toHaveBeenCalledWith(400); expect(mockRes.send).toHaveBeenCalledWith({ error: 'Recipient ID is required' }); - }) + }); test('Ensures markNotificationAsRead returns 200 and marks notification as read', async () => { const { markNotificationAsRead } = makeSut(); const mockNotification = { @@ -331,7 +281,7 @@ describe('Notification controller Unit Tests', () => { requestorId: '5a7e21f00317bc1538def4b7', }; mockReq.params = { - notificationId: '12345' + notificationId: '12345', }; const mockService = jest.fn().mockResolvedValue(mockNotification); @@ -341,7 +291,10 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.status).toHaveBeenCalledWith(200); expect(mockRes.send).toHaveBeenCalledWith(mockNotification); - expect(mockService).toHaveBeenCalledWith(mockReq.params.notificationId,mockReq.body.requestor.requestorId); + expect(mockService).toHaveBeenCalledWith( + mockReq.params.notificationId, + mockReq.body.requestor.requestorId, + ); }); test('Ensures markNotificationAsRead returns 500 if there is an internal error while marking notification as read.', async () => { const { markNotificationAsRead } = makeSut(); @@ -356,6 +309,5 @@ describe('Notification controller Unit Tests', () => { expect(mockRes.status).toHaveBeenCalledWith(500); expect(mockRes.send).toHaveBeenCalledWith({ error: 'Internal Error' }); }); - - }) + }); });