diff --git a/__tests__/profileController.test.ts b/__tests__/profileController.test.ts deleted file mode 100644 index fbdc59b..0000000 --- a/__tests__/profileController.test.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; -import { - createProfile, - updateProfile, - getAllProfiles, - getProfileById, -} from '../server/controllers/profileController'; -import Profile from '../server/models/profileModel'; - -// TODO -/*eslint jest/no-disabled-tests: "off"*/ - -jest.mock('../server/models/profileModel', () => ({ - findOneAndUpdate: jest.fn(), - findOne: jest.fn(), - create: jest.fn(), - find: jest.fn(), -})); - -xdescribe('Profile Controller Tests', () => { - let mockRequest: Partial; - let mockResponse: Partial; - let mockNext: NextFunction = jest.fn(); - - beforeEach(() => { - mockRequest = {}; - mockResponse = { - status: jest.fn().mockReturnThis(), - json: jest.fn(), - locals: {}, - }; - }); - - describe('createProfile function', () => { - xit('should handle profile creation', async () => { - (Profile.create as jest.Mock).mockResolvedValue({ - _id: 'someId', - bio: 'I am Code', - job: { - title: 'Senior Developer', - company: 'ACME Corp.', - description: 'Working on various projects...', - date: '2021-04-07T00:00:00.000Z', - }, - socials: { - linkedIn: 'https://www.linkedin.com/in/yourprofile', - github: 'https://github.com/yourprofile', - twitter: 'https://twitter.com/yourprofile', - facebook: 'https://www.facebook.com/yourprofile', - instagram: 'https://www.instagram.com/yourprofile', - }, - }); - - mockRequest.body = { - user: '65117c94f000c9930ef5c0ee', - bio: 'I am Code', - job: { - title: 'Senior Developer', - company: 'ACME Corp.', - description: 'Working on various projects', - date: '2021-04-07T00:00:00.000Z', - }, - socials: { - linkedIn: 'https://www.linkedin.com/in/yourprofile', - github: 'https://github.com/yourprofile', - twitter: 'https://twitter.com/yourprofile', - facebook: 'https://www.facebook.com/yourprofile', - instagram: 'https://www.instagram.com/yourprofile', - }, - }; - - await createProfile(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockResponse.json).toHaveBeenCalledWith( - expect.objectContaining({ - _id: 'someId', - bio: 'I am Code', - job: { - title: 'Senior Developer', - company: 'ACME Corp.', - description: 'Working on various projects...', - date: '2021-04-07T00:00:00.000Z', - }, - socials: { - linkedIn: 'https://www.linkedin.com/in/yourprofile', - github: 'https://github.com/yourprofile', - twitter: 'https://twitter.com/yourprofile', - facebook: 'https://www.facebook.com/yourprofile', - instagram: 'https://www.instagram.com/yourprofile', - }, - }), - ); - }); - }); - - describe('updateProfile function', () => { - beforeEach(() => { - jest.clearAllMocks(); - mockRequest = { - params: { userID: '65117c94f000c9930ef5c0ee' }, - body: { - availabilityForNetworking: true, - careerInformation: { - currentPosition: { - company: 'CodeHammers', - title: 'Developer', - }, - pastPositions: [ - { - company: 'CodeHammers', - title: 'Junior Developer', - startDate: '2020-01-01', - endDate: '2021-01-01', - }, - ], - }, - cohort: 'ECRI-TEST', - email: 'test@test.com', - gitHubProfile: 'Ghub', - linkedInProfile: 'Lin', - nickName: 'Johnny', - personalBio: 'I love dogs!', - skills: ['Javascript', 'Typescript', 'React', 'Nodejs'], - socialMediaLinks: 'SMlinks', - specializations: ['Javascript', 'React'], - }, - }; - mockResponse = { - status: jest.fn().mockReturnThis(), - json: jest.fn(), - }; - mockNext = jest.fn(); - }); - - it('should handle profile update', async () => { - (Profile.findOneAndUpdate as jest.Mock).mockResolvedValue({ - _id: '65117c94f000c9930ef5c0ee', - availabilityForNetworking: true, - careerInformation: { - currentPosition: { - company: 'CodeHammers', - title: 'Developer', - }, - pastPositions: [ - { - company: 'CodeHammers', - title: 'Junior Developer', - startDate: '2020-01-01', - endDate: '2021-01-01', - }, - ], - }, - cohort: 'ECRI-TEST', - email: 'test@test.com', - gitHubProfile: 'Ghub', - linkedInProfile: 'Lin', - nickName: 'Johnny', - personalBio: 'I love dogs!', - skills: ['Javascript', 'Typescript', 'React', 'Nodejs'], - socialMediaLinks: 'SMlinks', - specializations: ['Javascript', 'React'], - }); - - await updateProfile(mockRequest as Request, mockResponse as Response, mockNext); - - expect(Profile.findOneAndUpdate).toHaveBeenCalledWith( - { user: '65117c94f000c9930ef5c0ee' }, - mockRequest.body, - { new: true }, - ); - expect(mockResponse.status).toHaveBeenCalledWith(200); - expect(mockResponse.json).toHaveBeenCalledWith(expect.any(Object)); - }); - - it('should handle errors in profile updating', async () => { - (Profile.findOneAndUpdate as jest.Mock).mockRejectedValue(new Error('Update failed')); - - await updateProfile(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith(expect.anything()); - }); - - it('should handle the case where no profile is found', async () => { - (Profile.findOneAndUpdate as jest.Mock).mockResolvedValue(null); - - await updateProfile(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith( - expect.objectContaining({ - log: 'Express error in updateProfile Middleware - NO PROFILE FOUND', - status: 404, - message: { err: 'An error occurred during profile update' }, - }), - ); - }); - }); - - describe('getAllProfiles function', () => { - xit('should handle successful retrieval of all profiles', async () => { - const mockProfiles = [ - { _id: '1', user: 'user1', bio: 'Bio 1' }, - { _id: '2', user: 'user2', bio: 'Bio 2' }, - ]; - (Profile.find as jest.Mock).mockResolvedValue(mockProfiles); - - await getAllProfiles(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockResponse.status).toHaveBeenCalledWith(201); - expect(mockResponse.json).toHaveBeenCalledWith(mockProfiles); - }); - - it('should handle no profiles found', async () => { - (Profile.find as jest.Mock).mockResolvedValue([]); - - await getAllProfiles(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith( - expect.objectContaining({ - log: 'There are no profiles to retrieve', - status: 404, - message: { err: 'There were no profiles to retrieve' }, - }), - ); - }); - - it('should handle errors during profile retrieval', async () => { - const errorMessage = { message: 'Error finding profiles' }; - (Profile.find as jest.Mock).mockRejectedValue(errorMessage); - - await getAllProfiles(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith( - expect.objectContaining({ - log: 'Express error in getAllProfiles Middleware', - status: 500, - message: { err: 'An error occurred during profile creation' }, - }), - ); - }); - }); - - describe('getProfileById function', () => { - beforeEach(() => { - jest.clearAllMocks(); - mockRequest = { params: { userID: 'someUserId' } }; - mockResponse = { - status: jest.fn().mockReturnThis(), - json: jest.fn(), - }; - mockNext = jest.fn(); - }); - - it('should handle successful profile retrieval', async () => { - const mockProfile = { - _id: 'someUserId', - bio: 'User Bio', - //ABBRIEVIATED PROFILE OBJECT - }; - (Profile.findOne as jest.Mock).mockResolvedValue(mockProfile); - - await getProfileById(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockResponse.status).toHaveBeenCalledWith(200); - expect(mockResponse.json).toHaveBeenCalledWith(mockProfile); - }); - - it('should handle profile not found', async () => { - (Profile.findOne as jest.Mock).mockResolvedValue(null); - - await getProfileById(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith( - expect.objectContaining({ - log: 'Profile does not exist', - status: 404, - message: { err: 'An error occurred during profile retrieval' }, - }), - ); - }); - - it('should handle errors', async () => { - const errorMessage = { message: 'Error finding profile' }; - (Profile.findOne as jest.Mock).mockRejectedValue(errorMessage); - - await getProfileById(mockRequest as Request, mockResponse as Response, mockNext); - - expect(mockNext).toHaveBeenCalledWith( - expect.objectContaining({ - log: 'Express error in getProfileById Middleware', - status: 500, - message: { err: 'An error occurred during profile retrieval' }, - }), - ); - }); - }); -}); diff --git a/server/controllers/profileController/getAllProfiles/getAllProfiles.test.ts b/server/controllers/profileController/getAllProfiles/getAllProfiles.test.ts new file mode 100644 index 0000000..14b0279 --- /dev/null +++ b/server/controllers/profileController/getAllProfiles/getAllProfiles.test.ts @@ -0,0 +1,90 @@ +import request from 'supertest'; +import app from '../../../app'; +import Profile from '../../../models/profileModel'; +import User from '../../../models/userModel'; + +const testEmail1 = 'john.doe@codehammers.com'; +const testEmail2 = 'jane.doe@codehammers.com'; +const testPassword = 'password123'; + +//TODO Success tests passed but are disabled until this can be refactored to not ping AWS service +/*eslint jest/no-disabled-tests: "off"*/ + +const createUser = async (email: string) => { + const user = await User.create({ + firstName: 'John', + lastName: 'Doe', + email: email, + password: testPassword, + }); + return user; +}; + +const loginAndGetCookie = async () => { + const response = await request(app) + .post('/api/users/login') + .send({ email: testEmail1, password: testPassword }); + return response.headers['set-cookie']; +}; + +// Commented out for linting pass - "defined but never used" +// const createProfile = async (userId: string, profilePhoto: string | null = null) => { +// const profile = await Profile.create({ +// user: userId, +// firstName: 'John', +// lastName: 'Doe', +// email: profilePhoto ? testEmail1 : testEmail2, +// profilePhoto, +// cohort: 'ECRI 44', +// graduationYear: 2022, +// }); +// return profile; +// }; +//TODO Build this test with S3 mocks to avoid pinging the service every time the test is run. +describe('Tests for profileController.getAllProfiles', () => { + const baseUrl = '/api/profiles'; + let authCookie: string; + + // Temporarily removed to avoid pinging AWS on every test run + // beforeEach(async () => { + // await User.deleteMany(); + // await Profile.deleteMany(); + // const user1 = await createUser(testEmail1); + // const user2 = await createUser(testEmail2); + // authCookie = await loginAndGetCookie(); + // await createProfile(user1._id.toString(), 'photo.jpg'); + // await createProfile(user2._id.toString(), null); + // }); + + describe('Get All Profiles Success Tests', () => { + xit('🧪 Retrieves all profiles successfully with a 200 status and processes S3 URLs', async () => { + const response = await request(app).get(baseUrl).set('Cookie', authCookie).send(); + + expect(response.status).toEqual(201); + expect(response.body.length).toEqual(2); + + expect(response.body[0].firstName).toEqual('John'); + expect(response.body[0].email).toEqual(testEmail1); + expect(response.body[0].profilePhoto).toContain('https://s3.amazonaws.com/'); + + expect(response.body[1].firstName).toEqual('John'); + expect(response.body[1].email).toEqual(testEmail2); + expect(response.body[1].profilePhoto).toBeNull(); + }); + }); + + describe('Get All Profiles Failure Tests', () => { + beforeEach(async () => { + await Profile.deleteMany(); + }); + + it('🧪 Fails when no profiles are found, returning a 404 status', async () => { + await createUser(testEmail1); + authCookie = await loginAndGetCookie(); + const response = await request(app).get(baseUrl).set('Cookie', authCookie).send(); + + expect(response.status).toEqual(404); + expect(response.body[0].message).toEqual('Not Found'); + }); + }); +}); diff --git a/server/controllers/profileController/getAllProfiles/getAllProfiles.ts b/server/controllers/profileController/getAllProfiles/getAllProfiles.ts index 24bd3d4..12d4838 100644 --- a/server/controllers/profileController/getAllProfiles/getAllProfiles.ts +++ b/server/controllers/profileController/getAllProfiles/getAllProfiles.ts @@ -1,5 +1,6 @@ import Profile from '../../../models/profileModel'; -import { Request, Response, NextFunction } from 'express'; +import { Request, Response } from 'express'; +import { NotFoundError } from '../../../errors'; import { IProfile } from '../../../types/profile'; import AWS from 'aws-sdk'; @@ -14,44 +15,32 @@ const s3 = new AWS.S3(); // ENDPOINT GET api/profiles // PURPOSE Get all profiles // ACCESS Private -const getAllProfiles = async (req: Request, res: Response, next: NextFunction) => { - try { - const profiles: IProfile[] = await Profile.find({}); +const getAllProfiles = async (req: Request, res: Response) => { + const profiles: IProfile[] = await Profile.find({}); - if (profiles.length === 0) { - return next({ - log: 'There are no profiles to retrieve', - status: 404, - message: { err: 'There were no profiles to retrieve' }, - }); - } else { - // Route bypass for development - need AWS credentials to work on this route - // This allows Mock Profile Photos to work in development - if (process.env.NODE_ENV === 'development' && !process.env.IS_SK) { - return res.status(200).send(profiles); - } - const processedProfiles = await Promise.all( - profiles.map(async (profile) => { - if (profile.profilePhoto) { - const presignedUrl = s3.getSignedUrl('getObject', { - Bucket: process.env.BUCKET_NAME, - Key: profile.profilePhoto, - Expires: 60 * 5, - }); - profile.profilePhoto = presignedUrl; - } - return profile.toObject(); - }), - ); - - return res.status(201).json(processedProfiles); + if (profiles.length === 0) { + throw new NotFoundError(); + } else { + // Route bypass for development - need AWS credentials to work on this route + // This allows Mock Profile Photos to work in development + if (process.env.NODE_ENV === 'development' && !process.env.IS_SK) { + return res.status(200).send(profiles); } - } catch (error) { - return next({ - log: 'Express error in getAllProfiles Middleware', - status: 500, - message: { err: 'An error occurred during profile creation' }, - }); + const processedProfiles = await Promise.all( + profiles.map(async (profile) => { + if (profile.profilePhoto) { + const presignedUrl = s3.getSignedUrl('getObject', { + Bucket: process.env.BUCKET_NAME, + Key: profile.profilePhoto, + Expires: 60 * 5, + }); + profile.profilePhoto = presignedUrl; + } + return profile.toObject(); + }), + ); + + return res.status(201).json(processedProfiles); } };