diff --git a/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts b/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts index 9f5a23ac52..9ebe42a2b2 100644 --- a/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts +++ b/apps/api/v2/src/ee/bookings/2024-08-13/controllers/e2e/user-bookings.e2e-spec.ts @@ -1581,17 +1581,55 @@ describe("Bookings Endpoints 2024-08-13", () => { }); describe("cancel bookings", () => { + afterEach(async () => { + await bookingsRepositoryFixture.deleteAllBookings(user.id, user.email); + }); + it("should cancel booking", async () => { + const createBody: CreateBookingInput_2024_08_13 = { + start: new Date(Date.UTC(2030, 0, 8, 15, 0, 0)).toISOString(), + eventTypeId, + attendee: { + name: "Mr Proper Cancel", + email: "mr_proper_cancel@gmail.com", + timeZone: "Europe/Rome", + language: "it", + }, + location: "https://meet.google.com/abc-def-ghi", + bookingFieldsResponses: { + customField: "customValue", + }, + metadata: { + userId: "100", + }, + }; + + const createResponse = await request(app.getHttpServer()) + .post("/v2/bookings") + .send(createBody) + .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) + .set(X_CAL_CLIENT_ID, oAuthClient.id) + .expect(201); + + const createResponseBody: CreateBookingOutput_2024_08_13 = createResponse.body; + expect(responseDataIsBooking(createResponseBody.data)).toBe(true); + + if (!responseDataIsBooking(createResponseBody.data)) { + throw new Error("Failed to create booking for test"); + } + + const testBooking: BookingOutput_2024_08_13 = createResponseBody.data; + + const booking = await bookingsRepositoryFixture.getByUid(testBooking.uid); + expect(booking).toBeDefined(); + expect(booking?.status).toEqual("ACCEPTED"); + const body: CancelBookingInput_2024_08_13 = { cancellationReason: "Going on a vacation", }; - const booking = await bookingsRepositoryFixture.getByUid(rescheduledBooking.uid); - expect(booking).toBeDefined(); - expect(booking?.status).toEqual("ACCEPTED"); - return request(app.getHttpServer()) - .post(`/v2/bookings/${rescheduledBooking.uid}/cancel`) + .post(`/v2/bookings/${testBooking.uid}/cancel`) .send(body) .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) .set(X_CAL_CLIENT_ID, oAuthClient.id) @@ -1610,27 +1648,61 @@ describe("Bookings Endpoints 2024-08-13", () => { expect(data.hosts[0].email).toEqual(user.email); expect(data.status).toEqual("cancelled"); expect(data.cancellationReason).toEqual(body.cancellationReason); - expect(data.start).toEqual(rescheduledBooking.start); - expect(data.end).toEqual(rescheduledBooking.end); - expect(data.duration).toEqual(rescheduledBooking.duration); - expect(data.eventTypeId).toEqual(rescheduledBooking.eventTypeId); - expect(data.attendees[0]).toEqual(rescheduledBooking.attendees[0]); - expect(data.location).toEqual(rescheduledBooking.location); - expect(data.absentHost).toEqual(rescheduledBooking.absentHost); + expect(data.start).toEqual(testBooking.start); + expect(data.end).toEqual(testBooking.end); + expect(data.duration).toEqual(testBooking.duration); + expect(data.eventTypeId).toEqual(testBooking.eventTypeId); + expect(data.attendees[0]).toEqual(testBooking.attendees[0]); + expect(data.location).toEqual(testBooking.location); + expect(data.absentHost).toEqual(testBooking.absentHost); - const cancelledBooking = await bookingsRepositoryFixture.getByUid(rescheduledBooking.uid); + const cancelledBooking = await bookingsRepositoryFixture.getByUid(testBooking.uid); expect(cancelledBooking).toBeDefined(); expect(cancelledBooking?.status).toEqual("CANCELLED"); }); }); it("should cancel recurring booking", async () => { + const createBody: CreateRecurringBookingInput_2024_08_13 = { + start: new Date(Date.UTC(2030, 1, 4, 13, 0, 0)).toISOString(), + eventTypeId: recurringEventTypeId, + attendee: { + name: "Mr Proper Recurring Cancel", + email: "mr_proper_recurring_cancel@gmail.com", + timeZone: "Europe/Rome", + language: "it", + }, + location: "https://meet.google.com/abc-def-ghi", + bookingFieldsResponses: { + customField: "customValue", + }, + metadata: { + userId: "100", + }, + }; + + const createResponse = await request(app.getHttpServer()) + .post("/v2/bookings") + .send(createBody) + .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) + .set(X_CAL_CLIENT_ID, oAuthClient.id) + .expect(201); + + const createResponseBody: CreateBookingOutput_2024_08_13 = createResponse.body; + expect(responseDataIsRecurringBooking(createResponseBody.data)).toBe(true); + + if (!responseDataIsRecurringBooking(createResponseBody.data)) { + throw new Error("Failed to create recurring booking for test"); + } + + const testRecurringBooking: RecurringBookingOutput_2024_08_13[] = createResponseBody.data; + const body: CancelBookingInput_2024_08_13 = { cancellationReason: "Going on a vacation", }; return request(app.getHttpServer()) - .post(`/v2/bookings/${createdRecurringBooking[1].recurringBookingUid}/cancel`) + .post(`/v2/bookings/${testRecurringBooking[1].recurringBookingUid}/cancel`) .send(body) .set(CAL_API_VERSION_HEADER, VERSION_2024_08_13) .set(X_CAL_CLIENT_ID, oAuthClient.id) @@ -1643,7 +1715,7 @@ describe("Bookings Endpoints 2024-08-13", () => { if (responseDataIsRecurringBooking(responseBody.data)) { const data: RecurringBookingOutput_2024_08_13[] = responseBody.data; - expect(data.length).toEqual(4); + expect(data.length).toEqual(3); const firstBooking = data[0]; expect(firstBooking.status).toEqual("cancelled"); @@ -1653,9 +1725,6 @@ describe("Bookings Endpoints 2024-08-13", () => { const thirdBooking = data[2]; expect(thirdBooking.status).toEqual("cancelled"); - - const fourthBooking = data[3]; - expect(fourthBooking.status).toEqual("cancelled"); } else { throw new Error( "Invalid response data - expected recurring booking but received non array response" diff --git a/apps/api/v2/src/modules/organizations/event-types/assign-all-team-members.e2e-spec.ts b/apps/api/v2/src/modules/organizations/event-types/assign-all-team-members.e2e-spec.ts index 84b1e0ebfd..fa882df1a8 100644 --- a/apps/api/v2/src/modules/organizations/event-types/assign-all-team-members.e2e-spec.ts +++ b/apps/api/v2/src/modules/organizations/event-types/assign-all-team-members.e2e-spec.ts @@ -63,6 +63,7 @@ describe("Assign all team members", () => { let firstManagedUser: CreateManagedUserData; let secondManagedUser: CreateManagedUserData; + let collectiveEventType: TeamEventTypeOutput_2024_06_14; let roundRobinEventType: TeamEventTypeOutput_2024_06_14; beforeAll(async () => { @@ -315,6 +316,7 @@ describe("Assign all team members", () => { const secondHost = eventTypeHosts.find((host) => host.userId === secondManagedUser.user.id); expect(firstHost).toBeDefined(); expect(secondHost).toBeDefined(); + collectiveEventType = data; }); }); @@ -365,6 +367,28 @@ describe("Assign all team members", () => { }); it("should update round robin event type", async () => { + if (!roundRobinEventType) { + const setupBody: CreateTeamEventTypeInput_2024_06_14 = { + title: "Coding consultation round robin", + slug: `assign-all-team-members-round-robin-${randomString()}`, + lengthInMinutes: 60, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + schedulingType: "roundRobin", + assignAllTeamMembers: true, + }; + + const setupResponse = await request(app.getHttpServer()) + .post(`/v2/organizations/${organization.id}/teams/${managedTeam.id}/event-types`) + .send(setupBody) + .set(X_CAL_SECRET_KEY, oAuthClient.secret) + .set(X_CAL_CLIENT_ID, oAuthClient.id) + .expect(201); + + const setupResponseBody: ApiSuccessResponse = setupResponse.body; + roundRobinEventType = setupResponseBody.data; + } + const body: UpdateTeamEventTypeInput_2024_06_14 = { title: "Coding consultation round robin updated", }; @@ -467,10 +491,17 @@ describe("Assign all team members", () => { }); }); - function evaluateHost(expected: Host, received: Host | undefined) { - expect(expected.userId).toEqual(received?.userId); - expect(expected.mandatory).toEqual(received?.mandatory); - expect(expected.priority).toEqual(received?.priority); + function evaluateHost(expected: Partial, received: Host | undefined) { + if (!received) { + throw new Error(`Host is undefined. Expected userId: ${expected.userId}`); + } + expect(expected.userId).toEqual(received.userId); + if (expected.mandatory !== undefined) { + expect(expected.mandatory).toEqual(received.mandatory); + } + if (expected.priority !== undefined) { + expect(expected.priority).toEqual(received.priority); + } } afterAll(async () => { diff --git a/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts b/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts index a41173d2a4..6662bff7c3 100644 --- a/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts +++ b/apps/api/v2/src/modules/teams/event-types/controllers/teams-event-types.controller.e2e-spec.ts @@ -61,6 +61,48 @@ describe("Organizations Event Types Endpoints", () => { let collectiveEventType: TeamEventTypeOutput_2024_06_14; let managedEventType: TeamEventTypeOutput_2024_06_14; + async function ensureManagedEventType(): Promise { + if (!managedEventType) { + const setupBody: CreateTeamEventTypeInput_2024_06_14 = { + title: `teams-event-types-managed-${randomString()}`, + slug: `teams-event-types-managed-${randomString()}`, + description: "Our team will review your codebase.", + lengthInMinutes: 60, + locations: [ + { + type: "integration", + integration: "cal-video", + }, + ], + schedulingType: "MANAGED", + hosts: [ + { + userId: teamMember1.id, + mandatory: true, + priority: "high", + }, + { + userId: teamMember2.id, + mandatory: false, + priority: "low", + }, + ], + }; + + const setupResponse = await request(app.getHttpServer()) + .post(`/v2/teams/${team.id}/event-types`) + .send(setupBody) + .expect(201); + + const setupResponseBody: ApiSuccessResponse = setupResponse.body; + const responseTeamEvent = setupResponseBody.data.find((event) => event.teamId === team.id); + if (responseTeamEvent) { + managedEventType = responseTeamEvent; + } + } + return managedEventType; + } + beforeAll(async () => { const moduleRef = await withApiAuth( userEmail, @@ -396,29 +438,36 @@ describe("Organizations Event Types Endpoints", () => { const teammate2EventTypes = await eventTypesRepositoryFixture.getAllUserEventTypes(teamMember2.id); const teamEventTypes = await eventTypesRepositoryFixture.getAllTeamEventTypes(team.id); - expect(teammate1EventTypes.length).toEqual(1); - expect(teammate1EventTypes[0].title).toEqual(body.title); - expect(teammate2EventTypes.length).toEqual(1); - expect(teamEventTypes.filter((eventType) => eventType.schedulingType === "MANAGED").length).toEqual( - 1 + const teammate1ManagedEvents = teammate1EventTypes.filter((et) => et.title === body.title); + const teammate2ManagedEvents = teammate2EventTypes.filter((et) => et.title === body.title); + const managedTeamEvents = teamEventTypes.filter( + (eventType) => eventType.schedulingType === "MANAGED" && eventType.title === body.title ); + expect(teammate1ManagedEvents.length).toEqual(1); + expect(teammate1ManagedEvents[0].title).toEqual(body.title); + expect(teammate2ManagedEvents.length).toEqual(1); + expect(managedTeamEvents.length).toEqual(1); + const responseTeamEvent = responseBody.data.find((event) => event.teamId === team.id); expect(responseTeamEvent).toBeDefined(); - expect(responseTeamEvent?.hosts).toEqual([ - { - userId: teamMember1.id, - name: teamMember1.name, - username: teamMember1.username, - avatarUrl: teamMember1.avatarUrl, - }, - { - userId: teamMember2.id, - name: teamMember2.name, - username: teamMember2.username, - avatarUrl: teamMember2.avatarUrl, - }, - ]); + expect(responseTeamEvent?.hosts).toHaveLength(2); + expect(responseTeamEvent?.hosts).toEqual( + expect.arrayContaining([ + { + userId: teamMember1.id, + name: teamMember1.name, + username: teamMember1.username, + avatarUrl: teamMember1.avatarUrl, + }, + { + userId: teamMember2.id, + name: teamMember2.name, + username: teamMember2.username, + avatarUrl: teamMember2.avatarUrl, + }, + ]) + ); if (!responseTeamEvent) { throw new Error("Team event not found"); @@ -437,6 +486,8 @@ describe("Organizations Event Types Endpoints", () => { }); it("managed team event types should be returned when fetching event types of users", async () => { + await ensureManagedEventType(); + return request(app.getHttpServer()) .get(`/v2/event-types?username=${teamMember1.username}`) .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) @@ -446,16 +497,19 @@ describe("Organizations Event Types Endpoints", () => { expect(responseBody.status).toEqual(SUCCESS_STATUS); const data = responseBody.data; - expect(data.length).toEqual(1); - expect(data[0].slug).toEqual(managedEventType.slug); - expect(data[0].ownerId).toEqual(teamMember1.id); - expect(data[0].id).not.toEqual(managedEventType.id); + const managedEvents = data.filter((event) => event.slug === managedEventType.slug); + expect(managedEvents.length).toEqual(1); + expect(managedEvents[0].slug).toEqual(managedEventType.slug); + expect(managedEvents[0].ownerId).toEqual(teamMember1.id); + expect(managedEvents[0].id).not.toEqual(managedEventType.id); }); }); it("managed team event type should be returned when fetching event types of users", async () => { + await ensureManagedEventType(); + return request(app.getHttpServer()) - .get(`/v2/event-types?username=${teamMember1.username}&eventSlug=${managedEventType.slug}`) + .get(`/v2/event-types?username=${teamMember1.username}&eventSlug=${managedEventType?.slug}`) .set(CAL_API_VERSION_HEADER, VERSION_2024_06_14) .expect(200) .then(async (response) => { @@ -463,10 +517,11 @@ describe("Organizations Event Types Endpoints", () => { expect(responseBody.status).toEqual(SUCCESS_STATUS); const data = responseBody.data; - expect(data.length).toEqual(1); - expect(data[0].slug).toEqual(managedEventType.slug); - expect(data[0].ownerId).toEqual(teamMember1.id); - expect(data[0].id).not.toEqual(managedEventType.id); + const managedEventTypes = data.filter((et) => et.slug === managedEventType?.slug); + expect(managedEventTypes.length).toEqual(1); + expect(managedEventTypes[0].slug).toEqual(managedEventType?.slug); + expect(managedEventTypes[0].ownerId).toEqual(teamMember1.id); + expect(managedEventTypes[0].id).not.toEqual(managedEventType?.id); }); }); @@ -570,6 +625,8 @@ describe("Organizations Event Types Endpoints", () => { }); it("should update managed event-type", async () => { + await ensureManagedEventType(); + const newTitle = `teams-event-types-managed-updated-${randomString()}`; const newHosts: UpdateTeamEventTypeInput_2024_06_14["hosts"] = [ { @@ -585,7 +642,7 @@ describe("Organizations Event Types Endpoints", () => { }; return request(app.getHttpServer()) - .patch(`/v2/teams/${team.id}/event-types/${managedEventType.id}`) + .patch(`/v2/teams/${team.id}/event-types/${managedEventType?.id}`) .send(body) .expect(200) .then(async (response) => { @@ -629,12 +686,14 @@ describe("Organizations Event Types Endpoints", () => { }); it("should assign all members to managed event-type", async () => { + await ensureManagedEventType(); + const body: UpdateTeamEventTypeInput_2024_06_14 = { assignAllTeamMembers: true, }; return request(app.getHttpServer()) - .patch(`/v2/teams/${team.id}/event-types/${managedEventType.id}`) + .patch(`/v2/teams/${team.id}/event-types/${managedEventType?.id}`) .send(body) .expect(200) .then(async (response) => { @@ -693,8 +752,10 @@ describe("Organizations Event Types Endpoints", () => { }); it("should delete managed event-type", async () => { + await ensureManagedEventType(); + return request(app.getHttpServer()) - .delete(`/v2/teams/${team.id}/event-types/${managedEventType.id}`) + .delete(`/v2/teams/${team.id}/event-types/${managedEventType?.id}`) .expect(200); });