From 2fa95b469d19135fe5cdf55cd7ba4179db7d749d Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Fri, 29 Mar 2024 23:17:22 -0400 Subject: [PATCH 01/10] test: setup tests for teamController --- src/controllers/teamController.spec.js | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/controllers/teamController.spec.js diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js new file mode 100644 index 000000000..18a91876b --- /dev/null +++ b/src/controllers/teamController.spec.js @@ -0,0 +1,60 @@ +const Team = require('../models/team'); +const teamController = require('./teamController'); +const { mockReq, mockRes } = require('../test'); + +const makeSut = () => { + const { getAllTeams } = teamController(Team); + return { + getAllTeams, + }; +}; + +const flushPromises = () => new Promise(setImmediate); + +describe('teamController', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + const sortObject = { + sort: () => {}, + }; + + describe('getAllTeams', () => { + test('should return all teams sorted by name', async () => { + const team1 = { + teamName: 'Team A', + }; + const team2 = { + teamName: 'Team B', + }; + + const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue([team1, team2]); + const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); + const { getAllTeams } = makeSut(); + + getAllTeams(mockReq, mockRes); + await flushPromises(); + + expect(findSpy).toHaveBeenCalledWith({}); + expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith([team1, team2]); + }); + + test('should return 404 if an error occurs', async () => { + const { getAllTeams } = makeSut(); + + const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(new Error('any error')); + + const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); + + getAllTeams(mockReq, mockRes); + await flushPromises(); + + expect(findSpy).toHaveBeenCalledWith({}); + expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); + expect(mockRes.status).toHaveBeenCalledWith(404); + expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); + }); + }); +}); From 91d2d899f66589d2b430a816ff8505c7b6ed0ae1 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Mon, 1 Apr 2024 13:36:23 -0400 Subject: [PATCH 02/10] test: update getTeamById tests --- src/controllers/teamController.spec.js | 37 ++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 18a91876b..4879ea6f5 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -3,9 +3,11 @@ const teamController = require('./teamController'); const { mockReq, mockRes } = require('../test'); const makeSut = () => { - const { getAllTeams } = teamController(Team); + const { getAllTeams, getTeamById, postTeam } = teamController(Team); return { getAllTeams, + getTeamById, + postTeam, }; }; @@ -15,6 +17,7 @@ describe('teamController', () => { afterEach(() => { jest.clearAllMocks(); }); + const sortObject = { sort: () => {}, }; @@ -45,7 +48,6 @@ describe('teamController', () => { const { getAllTeams } = makeSut(); const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(new Error('any error')); - const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); getAllTeams(mockReq, mockRes); @@ -57,4 +59,35 @@ describe('teamController', () => { expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); }); }); + + describe('getTeamById', () => { + test('should return a team by ID', async () => { + const { getTeamById } = makeSut(); + const teamId = '22335'; + const req = { params: { teamId } }; + + const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId: '22335' }); + getTeamById(req, mockRes); + + await flushPromises(); + + expect(findByIdSpy).toHaveBeenCalledWith(teamId); + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith({ teamId: '22335' }); + }); + + test('should return 404 if the team is not found', async () => { + const teamId = 'nonExistentTeamId'; + const req = { params: { teamId } }; + const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(new Error('any error')); + + const { getTeamById } = makeSut(); + getTeamById(req, mockRes); + await flushPromises(); + + expect(findByIdSpy).toHaveBeenCalledWith(teamId); + expect(mockRes.status).toHaveBeenCalledWith(404); + expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); + }); + }); }); From 68bfbdf23c22f25ded0d9ae1d16c62351fad5b90 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Wed, 3 Apr 2024 11:01:12 -0400 Subject: [PATCH 03/10] test: update postTeam function tests --- requirements/teamController/teamController.md | 28 +++++++ src/controllers/teamController.js | 63 ++++++++------ src/controllers/teamController.spec.js | 82 ++++++++++++++++--- src/test/mock-request.js | 5 +- 4 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 requirements/teamController/teamController.md diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md new file mode 100644 index 000000000..768b5ee55 --- /dev/null +++ b/requirements/teamController/teamController.md @@ -0,0 +1,28 @@ +Check mark: ✅ +Cross Mark: ❌ + +# Team Controller + +The Team Controller manages team-related operations, including creating, retrieving, updating, and deleting team information. Below are the various cases handled by the controller. + + +## Functionalities + +### GetAllTeams +- ✅ Retrieves all teams, sorted by team name. +- ✅ Returns a status of 200 with team data on success. +- ❌ Returns a status of 404 with an error message if there's an error during retrieval. + +### GetTeamById +- ✅ Retrieves a specific team by its ID. +- ✅ Returns a status of 200 with team data if the team exists. +- ❌ Returns a status of 404 with an error message if the team does not exist or an error occurs. + +### PostTeam +- ✅ Creates a new team if the requestor has `postTeam` permission and the team name does not already exist. +- ✅ Returns a status of 200 with the created team data on success. +- ❌ Returns a status of 403 if the requestor does not have the necessary permission. +- ❌ Returns a status of 403 with an error message if a team with the same name already exists. +- ❌ Returns a status of 404 with an error message if there's an error during the save operation. + + diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 4a90aea99..ea0e51df0 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -18,7 +18,7 @@ const teamcontroller = function (Team) { .catch((error) => res.status(404).send(error)); }; const postTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'postTeam')) { + if (!(await hasPermission(req.body.requestor, 'postTeam'))) { res.status(403).send({ error: 'You are not authorized to create teams.' }); return; } @@ -34,23 +34,14 @@ const teamcontroller = function (Team) { team.createdDatetime = Date.now(); team.modifiedDatetime = Date.now(); - // Check if a team with the same name already exists - Team.findOne({ teamName: team.teamName }) - .then((existingTeam) => { - if (existingTeam) { - // If a team with the same name exists, return an error - res.status(400).send({ error: 'A team with this name already exists' }); - } else { - // If no team with the same name exists, save the new team - team.save() - .then((results) => res.send(results).status(200)) - .catch((error) => res.send(error).status(404)); - } - }) - .catch((error) => res.send(error).status(404)); + team + .save() + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }; + const deleteTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'deleteTeam')) { + if (!(await hasPermission(req.body.requestor, 'deleteTeam'))) { res.status(403).send({ error: 'You are not authorized to delete teams.' }); return; } @@ -60,11 +51,15 @@ const teamcontroller = function (Team) { res.status(400).send({ error: 'No valid records found' }); return; } - const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); + const removeteamfromprofile = userProfile + .updateMany({}, { $pull: { teams: record._id } }) + .exec(); const deleteteam = record.remove(); Promise.all([removeteamfromprofile, deleteteam]) - .then(res.status(200).send({ message: 'Team successfully deleted and user profiles updated' })) + .then( + res.status(200).send({ message: 'Team successfully deleted and user profiles updated' }), + ) .catch((errors) => { res.status(400).send(errors); }); @@ -73,7 +68,7 @@ const teamcontroller = function (Team) { }); }; const putTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'putTeam')) { + if (!(await hasPermission(req.body.requestor, 'putTeam'))) { res.status(403).send('You are not authorized to make changes in the teams.'); return; } @@ -86,8 +81,9 @@ const teamcontroller = function (Team) { return; } - const canEditTeamCode = req.body.requestor.role === 'Owner' - || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); + const canEditTeamCode = + req.body.requestor.role === 'Owner' || + req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); if (!canEditTeamCode) { res.status(403).send('You are not authorized to edit team code.'); @@ -110,7 +106,7 @@ const teamcontroller = function (Team) { const assignTeamToUsers = async function (req, res) { // verify requestor is administrator, teamId is passed in request params and is valid mongoose objectid, and request body contains an array of users - if (!await hasPermission(req.body.requestor, 'assignTeamToUsers')) { + if (!(await hasPermission(req.body.requestor, 'assignTeamToUsers'))) { res.status(403).send({ error: 'You are not authorized to perform this operation' }); return; } @@ -137,12 +133,27 @@ const teamcontroller = function (Team) { if (cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); if (operation === 'Assign') { - await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }, { new: true }); - const newMember = await userProfile.findOneAndUpdate({ _id: userId }, { $addToSet: { teams: teamId } }, { new: true }); + await Team.findOneAndUpdate( + { _id: teamId }, + { $addToSet: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }, + { new: true }, + ); + const newMember = await userProfile.findOneAndUpdate( + { _id: userId }, + { $addToSet: { teams: teamId } }, + { new: true }, + ); res.status(200).send({ newMember }); } else { - await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }); - await userProfile.findOneAndUpdate({ _id: userId }, { $pull: { teams: teamId } }, { new: true }); + await Team.findOneAndUpdate( + { _id: teamId }, + { $pull: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }, + ); + await userProfile.findOneAndUpdate( + { _id: userId }, + { $pull: { teams: teamId } }, + { new: true }, + ); res.status(200).send({ result: 'Delete Success' }); } } catch (error) { diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 4879ea6f5..886a3e07f 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -1,6 +1,7 @@ const Team = require('../models/team'); const teamController = require('./teamController'); const { mockReq, mockRes } = require('../test'); +const helper = require('../utilities/permissions'); const makeSut = () => { const { getAllTeams, getTeamById, postTeam } = teamController(Team); @@ -11,6 +12,9 @@ const makeSut = () => { }; }; +const mockHasPermission = (value) => + jest.spyOn(helper, 'hasPermission').mockImplementationOnce(() => Promise.resolve(value)); + const flushPromises = () => new Promise(setImmediate); describe('teamController', () => { @@ -46,11 +50,10 @@ describe('teamController', () => { test('should return 404 if an error occurs', async () => { const { getAllTeams } = makeSut(); - const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(new Error('any error')); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); - getAllTeams(mockReq, mockRes); + await flushPromises(); expect(findSpy).toHaveBeenCalledWith({}); @@ -61,13 +64,11 @@ describe('teamController', () => { }); describe('getTeamById', () => { - test('should return a team by ID', async () => { + test.only('should return a team by ID', async () => { const { getTeamById } = makeSut(); - const teamId = '22335'; - const req = { params: { teamId } }; - + const teamId = '5a8e21f00317bc'; const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId: '22335' }); - getTeamById(req, mockRes); + getTeamById(mockReq, mockRes); await flushPromises(); @@ -78,11 +79,10 @@ describe('teamController', () => { test('should return 404 if the team is not found', async () => { const teamId = 'nonExistentTeamId'; - const req = { params: { teamId } }; const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(new Error('any error')); - const { getTeamById } = makeSut(); - getTeamById(req, mockRes); + getTeamById(mockReq, mockRes); + await flushPromises(); expect(findByIdSpy).toHaveBeenCalledWith(teamId); @@ -90,4 +90,66 @@ describe('teamController', () => { expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); }); }); + + describe('postTeam', () => { + test('should successfully create a team', async () => { + const { postTeam } = makeSut(); + const hasPermissionSpy = mockHasPermission(true); + jest.spyOn(Team, 'exists').mockResolvedValue(false); + const mockSave = jest + .spyOn(Team, 'save') + .mockResolvedValue({ teamName: 'Unique Team', isActive: true }); + + await postTeam(mockReq, mockRes); + + expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); + expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); + expect(mockSave).toHaveBeenCalled(); + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.send).toHaveBeenCalledWith({ teamName: 'Unique Team', isActive: true }); + }); + + test('should reject unauthorized request', async () => { + const { postTeam } = makeSut(); + const hasPermissionSpy = mockHasPermission(false); + const response = await postTeam(mockReq, mockRes); + + expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ + error: 'You are not authorized to create teams.', + }); + expect(response).toBeUndefined(); + }); + + test('should reject request if team name already exists', async () => { + const { postTeam } = makeSut(); + jest.spyOn(Team, 'exists').mockResolvedValue(true); + const hasPermissionSpy = mockHasPermission(true); + const response = await postTeam(mockReq, mockRes); + + expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); + expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); + expect(mockRes.status).toHaveBeenCalledWith(403); + expect(mockRes.send).toHaveBeenCalledWith({ + error: `Team Name "${mockReq.body.teamName}" already exists`, + }); + expect(response).toBeUndefined(); + }); + + test('should return 404 if saving the team fails', async () => { + const { postTeam } = makeSut(); + const hasPermissionSpy = mockHasPermission(true); + + jest.spyOn(Team, 'exists').mockResolvedValue(false); + const mockSave = jest.spyOn(Team, 'save').mockRejectedValue(new Error('Error message.')); + await postTeam(mockReq, mockRes); + + expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); + expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); + expect(mockSave).toHaveBeenCalled(); + expect(mockRes.status).toHaveBeenCalledWith(404); + expect(mockRes.send).toHaveBeenCalledWith(new Error('Error message.')); + }); + }); }); diff --git a/src/test/mock-request.js b/src/test/mock-request.js index b522f7f14..32cf5493c 100644 --- a/src/test/mock-request.js +++ b/src/test/mock-request.js @@ -9,7 +9,10 @@ const mockReq = { requestorId: '65cf6c3706d8ac105827bb2e', // this one matches the id of the db/createUser for testing purposes }, }, - params: { userid: '5a7e21f00317bc1538def4b7' }, + params: { + userId: '5a7e21f00317bc1538def4b7', + teamId: '5a8e21f00317bc', + }, }; module.exports = mockReq; From 8a8c507d672cd413fcccc3bdecea55d43f0c9246 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Wed, 3 Apr 2024 11:31:09 -0400 Subject: [PATCH 04/10] test: update tests getAllTeams, getTeamById, and postTeam methods --- src/controllers/teamController.spec.js | 55 +++++++++++--------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 886a3e07f..8b4fbaffb 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -12,6 +12,10 @@ const makeSut = () => { }; }; +jest.mock('../utilities/permissions', () => ({ + hasPermission: jest.fn(), +})); + const mockHasPermission = (value) => jest.spyOn(helper, 'hasPermission').mockImplementationOnce(() => Promise.resolve(value)); @@ -38,7 +42,6 @@ describe('teamController', () => { const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue([team1, team2]); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); const { getAllTeams } = makeSut(); - getAllTeams(mockReq, mockRes); await flushPromises(); @@ -50,10 +53,10 @@ describe('teamController', () => { test('should return 404 if an error occurs', async () => { const { getAllTeams } = makeSut(); + const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(new Error('any error')); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); getAllTeams(mockReq, mockRes); - await flushPromises(); expect(findSpy).toHaveBeenCalledWith({}); @@ -64,51 +67,35 @@ describe('teamController', () => { }); describe('getTeamById', () => { - test.only('should return a team by ID', async () => { + test('should return a team by ID', async () => { const { getTeamById } = makeSut(); + const teamId = '5a8e21f00317bc'; - const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId: '22335' }); + const findByIdSpy = jest + .spyOn(Team, 'findById') + .mockResolvedValue({ teamId: '5a8e21f00317bc' }); getTeamById(mockReq, mockRes); - await flushPromises(); expect(findByIdSpy).toHaveBeenCalledWith(teamId); expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith({ teamId: '22335' }); + expect(mockRes.send).toHaveBeenCalledWith({ teamId: '5a8e21f00317bc' }); }); test('should return 404 if the team is not found', async () => { - const teamId = 'nonExistentTeamId'; - const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(new Error('any error')); const { getTeamById } = makeSut(); - getTeamById(mockReq, mockRes); - + const req = { params: { teamId: 'nonExistentTeamId' } }; + const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(new Error('any error')); + getTeamById(req, mockRes); await flushPromises(); - expect(findByIdSpy).toHaveBeenCalledWith(teamId); + expect(findByIdSpy).toHaveBeenCalledWith(req.params.teamId); expect(mockRes.status).toHaveBeenCalledWith(404); expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); }); }); describe('postTeam', () => { - test('should successfully create a team', async () => { - const { postTeam } = makeSut(); - const hasPermissionSpy = mockHasPermission(true); - jest.spyOn(Team, 'exists').mockResolvedValue(false); - const mockSave = jest - .spyOn(Team, 'save') - .mockResolvedValue({ teamName: 'Unique Team', isActive: true }); - - await postTeam(mockReq, mockRes); - - expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); - expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); - expect(mockSave).toHaveBeenCalled(); - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith({ teamName: 'Unique Team', isActive: true }); - }); - test('should reject unauthorized request', async () => { const { postTeam } = makeSut(); const hasPermissionSpy = mockHasPermission(false); @@ -137,19 +124,21 @@ describe('teamController', () => { expect(response).toBeUndefined(); }); - test('should return 404 if saving the team fails', async () => { + test('should successfully create a team', async () => { const { postTeam } = makeSut(); const hasPermissionSpy = mockHasPermission(true); - jest.spyOn(Team, 'exists').mockResolvedValue(false); - const mockSave = jest.spyOn(Team, 'save').mockRejectedValue(new Error('Error message.')); + const mockSave = jest + .spyOn(Team.prototype, 'save') + .mockResolvedValue({ teamName: 'Unique Team', isActive: true }); + await postTeam(mockReq, mockRes); expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); expect(mockSave).toHaveBeenCalled(); - expect(mockRes.status).toHaveBeenCalledWith(404); - expect(mockRes.send).toHaveBeenCalledWith(new Error('Error message.')); + expect(mockRes.send).toHaveBeenCalledWith({ teamName: 'Unique Team', isActive: true }); + expect(mockRes.status).toHaveBeenCalledWith(200); }); }); }); From b9a204bd031797d074fcc082b6080aa5de16cbcb Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Wed, 3 Apr 2024 18:26:37 -0400 Subject: [PATCH 05/10] test: update tests --- requirements/teamController/teamController.md | 32 ++++++++++++------- src/controllers/teamController.spec.js | 17 +++++----- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md index 768b5ee55..f3b65751d 100644 --- a/requirements/teamController/teamController.md +++ b/requirements/teamController/teamController.md @@ -1,28 +1,36 @@ -Check mark: ✅ -Cross Mark: ❌ # Team Controller -The Team Controller manages team-related operations, including creating, retrieving, updating, and deleting team information. Below are the various cases handled by the controller. - +The Team Controller manages team - related operations, including creating, retrieving, updating, and deleting team information.The cases are categorized into positive, negative, and edge cases for clarity and test prioritization. ## Functionalities ### GetAllTeams -- ✅ Retrieves all teams, sorted by team name. -- ✅ Returns a status of 200 with team data on success. -- ❌ Returns a status of 404 with an error message if there's an error during retrieval. + +#### Negative Cases + - ❌ Returns a status of 404 with an error message if there's an error during retrieval. + +#### Positive Cases + - ✅ Returns a status of 200 with team data on success. ### GetTeamById -- ✅ Retrieves a specific team by its ID. + +#### Negative Cases + - ❌ Returns a status of 404 with an error message if the team does not exist or an error occurs. + +#### Positive Cases + - ✅ Retrieves a specific team by its ID. - ✅ Returns a status of 200 with team data if the team exists. -- ❌ Returns a status of 404 with an error message if the team does not exist or an error occurs. ### PostTeam -- ✅ Creates a new team if the requestor has `postTeam` permission and the team name does not already exist. -- ✅ Returns a status of 200 with the created team data on success. -- ❌ Returns a status of 403 if the requestor does not have the necessary permission. + +#### Negative Cases + - ❌ Returns a status of 403 if the requestor does not have the necessary permission. - ❌ Returns a status of 403 with an error message if a team with the same name already exists. - ❌ Returns a status of 404 with an error message if there's an error during the save operation. +#### Positive Cases + - ✅ Creates a new team if the requestor has `postTeam` permission and the team name does not already exist. +- ✅ Returns a status of 200 with the created team data on success. + diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 8b4fbaffb..527aeb565 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -30,6 +30,8 @@ describe('teamController', () => { sort: () => {}, }; + const error = new Error('any error'); + describe('getAllTeams', () => { test('should return all teams sorted by name', async () => { const team1 = { @@ -54,7 +56,7 @@ describe('teamController', () => { test('should return 404 if an error occurs', async () => { const { getAllTeams } = makeSut(); - const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(new Error('any error')); + const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(error); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); getAllTeams(mockReq, mockRes); await flushPromises(); @@ -62,36 +64,33 @@ describe('teamController', () => { expect(findSpy).toHaveBeenCalledWith({}); expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); expect(mockRes.status).toHaveBeenCalledWith(404); - expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); + expect(mockRes.send).toHaveBeenCalledWith(error); }); }); describe('getTeamById', () => { test('should return a team by ID', async () => { const { getTeamById } = makeSut(); - const teamId = '5a8e21f00317bc'; - const findByIdSpy = jest - .spyOn(Team, 'findById') - .mockResolvedValue({ teamId: '5a8e21f00317bc' }); + const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId }); getTeamById(mockReq, mockRes); await flushPromises(); expect(findByIdSpy).toHaveBeenCalledWith(teamId); expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith({ teamId: '5a8e21f00317bc' }); + expect(mockRes.send).toHaveBeenCalledWith({ teamId }); }); test('should return 404 if the team is not found', async () => { const { getTeamById } = makeSut(); const req = { params: { teamId: 'nonExistentTeamId' } }; - const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(new Error('any error')); + const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(error); getTeamById(req, mockRes); await flushPromises(); expect(findByIdSpy).toHaveBeenCalledWith(req.params.teamId); expect(mockRes.status).toHaveBeenCalledWith(404); - expect(mockRes.send).toHaveBeenCalledWith(new Error('any error')); + expect(mockRes.send).toHaveBeenCalledWith(error); }); }); From 0ecc32280c085c00e2833b452a7ac097b64b2f0b Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Wed, 3 Apr 2024 22:54:03 -0400 Subject: [PATCH 06/10] test: update teamController.md --- requirements/teamController/teamController.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md index f3b65751d..a777056ec 100644 --- a/requirements/teamController/teamController.md +++ b/requirements/teamController/teamController.md @@ -1,36 +1,36 @@ -# Team Controller +Check mark: ✅ +Cross Mark: ❌ -The Team Controller manages team - related operations, including creating, retrieving, updating, and deleting team information.The cases are categorized into positive, negative, and edge cases for clarity and test prioritization. +# Team Controller Test Documentation -## Functionalities +## GetAllTeams -### GetAllTeams +> ### Negative Cases +1. ✅ **Returns 404 - an error occurs during team retrieval.** + +> ### Positive Cases +1. ✅ **Returns 200 - all teams are returned and sorted by name.** -#### Negative Cases - - ❌ Returns a status of 404 with an error message if there's an error during retrieval. -#### Positive Cases - - ✅ Returns a status of 200 with team data on success. +## GetTeamById -### GetTeamById +> ### Negative Cases +1. ✅ **Returns 404 - the specified team ID does not exist.** + +> ### Positive Cases +1. ✅ **Returns 200 - a team is successfully returned by its ID.** -#### Negative Cases - - ❌ Returns a status of 404 with an error message if the team does not exist or an error occurs. -#### Positive Cases - - ✅ Retrieves a specific team by its ID. -- ✅ Returns a status of 200 with team data if the team exists. +## PostTeam -### PostTeam +> ### Negative Cases +1. ✅ **Returns 403 - the requestor lacks `postTeam` permission.** +2. ✅ **Returns 403 - a team with the same name already exists.** + +> ### Positive Cases +1. ✅ **Returns 200 - a new team is successfully created.** -#### Negative Cases - - ❌ Returns a status of 403 if the requestor does not have the necessary permission. -- ❌ Returns a status of 403 with an error message if a team with the same name already exists. -- ❌ Returns a status of 404 with an error message if there's an error during the save operation. -#### Positive Cases - - ✅ Creates a new team if the requestor has `postTeam` permission and the team name does not already exist. -- ✅ Returns a status of 200 with the created team data on success. From 4b7b6970bb8fa3c3cad7bff4f2ef47bb88d41641 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Wed, 3 Apr 2024 23:32:05 -0400 Subject: [PATCH 07/10] refactor: update unit tests --- requirements/teamController/teamController.md | 4 ++-- src/controllers/teamController.spec.js | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md index a777056ec..28b4cb5fb 100644 --- a/requirements/teamController/teamController.md +++ b/requirements/teamController/teamController.md @@ -10,7 +10,7 @@ Cross Mark: ❌ 1. ✅ **Returns 404 - an error occurs during team retrieval.** > ### Positive Cases -1. ✅ **Returns 200 - all teams are returned and sorted by name.** +1. ✅ **Returns 200 - should return all teams sorted by name.** ## GetTeamById @@ -19,7 +19,7 @@ Cross Mark: ❌ 1. ✅ **Returns 404 - the specified team ID does not exist.** > ### Positive Cases -1. ✅ **Returns 200 - a team is successfully returned by its ID.** +1. ✅ **Returns 200 - a team is successfully when the .. returned by its ID.** ## PostTeam diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 527aeb565..765f5811f 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -41,7 +41,8 @@ describe('teamController', () => { teamName: 'Team B', }; - const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue([team1, team2]); + const mockSortResovledValue = [team1, team2]; + const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue(mockSortResovledValue); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); const { getAllTeams } = makeSut(); getAllTeams(mockReq, mockRes); @@ -50,7 +51,7 @@ describe('teamController', () => { expect(findSpy).toHaveBeenCalledWith({}); expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith([team1, team2]); + expect(mockRes.send).toHaveBeenCalledWith(mockSortResovledValue); }); test('should return 404 if an error occurs', async () => { @@ -126,17 +127,16 @@ describe('teamController', () => { test('should successfully create a team', async () => { const { postTeam } = makeSut(); const hasPermissionSpy = mockHasPermission(true); + const mockSaveResolvedValue = { teamName: 'Unique Team', isActive: true }; jest.spyOn(Team, 'exists').mockResolvedValue(false); - const mockSave = jest - .spyOn(Team.prototype, 'save') - .mockResolvedValue({ teamName: 'Unique Team', isActive: true }); + const mockSave = jest.spyOn(Team.prototype, 'save').mockResolvedValue(mockSaveResolvedValue); await postTeam(mockReq, mockRes); expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); expect(mockSave).toHaveBeenCalled(); - expect(mockRes.send).toHaveBeenCalledWith({ teamName: 'Unique Team', isActive: true }); + expect(mockRes.send).toHaveBeenCalledWith(mockSaveResolvedValue); expect(mockRes.status).toHaveBeenCalledWith(200); }); }); From f619eec0e50beb58ea740d9f5f157c178fcff6f4 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Sat, 20 Apr 2024 14:00:19 -0400 Subject: [PATCH 08/10] refactor: Christy Unit tests for the Team Controller's --- requirements/teamController/teamController.md | 2 +- src/controllers/teamController.spec.js | 89 ++++++++----------- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md index 28b4cb5fb..e41e25ae3 100644 --- a/requirements/teamController/teamController.md +++ b/requirements/teamController/teamController.md @@ -19,7 +19,7 @@ Cross Mark: ❌ 1. ✅ **Returns 404 - the specified team ID does not exist.** > ### Positive Cases -1. ✅ **Returns 200 - a team is successfully when the .. returned by its ID.** +1. ✅ **Returns 200 - all is successful, return a team by ID.** ## PostTeam diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 765f5811f..68aa5034a 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -1,6 +1,6 @@ const Team = require('../models/team'); const teamController = require('./teamController'); -const { mockReq, mockRes } = require('../test'); +const { mockReq, mockRes, assertResMock } = require('../test'); const helper = require('../utilities/permissions'); const makeSut = () => { @@ -33,83 +33,72 @@ describe('teamController', () => { const error = new Error('any error'); describe('getAllTeams', () => { - test('should return all teams sorted by name', async () => { - const team1 = { - teamName: 'Team A', - }; - const team2 = { - teamName: 'Team B', - }; + test('Returns 404 - an error occurs during team retrieval.', async () => { + const { getAllTeams } = makeSut(); - const mockSortResovledValue = [team1, team2]; - const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue(mockSortResovledValue); + const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(error); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); - const { getAllTeams } = makeSut(); - getAllTeams(mockReq, mockRes); + const response = getAllTeams(mockReq, mockRes); await flushPromises(); expect(findSpy).toHaveBeenCalledWith({}); expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith(mockSortResovledValue); + assertResMock(404, error, response, mockRes); }); - test('should return 404 if an error occurs', async () => { - const { getAllTeams } = makeSut(); + test('Returns 200 - should return all teams sorted by name.', async () => { + const team1 = { teamName: 'Team A' }; + const team2 = { teamName: 'Team B' }; + const sortedTeams = [team1, team2]; - const mockSort = jest.spyOn(sortObject, 'sort').mockRejectedValueOnce(error); + const mockSortResovledValue = [team1, team2]; + const mockSort = jest.spyOn(sortObject, 'sort').mockResolvedValue(mockSortResovledValue); const findSpy = jest.spyOn(Team, 'find').mockReturnValue(sortObject); - getAllTeams(mockReq, mockRes); + const { getAllTeams } = makeSut(); + const response = getAllTeams(mockReq, mockRes); await flushPromises(); expect(findSpy).toHaveBeenCalledWith({}); expect(mockSort).toHaveBeenCalledWith({ teamName: 1 }); - expect(mockRes.status).toHaveBeenCalledWith(404); - expect(mockRes.send).toHaveBeenCalledWith(error); + assertResMock(200, sortedTeams, response, mockRes); }); }); describe('getTeamById', () => { - test('should return a team by ID', async () => { + test('Returns 404 - the specified team ID does not exist.', async () => { const { getTeamById } = makeSut(); - const teamId = '5a8e21f00317bc'; - const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId }); - getTeamById(mockReq, mockRes); + const req = { params: { teamId: 'nonExistentTeamId' } }; + const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(error); + const response = getTeamById(req, mockRes); await flushPromises(); - expect(findByIdSpy).toHaveBeenCalledWith(teamId); - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.send).toHaveBeenCalledWith({ teamId }); + expect(findByIdSpy).toHaveBeenCalledWith(req.params.teamId); + assertResMock(404, error, response, mockRes); }); - test('should return 404 if the team is not found', async () => { + test('Returns 200 - all is successful, return a team by ID.', async () => { const { getTeamById } = makeSut(); - const req = { params: { teamId: 'nonExistentTeamId' } }; - const findByIdSpy = jest.spyOn(Team, 'findById').mockRejectedValue(error); - getTeamById(req, mockRes); + const teamId = '5a8e21f00317bc'; + const findByIdSpy = jest.spyOn(Team, 'findById').mockResolvedValue({ teamId }); + const response = getTeamById(mockReq, mockRes); await flushPromises(); - expect(findByIdSpy).toHaveBeenCalledWith(req.params.teamId); - expect(mockRes.status).toHaveBeenCalledWith(404); - expect(mockRes.send).toHaveBeenCalledWith(error); + expect(findByIdSpy).toHaveBeenCalledWith(teamId); + assertResMock(200, { teamId }, response, mockRes); }); }); describe('postTeam', () => { - test('should reject unauthorized request', async () => { + test('Returns 403 - the requestor lacks `postTeam` permission.', async () => { const { postTeam } = makeSut(); const hasPermissionSpy = mockHasPermission(false); const response = await postTeam(mockReq, mockRes); expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ - error: 'You are not authorized to create teams.', - }); - expect(response).toBeUndefined(); + assertResMock(403, { error: 'You are not authorized to create teams.' }, response, mockRes); }); - test('should reject request if team name already exists', async () => { + test('Returns 403 - a team with the same name already exists.', async () => { const { postTeam } = makeSut(); jest.spyOn(Team, 'exists').mockResolvedValue(true); const hasPermissionSpy = mockHasPermission(true); @@ -117,27 +106,27 @@ describe('teamController', () => { expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); - expect(mockRes.status).toHaveBeenCalledWith(403); - expect(mockRes.send).toHaveBeenCalledWith({ - error: `Team Name "${mockReq.body.teamName}" already exists`, - }); - expect(response).toBeUndefined(); + assertResMock( + 403, + { error: `Team Name "${mockReq.body.teamName}" already exists` }, + response, + mockRes, + ); }); - test('should successfully create a team', async () => { + test('Returns 200 - a new team is successfully created.', async () => { const { postTeam } = makeSut(); const hasPermissionSpy = mockHasPermission(true); const mockSaveResolvedValue = { teamName: 'Unique Team', isActive: true }; jest.spyOn(Team, 'exists').mockResolvedValue(false); const mockSave = jest.spyOn(Team.prototype, 'save').mockResolvedValue(mockSaveResolvedValue); - await postTeam(mockReq, mockRes); + const response = await postTeam(mockReq, mockRes); expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); expect(mockSave).toHaveBeenCalled(); - expect(mockRes.send).toHaveBeenCalledWith(mockSaveResolvedValue); - expect(mockRes.status).toHaveBeenCalledWith(200); + assertResMock(200, mockSaveResolvedValue, response, mockRes); }); }); }); From 0c072fc36ef5d4dbbd7470b7f3f81d6e415173db Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Sat, 27 Apr 2024 18:35:49 -0400 Subject: [PATCH 09/10] refactor: remove tests for PostTeam --- requirements/teamController/teamController.md | 6 +-- src/controllers/teamController.spec.js | 42 ------------------- 2 files changed, 3 insertions(+), 45 deletions(-) diff --git a/requirements/teamController/teamController.md b/requirements/teamController/teamController.md index e41e25ae3..ad5dd3281 100644 --- a/requirements/teamController/teamController.md +++ b/requirements/teamController/teamController.md @@ -25,11 +25,11 @@ Cross Mark: ❌ ## PostTeam > ### Negative Cases -1. ✅ **Returns 403 - the requestor lacks `postTeam` permission.** -2. ✅ **Returns 403 - a team with the same name already exists.** +1. ❌ **Returns 403 - the requestor lacks `postTeam` permission.** +2. ❌ **Returns 403 - a team with the same name already exists.** > ### Positive Cases -1. ✅ **Returns 200 - a new team is successfully created.** +1. ❌ **Returns 200 - a new team is successfully created.** diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index 68aa5034a..ccc1e2dc4 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -87,46 +87,4 @@ describe('teamController', () => { assertResMock(200, { teamId }, response, mockRes); }); }); - - describe('postTeam', () => { - test('Returns 403 - the requestor lacks `postTeam` permission.', async () => { - const { postTeam } = makeSut(); - const hasPermissionSpy = mockHasPermission(false); - const response = await postTeam(mockReq, mockRes); - - expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); - assertResMock(403, { error: 'You are not authorized to create teams.' }, response, mockRes); - }); - - test('Returns 403 - a team with the same name already exists.', async () => { - const { postTeam } = makeSut(); - jest.spyOn(Team, 'exists').mockResolvedValue(true); - const hasPermissionSpy = mockHasPermission(true); - const response = await postTeam(mockReq, mockRes); - - expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); - expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); - assertResMock( - 403, - { error: `Team Name "${mockReq.body.teamName}" already exists` }, - response, - mockRes, - ); - }); - - test('Returns 200 - a new team is successfully created.', async () => { - const { postTeam } = makeSut(); - const hasPermissionSpy = mockHasPermission(true); - const mockSaveResolvedValue = { teamName: 'Unique Team', isActive: true }; - jest.spyOn(Team, 'exists').mockResolvedValue(false); - const mockSave = jest.spyOn(Team.prototype, 'save').mockResolvedValue(mockSaveResolvedValue); - - const response = await postTeam(mockReq, mockRes); - - expect(hasPermissionSpy).toHaveBeenCalledWith(mockReq.body.requestor, 'postTeam'); - expect(Team.exists).toHaveBeenCalledWith({ teamName: mockReq.body.teamName }); - expect(mockSave).toHaveBeenCalled(); - assertResMock(200, mockSaveResolvedValue, response, mockRes); - }); - }); }); From 297ecc974cb1b30b1f6269904723a594dd5a1995 Mon Sep 17 00:00:00 2001 From: mianmiantea2019 Date: Sun, 5 May 2024 09:32:41 -0400 Subject: [PATCH 10/10] refactor: remove unused code from the getAllTeams and getTeamById tests --- src/controllers/teamController.spec.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/controllers/teamController.spec.js b/src/controllers/teamController.spec.js index ccc1e2dc4..bf6c1b51d 100644 --- a/src/controllers/teamController.spec.js +++ b/src/controllers/teamController.spec.js @@ -1,24 +1,15 @@ const Team = require('../models/team'); const teamController = require('./teamController'); const { mockReq, mockRes, assertResMock } = require('../test'); -const helper = require('../utilities/permissions'); const makeSut = () => { - const { getAllTeams, getTeamById, postTeam } = teamController(Team); + const { getAllTeams, getTeamById } = teamController(Team); return { getAllTeams, getTeamById, - postTeam, }; }; -jest.mock('../utilities/permissions', () => ({ - hasPermission: jest.fn(), -})); - -const mockHasPermission = (value) => - jest.spyOn(helper, 'hasPermission').mockImplementationOnce(() => Promise.resolve(value)); - const flushPromises = () => new Promise(setImmediate); describe('teamController', () => {