diff --git a/src/user-profiles/user-profiles.controller.ts b/src/user-profiles/user-profiles.controller.ts index 1e8af51e..4abff9db 100644 --- a/src/user-profiles/user-profiles.controller.ts +++ b/src/user-profiles/user-profiles.controller.ts @@ -147,6 +147,7 @@ export class UserProfilesController { } @UserPermissions(Permissions.REFERER) + @UseGuards(UserPermissionsGuard) @Get('refered') async findReferedCandidates( @UserPayload('id', new ParseUUIDPipe()) userId: string, diff --git a/tests/messaging/messaging.e2e-spec.ts b/tests/messaging/messaging.e2e-spec.ts index da3678d5..eb1fb422 100644 --- a/tests/messaging/messaging.e2e-spec.ts +++ b/tests/messaging/messaging.e2e-spec.ts @@ -31,8 +31,9 @@ describe('MESSAGING', () => { let conversationFactory: ConversationFactory; let userFactory: UserFactory; let loggedInCandidate: LoggedUser; + let loggedInCoach: LoggedUser; + let loggedInReferer: LoggedUser; let loggedInOtherCandidate: LoggedUser; - let coachs: User[]; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ @@ -67,13 +68,16 @@ describe('MESSAGING', () => { loggedInCandidate = await usersHelper.createLoggedInUser({ role: UserRoles.CANDIDATE, }); + loggedInCoach = await usersHelper.createLoggedInUser({ + role: UserRoles.COACH, + }); + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); loggedInOtherCandidate = await usersHelper.createLoggedInUser({ role: UserRoles.CANDIDATE, }); - - // Create the coach used for the conversations - coachs = await databaseHelper.createEntities(userFactory, NB_CONVERSATIONS); }); afterEach(async () => { @@ -85,13 +89,37 @@ describe('MESSAGING', () => { */ describe('CRUD Messages', () => { describe('C - Create Messages - /messaging/messages', () => { - it('should not create a conversation if a conversation between coach and candidate already exists', async () => { + it('should return 201 but not create a conversation if a conversation between coach and candidate already exists', async () => { + // Create the conversation + const conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); + const nbConversationBefore = await messagingHelper.countConversation(); + + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + conversationId: conversation.id, + }) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(nbConversationBefore); + expect(nbConversation).toBe(1); + }); + + it('should return 201 but not create a conversation if a conversation between referer and candidate already exists', async () => { // Create the conversation const conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInCandidate.user.id, coachs[0].id] + [loggedInCandidate.user.id, loggedInReferer.user.id] ); const nbConversationBefore = await messagingHelper.countConversation(); @@ -109,13 +137,13 @@ describe('MESSAGING', () => { expect(nbConversation).toBe(1); }); - it('should create a message in the conversation', async () => { + it('should return 201 and create a message in the conversation between candidate and coach (sent by candidate)', async () => { // Create the conversation let conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInCandidate.user.id, coachs[0].id] + [loggedInCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = @@ -132,13 +160,13 @@ describe('MESSAGING', () => { expect(conversation.messages.length).toBe(1); }); - it('should return 401 if the user is not a participant of the conversation', async () => { + it('should return 201 and create a message in the conversation between candidate and coach (sent by coach)', async () => { // Create the conversation - const conversation = await conversationFactory.create(); + let conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInOtherCandidate.user.id, coachs[0].id] + [loggedInCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = @@ -148,48 +176,140 @@ describe('MESSAGING', () => { content: 'Super message', conversationId: conversation.id, }) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + .set('authorization', `Bearer ${loggedInCoach.token}`); - expect(response.status).toBe(401); + conversation = await messagingHelper.findConversation(conversation.id); + expect(response.status).toBe(201); + expect(conversation.messages.length).toBe(1); }); - it('should return 400 if neither the participantIds nor the conversationId is provided', async () => { + it('should return 201 and create a message in the conversation between candidate and referer (sent by candidate)', async () => { + // Create the conversation + let conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInReferer.user.id] + ); + const response: APIResponse = await request(server) .post(`/messaging/messages`) .send({ content: 'Super message', + conversationId: conversation.id, }) .set('authorization', `Bearer ${loggedInCandidate.token}`); - expect(response.status).toBe(400); + + conversation = await messagingHelper.findConversation(conversation.id); + expect(response.status).toBe(201); + expect(conversation.messages.length).toBe(1); }); - it('should return 400 when the message is empty', async () => { + it('should return 201 and create a message in the conversation between candidate and referer (sent by referer)', async () => { + // Create the conversation + let conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInReferer.user.id] + ); + + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + conversationId: conversation.id, + }) + .set('authorization', `Bearer ${loggedInReferer.token}`); + + conversation = await messagingHelper.findConversation(conversation.id); + expect(response.status).toBe(201); + expect(conversation.messages.length).toBe(1); + }); + + it('should return 201 and create a message in the conversation between coach and referer (sent by coach)', async () => { + // Create the conversation + let conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCoach.user.id, loggedInReferer.user.id] + ); + + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + conversationId: conversation.id, + }) + .set('authorization', `Bearer ${loggedInCoach.token}`); + + conversation = await messagingHelper.findConversation(conversation.id); + expect(response.status).toBe(201); + expect(conversation.messages.length).toBe(1); + }); + + it('should return 201 and create a message in the conversation between coach and referer (sent by referer)', async () => { + // Create the conversation + let conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCoach.user.id, loggedInReferer.user.id] + ); + + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + conversationId: conversation.id, + }) + .set('authorization', `Bearer ${loggedInReferer.token}`); + + conversation = await messagingHelper.findConversation(conversation.id); + expect(response.status).toBe(201); + expect(conversation.messages.length).toBe(1); + }); + + it('should return 401 if the user is not a participant of the conversation', async () => { // Create the conversation const conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInCandidate.user.id, coachs[0].id] + [loggedInOtherCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = await request(server) .post(`/messaging/messages`) .send({ + content: 'Super message', conversationId: conversation.id, - content: '', + }) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + + expect(response.status).toBe(401); + }); + + it('should return 400 if neither the participantIds nor the conversationId is provided', async () => { + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', }) .set('authorization', `Bearer ${loggedInCandidate.token}`); expect(response.status).toBe(400); }); - it('shoud return 201 when a message is sent by a coach', async () => { + it('should return 400 when the message is empty', async () => { // Create the conversation const conversation = await conversationFactory.create(); - const loggedInCoach = await usersHelper.createLoggedInUser({ - role: UserRoles.COACH, - }); await messagingHelper.associationParticipantsToConversation( conversation.id, @@ -200,11 +320,11 @@ describe('MESSAGING', () => { await request(server) .post(`/messaging/messages`) .send({ - content: 'Super message', conversationId: conversation.id, + content: '', }) - .set('authorization', `Bearer ${loggedInCoach.token}`); - expect(response.status).toBe(201); + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(400); }); }); }); @@ -214,188 +334,322 @@ describe('MESSAGING', () => { */ describe('CRUD Conversations', () => { describe('C - Create conversations - /messaging/messages', () => { - it('should create a conversation if no conversation between coach and candidate doesn t exists', async () => { + it('should return 201 and create a conversation if no conversation between coach and candidate doesn t exists (initiated by Candidate)', async () => { const response: APIResponse = await request(server) .post(`/messaging/messages`) .send({ content: 'Super message', - participantIds: [coachs[0].id], + participantIds: [loggedInCoach.user.id], }) .set('authorization', `Bearer ${loggedInCandidate.token}`); const nbConversation = await messagingHelper.countConversation(); expect(response.status).toBe(201); expect(nbConversation).toBe(1); }); - }); - describe('R - Read conversations - /messaging/conversations', () => { - beforeEach(async () => { - // Create the conversations - const conversations = await databaseHelper.createEntities( - conversationFactory, - NB_CONVERSATIONS - ); - // And link the conversations to the coachs and the logged in candidate - const linkPromises = conversations.map((conversation, idx) => - messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInCandidate.user.id, coachs[idx].id] - ) - ); - await Promise.all(linkPromises); - - // Add messages to the conversations - const messagePromises = conversations.map((conversation) => - messagingHelper.addMessagesToConversation( - 2, - conversation.id, - loggedInCandidate.user.id - ) - ); - - await Promise.all(messagePromises); + it('should return 201 and create a conversation if no conversation between coach and candidate doesn t exists (initiated by Coach)', async () => { + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInCandidate.user.id], + }) + .set('authorization', `Bearer ${loggedInCoach.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); }); - it('should return all conversations', async () => { - const response: APIResponse = + it('should return 201 and create a conversation if no conversation between coach and referer doesn t exists (initiated by Referer)', async () => { + const response: APIResponse = await request(server) - .get(`/messaging/conversations`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInCoach.user.id], + }) + .set('authorization', `Bearer ${loggedInReferer.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); + }); - expect(response.status).toBe(200); - expect(response.body.length).toBe(NB_CONVERSATIONS); + it('should return 201 and create a conversation if no conversation between coach and referer doesn t exists (initiated by Coach)', async () => { + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInReferer.user.id], + }) + .set('authorization', `Bearer ${loggedInCoach.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); }); - it('should return 401 if no token provided', async () => { - const response = await request(server).get(`/messaging/conversations`); + it('should return 201 and create a conversation if no conversation between candidate and referer doesn t exists (initiated by Candidate)', async () => { + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInCandidate.user.id], + }) + .set('authorization', `Bearer ${loggedInReferer.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); + }); - expect(response.status).toBe(401); + it('should return 201 and create a conversation if no conversation between candidate and referer doesn t exists (initiated by Referer)', async () => { + const response: APIResponse = + await request(server) + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInCandidate.user.id], + }) + .set('authorization', `Bearer ${loggedInReferer.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); }); - it('should not return conversation from other users', async () => { - const response: APIResponse = + it('should return 201 and create a conversation if no conversation between candidate and referer doesn t exists (initiated by Candidate)', async () => { + const response: APIResponse = await request(server) - .get(`/messaging/conversations`) - .set('authorization', `Bearer ${loggedInOtherCandidate.token}`); + .post(`/messaging/messages`) + .send({ + content: 'Super message', + participantIds: [loggedInReferer.user.id], + }) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + const nbConversation = await messagingHelper.countConversation(); + expect(response.status).toBe(201); + expect(nbConversation).toBe(1); + }); + }); - expect(response.status).toBe(200); - expect(response.body.length).toBe(0); + describe('R - Read conversations', () => { + let coachs: User[]; + beforeEach(async () => { + coachs = await databaseHelper.createEntities( + userFactory, + NB_CONVERSATIONS, + { + role: UserRoles.COACH, + } + ); }); - it('should return 401 if the user is not logged in', async () => { - const response = await request(server).get(`/messaging/conversations`); + describe('R - Read conversations - /messaging/conversations', () => { + it('should return 401 if no token provided', async () => { + const response = await request(server).get( + `/messaging/conversations` + ); + expect(response.status).toBe(401); + }); - expect(response.status).toBe(401); - }); - }); + describe('Contexte : 1 Candidate -> Coach (x NB_CONVERSATIONS)', () => { + beforeEach(async () => { + // Create the conversations + const conversations = await databaseHelper.createEntities( + conversationFactory, + NB_CONVERSATIONS + ); + // And link the conversations to the coachs and the logged in candidate + const linkPromises = conversations.map((conversation, idx) => + messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, coachs[idx].id] + ) + ); + await Promise.all(linkPromises); + + // Add messages to the conversations + const messagePromises = conversations.map((conversation) => + messagingHelper.addMessagesToConversation( + 2, + conversation.id, + loggedInCandidate.user.id + ) + ); + + await Promise.all(messagePromises); + }); - describe('R - Read conversation - /messaging/conversations/:id', () => { - it('should return the conversation (conversation without message)', async () => { - const conversation = await conversationFactory.create(); + it('should return 200 and all conversations when logged as candidate', async () => { + const response: APIResponse< + MessagingController['getConversations'] + > = await request(server) + .get(`/messaging/conversations`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); - await messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInCandidate.user.id, coachs[0].id] - ); + expect(response.status).toBe(200); + expect(response.body.length).toBe(NB_CONVERSATIONS); + }); - const response: APIResponse = - await request(server) - .get(`/messaging/conversations/${conversation.id}`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + it('should not return conversation from other users', async () => { + const response: APIResponse< + MessagingController['getConversations'] + > = await request(server) + .get(`/messaging/conversations`) + .set('authorization', `Bearer ${loggedInOtherCandidate.token}`); + + expect(response.status).toBe(200); + expect(response.body.length).toBe(0); + }); + }); - expect(response.status).toBe(200); - expect(response.body.id).toBe(conversation.id); - expect(response.body.messages.length).toBe(0); + describe('Contexte : 1 Candidate -> 1 Coach', () => { + it('should return 200 and all conversations when logged as coach', async () => { + const conversation = await conversationFactory.create(); + messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); + + const response: APIResponse< + MessagingController['getConversations'] + > = await request(server) + .get(`/messaging/conversations`) + .set('authorization', `Bearer ${loggedInCoach.token}`); + + expect(response.status).toBe(200); + expect(response.body.length).toBe(1); + }); + }); + + describe('Contexte : 1 Candidate -> 1 Referer', () => { + it('should return 200 and all conversations when logged as referer', async () => { + const conversation = await conversationFactory.create(); + messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInReferer.user.id] + ); + + const response: APIResponse< + MessagingController['getConversations'] + > = await request(server) + .get(`/messaging/conversations`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + + expect(response.status).toBe(200); + expect(response.body.length).toBe(1); + }); + }); }); - it('should return the conversation (conversation with messages)', async () => { - const conversation = await conversationFactory.create(); + describe('R - Read conversation - /messaging/conversations/:id', () => { + it('should return the conversation (conversation without message)', async () => { + const conversation = await conversationFactory.create(); - await messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInCandidate.user.id, coachs[0].id] - ); + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); - await messagingHelper.addMessagesToConversation( - 2, - conversation.id, - loggedInCandidate.user.id - ); + const response: APIResponse = + await request(server) + .get(`/messaging/conversations/${conversation.id}`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); - const response: APIResponse = - await request(server) - .get(`/messaging/conversations/${conversation.id}`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(200); + expect(response.body.id).toBe(conversation.id); + expect(response.body.messages.length).toBe(0); + }); - expect(response.status).toBe(200); - expect(response.body.id).toBe(conversation.id); - expect(response.body.messages.length).toBe(2); - }); + it('should return the conversation (conversation with messages)', async () => { + const conversation = await conversationFactory.create(); - it('should return the conversation only with the messages in the conversation', async () => { - const conversation = await conversationFactory.create(); - const secondConversation = await conversationFactory.create(); + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); - await messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInCandidate.user.id, coachs[0].id] - ); - await messagingHelper.associationParticipantsToConversation( - secondConversation.id, - [loggedInCandidate.user.id, coachs[1].id] - ); + await messagingHelper.addMessagesToConversation( + 2, + conversation.id, + loggedInCandidate.user.id + ); - await messagingHelper.addMessagesToConversation( - 2, - conversation.id, - loggedInCandidate.user.id - ); - await messagingHelper.addMessagesToConversation( - 5, - secondConversation.id, - coachs[1].id - ); + const response: APIResponse = + await request(server) + .get(`/messaging/conversations/${conversation.id}`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); - const response: APIResponse = - await request(server) - .get(`/messaging/conversations/${conversation.id}`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(200); + expect(response.body.id).toBe(conversation.id); + expect(response.body.messages.length).toBe(2); + }); - expect(response.status).toBe(200); - expect(response.body.id).toBe(conversation.id); - expect(response.body.messages.length).toBe(2); - }); + it('should return the conversation only with the messages in the conversation', async () => { + const conversation = await conversationFactory.create(); + const secondConversation = await conversationFactory.create(); - it('should return 401 if the user is not a participant of the conversation', async () => { - const conversation = await conversationFactory.create(); + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, coachs[0].id] + ); + await messagingHelper.associationParticipantsToConversation( + secondConversation.id, + [loggedInCandidate.user.id, coachs[1].id] + ); + + await messagingHelper.addMessagesToConversation( + 2, + conversation.id, + loggedInCandidate.user.id + ); + await messagingHelper.addMessagesToConversation( + 5, + secondConversation.id, + coachs[1].id + ); + + const response: APIResponse = + await request(server) + .get(`/messaging/conversations/${conversation.id}`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + + expect(response.status).toBe(200); + expect(response.body.id).toBe(conversation.id); + expect(response.body.messages.length).toBe(2); + }); - await messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInOtherCandidate.user.id, coachs[0].id] - ); + it('should return 401 if the user is not a participant of the conversation', async () => { + const conversation = await conversationFactory.create(); - const response: APIResponse = - await request(server) - .get(`/messaging/conversations/${conversation.id}`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInOtherCandidate.user.id, loggedInCoach.user.id] + ); - expect(response.status).toBe(401); - }); + const response: APIResponse = + await request(server) + .get(`/messaging/conversations/${conversation.id}`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); - it('should return 401 if the user is not logged in', async () => { - const conversation = await conversationFactory.create(); + expect(response.status).toBe(401); + }); - await messagingHelper.associationParticipantsToConversation( - conversation.id, - [loggedInCandidate.user.id, coachs[0].id] - ); + it('should return 401 if the user is not logged in', async () => { + const conversation = await conversationFactory.create(); - const response = await request(server).get( - `/messaging/conversations/${conversation.id}` - ); + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); - expect(response.status).toBe(401); + const response = await request(server).get( + `/messaging/conversations/${conversation.id}` + ); + + expect(response.status).toBe(401); + }); }); }); }); @@ -404,12 +658,12 @@ describe('MESSAGING', () => { * CRUD - Report */ describe('CRUD - Report', () => { - it('should report a conversation', async () => { + it('should 201 when a candidate report a conversation', async () => { const conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInCandidate.user.id, coachs[0].id] + [loggedInCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = @@ -424,12 +678,52 @@ describe('MESSAGING', () => { expect(response.status).toBe(201); }); + it('should 201 when a coach report a conversation', async () => { + const conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInCoach.user.id] + ); + + const response: APIResponse = + await request(server) + .post(`/messaging/conversations/${conversation.id}/report`) + .set('authorization', `Bearer ${loggedInCoach.token}`) + .send({ + reason: 'SPAM', + comment: 'Cette personne fait du spam', + }); + + expect(response.status).toBe(201); + }); + + it('should 201 when a referer report a conversation', async () => { + const conversation = await conversationFactory.create(); + + await messagingHelper.associationParticipantsToConversation( + conversation.id, + [loggedInCandidate.user.id, loggedInReferer.user.id] + ); + + const response: APIResponse = + await request(server) + .post(`/messaging/conversations/${conversation.id}/report`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send({ + reason: 'SPAM', + comment: 'Cette personne fait du spam', + }); + + expect(response.status).toBe(201); + }); + it('should return 401 if the user is not a participant of the conversation', async () => { const conversation = await conversationFactory.create(); await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInOtherCandidate.user.id, coachs[0].id] + [loggedInOtherCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = @@ -449,7 +743,7 @@ describe('MESSAGING', () => { await messagingHelper.associationParticipantsToConversation( conversation.id, - [loggedInCandidate.user.id, coachs[0].id] + [loggedInCandidate.user.id, loggedInCoach.user.id] ); const response: APIResponse = diff --git a/tests/users/users.e2e-spec.ts b/tests/users/users.e2e-spec.ts index 4953c049..d3ac731b 100644 --- a/tests/users/users.e2e-spec.ts +++ b/tests/users/users.e2e-spec.ts @@ -402,12 +402,12 @@ describe('Users', () => { organization, candidat, coaches, - referer, whatsappZoneCoachName: coachWhatsappZoneCoachName, whatsappZoneCoachUrl: coachWhatsappZoneCoachUrl, whatsappZoneCoachQR: coachWhatsappZoneCoachQR, OrganizationId: coachOrganizationId, referredCandidates: coachReferredCandidates, + referer: coachReferer, ...coach } = await userFactory.create({ role: UserRoles.COACH }, {}, true); @@ -515,12 +515,12 @@ describe('Users', () => { organization, candidat, coaches, - referer, whatsappZoneCoachName: candidateWhatappZoneCoachName, whatsappZoneCoachUrl: candidateWhatappZoneCoachUrl, whatsappZoneCoachQR: candidateWhatappZoneCoachQR, refererId: candidateRefererId, referredCandidates: candidateReferredCandidates, + referer: candidateReferer, ...candidate } = await userFactory.create( { role: UserRoles.CANDIDATE }, @@ -1105,6 +1105,499 @@ describe('Users', () => { expect(response.status).toBe(409); }); }); + describe('/refering - Create user through refering', () => { + let loggedInReferer: LoggedUser; + let loggedInCandidate: LoggedUser; + let loggedInCoach: LoggedUser; + let organization: Organization; + + beforeEach(async () => { + organization = await organizationFactory.create({}, {}, true); + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + OrganizationId: organization.id, + }); + loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + OrganizationId: organization.id, + }); + loggedInCoach = await usersHelper.createLoggedInUser({ + role: UserRoles.COACH, + OrganizationId: organization.id, + }); + }); + + it('Should return 200 and a created candidate if valid candidate data', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchBusinessLines: [{ name: 'id' }] as BusinessLine[], + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(201); + expect(response.body).toEqual( + expect.objectContaining({ + ...userValues, + zone: getZoneFromDepartment(userProfileValues.department), + userProfile: expect.objectContaining({ + department: userProfileValues.department, + helpNeeds: expect.arrayContaining( + userProfileValues.helpNeeds.map((expectation) => + expect.objectContaining(expectation) + ) + ), + }), + }) + ); + }); + + it('Should return 200 and a created candidate if valid candidate data with minimum data', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [{ name: 'cv' }]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + program: Programs.THREE_SIXTY, + workingRight: CandidateYesNoNSPP.YES, + birthDate: '1996-24-04', + searchBusinessLines: [{ name: 'id' }] as BusinessLine[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(201); + expect(response.body).toEqual( + expect.objectContaining({ + ...userValues, + zone: getZoneFromDepartment(userProfileValues.department), + userProfile: expect.objectContaining({ + department: userProfileValues.department, + helpNeeds: expect.arrayContaining( + userProfileValues.helpNeeds.map((expectation) => + expect.objectContaining(expectation) + ) + ), + }), + }) + ); + }); + + it('Should return 400 when has missing mandatory fields', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = []; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + birthDate: '1996-24-04', + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(400); + }); + + it('Should return 400 when has invalid email', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: 'email.fr', // This is the incorrect data + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(400); + }); + + it('Should return 400 when has invalid email', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: 'email.fr', // This is the incorrect data + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(400); + }); + + it('Should return 400 when has invalid phone', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: '1234', // This is the incorrect data + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(400); + }); + + it('Should return 403 when a candidate referer another valid candidate', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchBusinessLines: [{ name: 'id' }] as BusinessLine[], + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInCandidate.token}`) + .send(userToSend); + expect(response.status).toBe(403); + }); + + it('Should return 403 when a candidate referer another valid coach', async () => { + const user = await userFactory.create( + { role: UserRoles.CANDIDATE }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchBusinessLines: [{ name: 'id' }] as BusinessLine[], + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInCoach.token}`) + .send(userToSend); + expect(response.status).toBe(403); + }); + + it('Should return 409 when the email already exist', async () => { + const existingUser = await userFactory.create({}, {}, true); + + const user = await userFactory.create( + { + role: UserRoles.CANDIDATE, + email: existingUser.email, + }, + {}, + false + ); + + const helpNeeds: { name: HelpValue }[] = [ + { name: 'cv' }, + { name: 'interview' }, + ]; + + const userValues = { + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + gender: user.gender, + }; + + const userProfileValues = { + helpNeeds: helpNeeds, + department: 'Paris (75)' as Department, + }; + + const userToSend = { + ...userValues, + ...userProfileValues, + campaign: '1234', + workingRight: CandidateYesNoNSPP.YES, + program: Programs.THREE_SIXTY, + birthDate: '1996-24-04', + nationality: Nationalities.EUROPEAN, + accommodation: CandidateAccommodations.INSERTION, + hasSocialWorker: YesNoJNSPR.YES, + resources: CandidateResources.AAH, + studiesLevel: StudiesLevels.BAC, + workingExperience: WorkingExperienceYears.BETWEEN_3_AND_10_YEARS, + jobSearchDuration: JobSearchDurations.BETWEEN_12_AND_24_MONTHS, + searchBusinessLines: [{ name: 'id' }] as BusinessLine[], + searchAmbitions: [{ name: 'développeur' }] as Ambition[], + }; + + const response: APIResponse< + UsersCreationController['createUserRefering'] + > = await request(server) + .post(`${route}/refering`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send(userToSend); + expect(response.status).toBe(409); + }); + }); }); describe('R - Read 1 User', () => { describe('/:id - Get a user by id or email', () => { @@ -3813,79 +4306,93 @@ describe('Users', () => { }); }); describe('R - Read many Profiles', () => { - describe('/profile - Read all profiles', () => { - it('Should return 401 if user is not logged in', async () => { - const response: APIResponse = - await request(server).get( - `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` - ); - expect(response.status).toBe(401); - }); - it('Should return 400 if no role parameter', async () => { - const loggedInCandidate = await usersHelper.createLoggedInUser({ - role: UserRoles.CANDIDATE, + describe('/profile', () => { + describe('/profile?limit=&offset= - Read all profiles', () => { + it('Should return 401 if user is not logged in', async () => { + const response: APIResponse = + await request(server).get( + `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` + ); + expect(response.status).toBe(401); + }); + it('Should return 400 if no role parameter', async () => { + const loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + }); + const response: APIResponse = + await request(server) + .get(`${route}/profile`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(400); }); - const response: APIResponse = - await request(server) - .get(`${route}/profile`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); - expect(response.status).toBe(400); - }); - it('Should return 200 if user is logged in as admin', async () => { - const loggedInAdmin = await usersHelper.createLoggedInUser({ - role: UserRoles.ADMIN, + it('Should return 200 if user is logged in as admin', async () => { + const loggedInAdmin = await usersHelper.createLoggedInUser({ + role: UserRoles.ADMIN, + }); + const response: APIResponse = + await request(server) + .get( + `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` + ) + .set('authorization', `Bearer ${loggedInAdmin.token}`); + expect(response.status).toBe(200); }); - const response: APIResponse = - await request(server) - .get( - `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` - ) - .set('authorization', `Bearer ${loggedInAdmin.token}`); - expect(response.status).toBe(200); - }); - it('Should return 200 if user is logged in as candidate', async () => { - const loggedInCandidate = await usersHelper.createLoggedInUser({ - role: UserRoles.CANDIDATE, + it('Should return 200 if user is logged in as candidate', async () => { + const loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + }); + const response: APIResponse = + await request(server) + .get( + `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` + ) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(200); }); - const response: APIResponse = - await request(server) - .get( - `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` - ) - .set('authorization', `Bearer ${loggedInCandidate.token}`); - expect(response.status).toBe(200); - }); - it('Should return 200 if user is logged in as coach', async () => { - const loggedInCoach = await usersHelper.createLoggedInUser({ - role: UserRoles.COACH, + it('Should return 200 if user is logged in as coach', async () => { + const loggedInCoach = await usersHelper.createLoggedInUser({ + role: UserRoles.COACH, + }); + const response: APIResponse = + await request(server) + .get( + `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` + ) + .set('authorization', `Bearer ${loggedInCoach.token}`); + expect(response.status).toBe(200); }); - const response: APIResponse = - await request(server) - .get( - `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` - ) - .set('authorization', `Bearer ${loggedInCoach.token}`); - expect(response.status).toBe(200); - }); - it('Should return 400 if no offset or limit parameter', async () => { - const loggedInCandidate = await usersHelper.createLoggedInUser({ - role: UserRoles.CANDIDATE, + it('Should return 200 if user is logged in as referer', async () => { + const loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); + const response: APIResponse = + await request(server) + .get( + `${route}/profile?offset=0&limit=25&role[]=${UserRoles.CANDIDATE}` + ) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(200); }); - const response: APIResponse = - await request(server) - .get(`${route}/profile?role[]=${UserRoles.CANDIDATE}`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); - expect(response.status).toBe(400); - }); - it('Should return 400 if no role parameter', async () => { - const loggedInCandidate = await usersHelper.createLoggedInUser({ - role: UserRoles.CANDIDATE, + it('Should return 400 if no offset or limit parameter', async () => { + const loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + }); + const response: APIResponse = + await request(server) + .get(`${route}/profile?role[]=${UserRoles.CANDIDATE}`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(400); + }); + it('Should return 400 if no role parameter', async () => { + const loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + }); + const response: APIResponse = + await request(server) + .get(`${route}/profile?offset=0&limit=25`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(400); }); - const response: APIResponse = - await request(server) - .get(`${route}/profile?offset=0&limit=25`) - .set('authorization', `Bearer ${loggedInCandidate.token}`); - expect(response.status).toBe(400); }); describe('/profile?limit=&offset=&role[]= - Get paginated and creation date sorted users filtered by role', () => { let loggedInCandidate: LoggedUser; @@ -4929,12 +5436,195 @@ describe('Users', () => { }); }); }); + + describe('/profile/refered', () => { + describe('/profile/refered?limit=&offset= - Read only candidates that current user refered', () => { + let loggedInReferer: LoggedUser; + beforeEach(async () => { + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); + }); + + it('Should return 401 if user is not logged in', async () => { + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server).get( + `${route}/profile/refered?limit=25&offset=0` + ); + expect(response.status).toBe(401); + }); + + it('Should return 200 and empty list if user is logged in as referer but has no candidate refered', async () => { + const loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(200); + expect(response.body).toEqual([]); + }); + + it('Should return 200 and sorted list of candidates refered by current user', async () => { + // Initialize referableCandidates + const referedCandidates = await databaseHelper.createEntities( + userFactory, + 3, + { + role: UserRoles.CANDIDATE, + zone: AdminZones.LILLE, + refererId: loggedInReferer.user.id, + }, + {} + ); + + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(200); + expect(response.body.length).toBe(referedCandidates.length); + expect(response.body).toEqual( + referedCandidates + .sort((userA, userB) => + moment(userB.createdAt).diff(userA.createdAt) + ) + .map((user) => + expect.objectContaining( + userProfilesHelper.mapUserProfileFromUser(user) + ) + ) + ); + }); + + it('Should return 200 and sorted list of candidates refered by current user with limit = 1 and offset = 1', async () => { + // Initialize referableCandidates + const referedCandidates = await databaseHelper.createEntities( + userFactory, + 3, + { + role: UserRoles.CANDIDATE, + zone: AdminZones.LILLE, + refererId: loggedInReferer.user.id, + }, + {} + ); + + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=1&offset=1`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + const sortedReferedCandidates = referedCandidates.sort( + (userA, userB) => moment(userB.createdAt).diff(userA.createdAt) + ); + expect(response.status).toBe(200); + expect(response.body.length).toBe(1); + expect(response.body).toEqual( + [sortedReferedCandidates[1]].map((user) => + expect.objectContaining( + userProfilesHelper.mapUserProfileFromUser(user) + ) + ) + ); + }); + + it('Should return 200 and only own refered candidates', async () => { + // Candidates of referer + const referedCandidates = await databaseHelper.createEntities( + userFactory, + 3, + { + role: UserRoles.CANDIDATE, + zone: AdminZones.LILLE, + refererId: loggedInReferer.user.id, + }, + {} + ); + + // Create other referer and his candidates + const otherLoggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); + await databaseHelper.createEntities( + userFactory, + 5, + { + role: UserRoles.CANDIDATE, + zone: AdminZones.PARIS, + refererId: otherLoggedInReferer.user.id, + }, + {} + ); + + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(200); + expect(response.body.length).toBe(referedCandidates.length); + expect(response.body).toEqual( + referedCandidates + .sort((userA, userB) => + moment(userB.createdAt).diff(userA.createdAt) + ) + .map((user) => + expect.objectContaining( + userProfilesHelper.mapUserProfileFromUser(user) + ) + ) + ); + }); + + it('Should return 403 if user is logged in as candidate', async () => { + const loggedInCandidate = await usersHelper.createLoggedInUser({ + role: UserRoles.CANDIDATE, + }); + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInCandidate.token}`); + expect(response.status).toBe(403); + }); + + it('Should return 403 if user is logged in as coach', async () => { + const loggedInCoach = await usersHelper.createLoggedInUser({ + role: UserRoles.COACH, + }); + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInCoach.token}`); + expect(response.status).toBe(403); + }); + + it('Should return 403 if user is logged in as admin', async () => { + const loggedInAdmin = await usersHelper.createLoggedInUser({ + role: UserRoles.ADMIN, + }); + const response: APIResponse< + UserProfilesController['findReferedCandidates'] + > = await request(server) + .get(`${route}/profile/refered?limit=25&offset=0`) + .set('authorization', `Bearer ${loggedInAdmin.token}`); + expect(response.status).toBe(403); + }); + }); + }); }); describe('U - Update 1 User', () => { describe('/:id - Update user', () => { let loggedInAdmin: LoggedUser; let loggedInCandidate: LoggedUser; let loggedInCoach: LoggedUser; + let loggedInReferer: LoggedUser; beforeEach(async () => { loggedInAdmin = await usersHelper.createLoggedInUser({ @@ -4946,6 +5636,9 @@ describe('Users', () => { loggedInCoach = await usersHelper.createLoggedInUser({ role: UserRoles.COACH, }); + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); }); it('Should return 401 if user is not logged in', async () => { const updates = await userFactory.create({}, {}, false); @@ -4993,6 +5686,23 @@ describe('Users', () => { expect(response.body.phone).toEqual(updates.phone); expect(response.body.address).toEqual(updates.address); }); + it('Should return 200 and updated user when a referer update himself', async () => { + const updates = await userFactory.create({}, {}, false); + const response: APIResponse = + await request(server) + .put(`${route}/${loggedInReferer.user.id}`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send({ + phone: updates.phone, + address: updates.address, + email: updates.email, + firstName: updates.firstName, + lastName: updates.lastName, + }); + expect(response.status).toBe(200); + expect(response.body.phone).toEqual(updates.phone); + expect(response.body.address).toEqual(updates.address); + }); it('Should return 400 when a candidate update himself with invalid phone', async () => { const response: APIResponse = await request(server) @@ -5327,7 +6037,6 @@ describe('Users', () => { const { candidat, coaches, - referer, lastConnection, createdAt, organization, @@ -5341,7 +6050,6 @@ describe('Users', () => { const { candidat: coachCandidat, coaches: coachCoaches, - referer: coachReferer, lastConnection: lastConnectionCoach, createdAt: createdAtCoach, organization: coachOrganization, @@ -5350,6 +6058,7 @@ describe('Users', () => { whatsappZoneCoachUrl: coachWhatsappZoneCoachUrl, whatsappZoneCoachQR: coachWhatsappZoneCoachQR, refererId: coachRefererId, + referer: coachReferer, referredCandidates: coachReferredCandidates, ...restCoach } = loggedInCoach.user; @@ -5386,15 +6095,14 @@ describe('Users', () => { whatsappZoneCoachUrl, whatsappZoneCoachQR, refererId, - referredCandidates, referer, + referredCandidates, ...restCandidate } = loggedInCandidate.user; const { candidat: coachCandidat, coaches: coachCoaches, - referer: coachReferer, lastConnection: lastConnectionCoach, createdAt: createdAtCoach, organization: coachOrganization, @@ -5442,7 +6150,6 @@ describe('Users', () => { lastConnection, createdAt, organization, - referer, ...restCandidate } = loggedInCandidate.user; @@ -5475,7 +6182,6 @@ describe('Users', () => { const { candidat, coaches, - referer, lastConnection, createdAt, organization, @@ -5540,6 +6246,7 @@ describe('Users', () => { let loggedInAdmin: LoggedUser; let loggedInCandidate: LoggedUser; let loggedInCoach: LoggedUser; + let loggedInReferer: LoggedUser; beforeEach(async () => { loggedInAdmin = await usersHelper.createLoggedInUser({ @@ -5551,6 +6258,9 @@ describe('Users', () => { const coach = await userFactory.create({ role: UserRoles.COACH, }); + const referer = await userFactory.create({ + role: UserRoles.REFERER, + }); await userCandidatsHelper.associateCoachAndCandidate(coach, candidat); loggedInCandidate = await usersHelper.createLoggedInUser( candidat, @@ -5562,6 +6272,11 @@ describe('Users', () => { {}, false ); + loggedInReferer = await usersHelper.createLoggedInUser( + referer, + {}, + false + ); }); it('Should return 401, if user not logged in', async () => { const response: APIResponse< @@ -5580,6 +6295,14 @@ describe('Users', () => { .set('authorization', `Bearer ${loggedInAdmin.token}`); expect(response.status).toBe(403); }); + it('Should return 403, if referer checks if note has been updated', async () => { + const response: APIResponse< + UsersController['checkNoteHasBeenModified'] + > = await request(server) + .get(`${route}/candidate/checkUpdate/${loggedInCandidate.user.id}`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(403); + }); it('Should return 200 and noteHasBeenModified, if coach checks if note has been updated', async () => { await userCandidatsHelper.setLastModifiedBy( loggedInCandidate.user.id, @@ -5668,6 +6391,7 @@ describe('Users', () => { let loggedInAdmin: LoggedUser; let loggedInCandidate: LoggedUser; let loggedInCoach: LoggedUser; + let loggedInReferer: LoggedUser; beforeEach(async () => { loggedInAdmin = await usersHelper.createLoggedInUser({ @@ -5679,6 +6403,9 @@ describe('Users', () => { loggedInCoach = await usersHelper.createLoggedInUser({ role: UserRoles.COACH, }); + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); }); it('Should return 401, if user not logged in', async () => { const response: APIResponse = @@ -5695,6 +6422,13 @@ describe('Users', () => { .set('authorization', `Bearer ${loggedInAdmin.token}`); expect(response.status).toBe(403); }); + it('Should return 403, if referer sets the note has been read', async () => { + const response: APIResponse = + await request(server) + .put(`${route}/candidate/read/${loggedInCandidate.user.id}`) + .set('authorization', `Bearer ${loggedInReferer.token}`); + expect(response.status).toBe(403); + }); it('Should return 403, if coach sets the note has been read on candidate not related', async () => { const response: APIResponse = await request(server) @@ -6159,6 +6893,7 @@ describe('Users', () => { let loggedInAdmin: LoggedUser; let loggedInCandidate: LoggedUser; let loggedInCoach: LoggedUser; + let loggedInReferer: LoggedUser; beforeEach(async () => { loggedInAdmin = await usersHelper.createLoggedInUser({ @@ -6170,6 +6905,9 @@ describe('Users', () => { loggedInCoach = await usersHelper.createLoggedInUser({ role: UserRoles.COACH, }); + loggedInReferer = await usersHelper.createLoggedInUser({ + role: UserRoles.REFERER, + }); }); it('Should return 200, and updated opportunities ids, if admin bulk updates some users', async () => { @@ -6220,7 +6958,7 @@ describe('Users', () => { ]) ); }); - it('Should return 403, if not logged in as candidate', async () => { + it('Should return 403, if logged in as candidate', async () => { const originalUsers = await databaseHelper.createEntities( userFactory, 5, @@ -6246,7 +6984,7 @@ describe('Users', () => { }); expect(responseCandidate.status).toBe(403); }); - it('Should return 403, if not logged in as coach', async () => { + it('Should return 403, if logged in as coach', async () => { const originalUsers = await databaseHelper.createEntities( userFactory, 5, @@ -6272,6 +7010,33 @@ describe('Users', () => { }); expect(responseCoach.status).toBe(403); }); + + it('Should return 403, if logged in as referer', async () => { + const originalUsers = await databaseHelper.createEntities( + userFactory, + 5, + { + role: UserRoles.CANDIDATE, + }, + { + userCandidat: { hidden: true }, + } + ); + const originalUsersIds = originalUsers.map(({ id }) => { + return id; + }); + const responseCoach: APIResponse = + await request(server) + .put(`${route}/candidate/bulk`) + .set('authorization', `Bearer ${loggedInReferer.token}`) + .send({ + attributes: { + hidden: true, + }, + ids: originalUsersIds, + }); + expect(responseCoach.status).toBe(403); + }); }); }); // TODO put in unit tests