307 event modification reset user participation (#316)
Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -2,10 +2,22 @@ import { CalendarApi } from "@fullcalendar/core";
|
||||
import { jest } from "@jest/globals";
|
||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||
import "@testing-library/jest-dom";
|
||||
import { act, screen, waitFor, within } from "@testing-library/react";
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from "@testing-library/react";
|
||||
import * as appHooks from "../../src/app/hooks";
|
||||
import * as eventThunks from "../../src/features/Calendars/CalendarSlice";
|
||||
import CalendarApp from "../../src/components/Calendar/Calendar";
|
||||
import EventUpdateModal from "../../src/features/Events/EventUpdateModal";
|
||||
import { renderWithProviders } from "../utils/Renderwithproviders";
|
||||
import {
|
||||
createEventHandlers,
|
||||
EventHandlersProps,
|
||||
} from "../../src/components/Calendar/handlers/eventHandlers";
|
||||
|
||||
describe("CalendarApp integration", () => {
|
||||
const today = new Date();
|
||||
@@ -260,4 +272,283 @@ describe("CalendarApp integration", () => {
|
||||
|
||||
expect(screen.getByText("Public Event")).toBeInTheDocument();
|
||||
});
|
||||
describe("BUGFIX", () => {
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "test",
|
||||
email: "test@test.com",
|
||||
sid: "mockSid",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
},
|
||||
tokens: {
|
||||
accessToken: "token",
|
||||
},
|
||||
},
|
||||
calendars: {
|
||||
list: {
|
||||
"667037022b752d0026472254/cal1": {
|
||||
name: "Calendar 1",
|
||||
id: "667037022b752d0026472254/cal1",
|
||||
color: { light: "#FFFFFF", dark: "#000000" },
|
||||
ownerEmails: ["alice@example.com"],
|
||||
events: {
|
||||
event1: {
|
||||
id: "event1",
|
||||
calId: "667037022b752d0026472254/cal1",
|
||||
uid: "event1",
|
||||
title: "Original Event",
|
||||
start: new Date("2025-11-14T10:31:00.000Z").toISOString(),
|
||||
end: new Date("2025-11-14T11:31:00.000Z").toISOString(),
|
||||
class: "PUBLIC",
|
||||
partstat: "ACCEPTED",
|
||||
organizer: {
|
||||
cn: "Alice",
|
||||
cal_address: "alice@example.com",
|
||||
},
|
||||
attendee: [
|
||||
{
|
||||
cn: "Alice",
|
||||
partstat: "ACCEPTED",
|
||||
rsvp: "TRUE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
cal_address: "alice@example.com",
|
||||
},
|
||||
{
|
||||
cn: "Bob",
|
||||
partstat: "ACCEPTED",
|
||||
rsvp: "TRUE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
cal_address: "bob@example.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pending: false,
|
||||
},
|
||||
};
|
||||
|
||||
it("keeps all attendees event participation on title update", async () => {
|
||||
const updateSpy = jest.spyOn(eventThunks, "putEventAsync");
|
||||
const onClose = jest.fn();
|
||||
renderWithProviders(
|
||||
<EventUpdateModal
|
||||
eventId="event1"
|
||||
calId="667037022b752d0026472254/cal1"
|
||||
open={true}
|
||||
onClose={onClose}
|
||||
typeOfAction="solo"
|
||||
/>,
|
||||
preloadedState
|
||||
);
|
||||
|
||||
const titleInput = await screen.findByDisplayValue("Original Event");
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(titleInput, "Updated Event");
|
||||
});
|
||||
|
||||
const saveButton = screen.getByRole("button", { name: /save/i });
|
||||
await act(async () => {
|
||||
saveButton.click();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(updateSpy).toHaveBeenCalled());
|
||||
|
||||
const dispatchedCalls = updateSpy.mock.calls;
|
||||
expect(dispatchedCalls.length).toBeGreaterThan(0);
|
||||
const updatedEvent = dispatchedCalls[0][0].newEvent;
|
||||
|
||||
// Ensure organizer attendee info is preserved
|
||||
const organizerAttendee = updatedEvent?.attendee?.find(
|
||||
(a: any) => a.cal_address === "alice@example.com"
|
||||
);
|
||||
|
||||
expect(organizerAttendee).toBeTruthy();
|
||||
expect(organizerAttendee?.partstat).toBe("ACCEPTED");
|
||||
expect(organizerAttendee?.role).toBe("CHAIR");
|
||||
|
||||
// Ensure normal attendee info is preserved too
|
||||
const normalAttendee = updatedEvent?.attendee?.find(
|
||||
(a: any) => a.cal_address === "bob@example.com"
|
||||
);
|
||||
|
||||
expect(normalAttendee).toBeTruthy();
|
||||
expect(normalAttendee?.partstat).toBe("ACCEPTED");
|
||||
expect(normalAttendee?.role).toBe("CHAIR"); //will need to be changed as not the right role
|
||||
});
|
||||
|
||||
it("changes normal attendee to need action on time update and no organizer changes", async () => {
|
||||
const updateSpy = jest.spyOn(eventThunks, "putEventAsync");
|
||||
const onClose = jest.fn();
|
||||
renderWithProviders(
|
||||
<EventUpdateModal
|
||||
eventId="event1"
|
||||
calId="667037022b752d0026472254/cal1"
|
||||
open={true}
|
||||
onClose={onClose}
|
||||
typeOfAction="solo"
|
||||
/>,
|
||||
preloadedState
|
||||
);
|
||||
|
||||
const startDateInput = await screen.findByTestId("start-time-input");
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(startDateInput, {
|
||||
target: { value: "08:00" },
|
||||
});
|
||||
});
|
||||
|
||||
const saveButton = screen.getByRole("button", { name: /save/i });
|
||||
await act(async () => {
|
||||
saveButton.click();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(updateSpy).toHaveBeenCalled());
|
||||
|
||||
const dispatchedCalls = updateSpy.mock.calls;
|
||||
expect(dispatchedCalls.length).toBeGreaterThan(0);
|
||||
const updatedEvent = dispatchedCalls[0][0].newEvent;
|
||||
|
||||
// Ensure organizer attendee info is preserved
|
||||
const organizerAttendee = updatedEvent?.attendee?.find(
|
||||
(a: any) => a.cal_address === "alice@example.com"
|
||||
);
|
||||
|
||||
expect(organizerAttendee).toBeTruthy();
|
||||
expect(organizerAttendee?.partstat).toBe("ACCEPTED");
|
||||
expect(organizerAttendee?.role).toBe("CHAIR");
|
||||
|
||||
// Ensure normal attendee partstat is updated
|
||||
const normalAttendee = updatedEvent?.attendee?.find(
|
||||
(a: any) => a.cal_address === "bob@example.com"
|
||||
);
|
||||
|
||||
expect(normalAttendee).toBeTruthy();
|
||||
expect(normalAttendee?.partstat).toBe("NEEDS-ACTION");
|
||||
expect(normalAttendee?.role).toBe("CHAIR"); //will need to be changed as not the right role
|
||||
});
|
||||
it("update event attendees on drag", async () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const updateSpy = jest.spyOn(eventThunks, "putEventAsync");
|
||||
|
||||
const eventHandlers = createEventHandlers({
|
||||
setSelectedRange: jest.fn(),
|
||||
setOpenEventModal: jest.fn(),
|
||||
setTempEvent: jest.fn(),
|
||||
setOpenEventDisplay: jest.fn(),
|
||||
dispatch: mockDispatch,
|
||||
calendarRange: { start: new Date(), end: new Date() },
|
||||
setEventDisplayedId: jest.fn(),
|
||||
setEventDisplayedCalId: jest.fn(),
|
||||
setEventDisplayedTemp: jest.fn(),
|
||||
calendars: preloadedState.calendars.list,
|
||||
setSelectedEvent: jest.fn(),
|
||||
setAfterChoiceFunc: jest.fn(),
|
||||
setOpenEditModePopup: jest.fn(),
|
||||
} as unknown as EventHandlersProps);
|
||||
|
||||
const mockArg = {
|
||||
event: {
|
||||
_def: {
|
||||
extendedProps: {
|
||||
uid: "event1",
|
||||
calId: "667037022b752d0026472254/cal1",
|
||||
},
|
||||
},
|
||||
},
|
||||
// drag event → move by 1 day
|
||||
delta: { years: 0, months: 0, days: 1, milliseconds: 0 },
|
||||
};
|
||||
|
||||
renderCalendar();
|
||||
eventHandlers.handleEventDrop(mockArg);
|
||||
|
||||
expect(updateSpy).toHaveBeenCalled();
|
||||
|
||||
// Extract the dispatched update event
|
||||
const dispatched = updateSpy.mock.calls[0];
|
||||
|
||||
expect(dispatched).toBeTruthy();
|
||||
|
||||
const updatePayload = dispatched[0];
|
||||
const updatedEvent = updatePayload.newEvent;
|
||||
|
||||
// Organizer should remain unchanged
|
||||
const organizer = updatedEvent.attendee.find(
|
||||
(a: any) => a.cal_address === "alice@example.com"
|
||||
);
|
||||
expect(organizer?.partstat).toBe("ACCEPTED");
|
||||
|
||||
// Normal attendee must become NEEDS-ACTION
|
||||
const normal = updatedEvent.attendee.find(
|
||||
(a: any) => a.cal_address === "bob@example.com"
|
||||
);
|
||||
expect(normal?.partstat).toBe("NEEDS-ACTION");
|
||||
});
|
||||
|
||||
it("update event attendees on resize", async () => {
|
||||
const mockDispatch = jest.fn();
|
||||
const updateSpy = jest.spyOn(eventThunks, "putEventAsync");
|
||||
|
||||
const eventHandlers = createEventHandlers({
|
||||
setSelectedRange: jest.fn(),
|
||||
setOpenEventModal: jest.fn(),
|
||||
setTempEvent: jest.fn(),
|
||||
setOpenEventDisplay: jest.fn(),
|
||||
dispatch: mockDispatch,
|
||||
calendarRange: { start: new Date(), end: new Date() },
|
||||
setEventDisplayedId: jest.fn(),
|
||||
setEventDisplayedCalId: jest.fn(),
|
||||
setEventDisplayedTemp: jest.fn(),
|
||||
calendars: preloadedState.calendars.list,
|
||||
setSelectedEvent: jest.fn(),
|
||||
setAfterChoiceFunc: jest.fn(),
|
||||
setOpenEditModePopup: jest.fn(),
|
||||
} as unknown as EventHandlersProps);
|
||||
|
||||
const mockArg = {
|
||||
event: {
|
||||
_def: {
|
||||
extendedProps: {
|
||||
uid: "event1",
|
||||
calId: "667037022b752d0026472254/cal1",
|
||||
},
|
||||
},
|
||||
},
|
||||
startDelta: { years: 0, months: 0, days: 0, milliseconds: 0 },
|
||||
endDelta: { years: 0, months: 0, days: 0, milliseconds: 3600000 }, // 1 hour
|
||||
};
|
||||
|
||||
renderCalendar();
|
||||
eventHandlers.handleEventResize(mockArg);
|
||||
|
||||
expect(updateSpy).toHaveBeenCalled();
|
||||
|
||||
// Extract the dispatched update event
|
||||
const dispatched = updateSpy.mock.calls[0];
|
||||
|
||||
expect(dispatched).toBeTruthy();
|
||||
|
||||
const updatePayload = dispatched[0];
|
||||
const updatedEvent = updatePayload.newEvent;
|
||||
|
||||
// Organizer should remain unchanged
|
||||
const organizer = updatedEvent.attendee.find(
|
||||
(a: any) => a.cal_address === "alice@example.com"
|
||||
);
|
||||
expect(organizer?.partstat).toBe("ACCEPTED");
|
||||
|
||||
// Normal attendee must become NEEDS-ACTION
|
||||
const normal = updatedEvent.attendee.find(
|
||||
(a: any) => a.cal_address === "bob@example.com"
|
||||
);
|
||||
expect(normal?.partstat).toBe("NEEDS-ACTION");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user