[#38]added missing tests

This commit is contained in:
Camille Moussu
2025-07-18 17:29:53 +02:00
parent a52ded03fb
commit 41e8d88841
6 changed files with 439 additions and 2072 deletions
@@ -0,0 +1,117 @@
import { screen, fireEvent } from "@testing-library/react";
import { useAppDispatch } from "../../../src/app/hooks";
import { createCalendar } from "../../../src/features/Calendars/CalendarSlice";
import CalendarPopover from "../../../src/features/Calendars/CalendarModal";
import { renderWithProviders } from "../../utils/Renderwithproviders";
jest.mock("../../../src/app/hooks");
describe("CalendarPopover", () => {
const mockDispatch = jest.fn();
const mockOnClose = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
(useAppDispatch as unknown as jest.Mock).mockReturnValue(mockDispatch);
});
const renderPopover = (open = true) => {
const preloadedState = {
user: {
userData: {
sub: "test",
email: "test@test.com",
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
openpaasId: "667037022b752d0026472254",
},
},
calendars: { list: {}, pending: true },
};
renderWithProviders(
<CalendarPopover
anchorEl={document.body}
open={open}
onClose={mockOnClose}
/>,
preloadedState
);
};
it("renders popover and inputs", () => {
renderPopover();
expect(screen.getByLabelText(/Name/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Description/i)).toBeInTheDocument();
expect(screen.getByText("Create a Calendar")).toBeInTheDocument();
});
it("updates name and description fields", () => {
renderPopover();
const nameInput = screen.getByLabelText(/Name/i);
fireEvent.change(nameInput, { target: { value: "My Calendar" } });
expect(nameInput).toHaveValue("My Calendar");
const descInput = screen.getByLabelText(/Description/i);
fireEvent.change(descInput, { target: { value: "Test description" } });
expect(descInput).toHaveValue("Test description");
});
it("selects a color when a color button is clicked", () => {
renderPopover();
// There are multiple color buttons; pick the first
const colorButtons = screen
.getAllByRole("button")
.filter((btn) => btn.style.backgroundColor !== "");
fireEvent.click(colorButtons[0]);
// The header background should update (check via inline style)
expect(screen.getByText("Create a Calendar").style.backgroundColor).toBe(
colorButtons[0].style.backgroundColor
);
});
it("dispatches createCalendar and calls onClose when Save clicked", () => {
renderPopover();
fireEvent.change(screen.getByLabelText(/Name/i), {
target: { value: "Test Calendar" },
});
fireEvent.change(screen.getByLabelText(/Description/i), {
target: { value: "Test Description" },
});
const expectedColor = "#D50000";
const colorButtons = screen
.getAllByRole("button")
.filter((btn) => btn.style.backgroundColor !== "");
fireEvent.click(colorButtons[0]);
fireEvent.click(screen.getByText(/Save/i));
expect(mockDispatch).toHaveBeenCalledWith(
createCalendar({
name: "Test Calendar",
description: "Test Description",
color: expectedColor,
})
);
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
// Inputs should be reset (optional check)
expect(screen.getByLabelText(/Name/i)).toHaveValue("");
expect(screen.getByLabelText(/Description/i)).toHaveValue("");
});
it("calls onClose when Cancel clicked", () => {
renderPopover();
fireEvent.click(screen.getByText(/Cancel/i));
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
});
@@ -0,0 +1,199 @@
import { screen, fireEvent } from "@testing-library/react";
import {
addEvent,
createCalendar,
} from "../../../src/features/Calendars/CalendarSlice";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import EventPopover from "../../../src/features/Events/EventModal";
import { DateSelectArg } from "@fullcalendar/core";
import { randomUUID } from "crypto";
import { formatDateToYYYYMMDDTHHMMSS } from "../../../src/utils/dateUtils";
import preview from "jest-preview";
import * as appHooks from "../../../src/app/hooks"; // Import the module
describe("EventPopover", () => {
const mockOnClose = jest.fn();
jest.mock("crypto");
const dispatch = jest.fn();
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
beforeEach(() => {
jest.clearAllMocks();
});
const renderPopover = (
selectedRange = {
startStr: "2025-07-18T09:00",
endStr: "2025-07-18T10:00",
start: new Date("2025-07-18T09:00"),
end: new Date("2025-07-18T10:00"),
allDay: false,
resource: undefined,
} as unknown as DateSelectArg
) => {
const preloadedState = {
user: {
userData: {
sub: "test",
email: "test@test.com",
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
openpaasId: "667037022b752d0026472254",
},
organiserData: {
cn: "test",
cal_address: "mailto:test@test.com",
},
},
calendars: {
list: {
"667037022b752d0026472254/cal1": {
name: "Calendar 1",
color: "#FF0000",
},
"667037022b752d0026472254/cal2": {
name: "Calendar 2",
color: "#00FF00",
},
},
pending: false,
},
};
renderWithProviders(
<EventPopover
anchorEl={document.body}
open={true}
onClose={mockOnClose}
selectedRange={selectedRange}
/>,
preloadedState
);
};
it("renders correctly with inputs and calendar options", () => {
renderPopover();
expect(screen.getByText(/Create Event/i)).toBeInTheDocument();
expect(screen.getByLabelText(/title/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Start/i)).toBeInTheDocument();
expect(screen.getByLabelText(/End/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Description/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Location/i)).toBeInTheDocument();
preview.debug();
// Calendar options
const select = screen.getByRole("combobox");
fireEvent.mouseDown(select);
expect(screen.getByText("Calendar 1")).toBeInTheDocument();
expect(screen.getByText("Calendar 2")).toBeInTheDocument();
});
it("fills start and end from selectedRange", () => {
const selectedRange = {
startStr: "2026-07-20T10:00",
endStr: "2026-07-20T12:00",
start: new Date("2026-07-20T10:00"),
end: new Date("2026-07-20T12:00"),
allDay: false,
resource: undefined,
};
renderPopover(selectedRange as unknown as DateSelectArg);
expect(screen.getByLabelText(/Start/i)).toHaveValue("2026-07-20T10:00");
expect(screen.getByLabelText(/End/i)).toHaveValue("2026-07-20T12:00");
});
it("updates inputs on change", () => {
renderWithProviders(
<EventPopover
anchorEl={document.body}
open={true}
onClose={mockOnClose}
selectedRange={null}
/>
);
fireEvent.change(screen.getByLabelText(/title/i), {
target: { value: "My Event" },
});
expect(screen.getByLabelText(/title/i)).toHaveValue("My Event");
fireEvent.change(screen.getByLabelText(/Description/i), {
target: { value: "Event Description" },
});
expect(screen.getByLabelText(/Description/i)).toHaveValue(
"Event Description"
);
fireEvent.change(screen.getByLabelText(/Location/i), {
target: { value: "Conference Room" },
});
expect(screen.getByLabelText(/Location/i)).toHaveValue("Conference Room");
});
it("changes selected calendar", async () => {
renderPopover();
const select = screen.getByRole("combobox");
fireEvent.mouseDown(select); // Open menu
const option = await screen.findByText("Calendar 2");
fireEvent.click(option);
// The Select control value isn't easy to check directly because MUI Select wraps input,
// but we can test by triggering save later
});
it("dispatches addEvent and calls onClose when Save is clicked", () => {
renderPopover();
// Select calendar id
const select = screen.getByRole("combobox");
fireEvent.mouseDown(select);
fireEvent.click(screen.getByText("Calendar 1"));
// Fill inputs
fireEvent.change(screen.getByLabelText(/title/i), {
target: { value: "Meeting" },
});
fireEvent.change(screen.getByLabelText(/Start/i), {
target: { value: "2025-07-18T09:00" },
});
fireEvent.change(screen.getByLabelText(/End/i), {
target: { value: "2025-07-18T10:00" },
});
fireEvent.change(screen.getByLabelText(/Description/i), {
target: { value: "Discuss project" },
});
fireEvent.change(screen.getByLabelText(/Location/i), {
target: { value: "Zoom" },
});
fireEvent.click(screen.getByText(/Save/i));
expect(dispatch).toHaveBeenCalled();
// Extract dispatched action argument
const dispatchedArg = dispatch.mock.calls[0][0].payload;
console.log(dispatchedArg);
expect(dispatchedArg.calendarUid).toBe("667037022b752d0026472254/cal1");
expect(dispatchedArg.event.title).toBe("Meeting");
expect(dispatchedArg.event.description).toBe("Discuss project");
expect(dispatchedArg.event.location).toBe("Zoom");
expect(dispatchedArg.event.color).toBe("#FF0000");
expect(dispatchedArg.event.organizer).toEqual({
cn: "test",
cal_address: "mailto:test@test.com",
});
// onClose should be called
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
it("calls onClose when Cancel clicked", () => {
renderPopover();
fireEvent.click(screen.getByText(/Cancel/i));
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
});
+115
View File
@@ -0,0 +1,115 @@
import { parseCalendarEvent } from "../../../src/features/Events/eventUtils";
describe("parseCalendarEvent", () => {
const baseColor = "#00FF00";
const calendarId = "calendar-123";
it("parses a full event correctly", () => {
const rawData = [
["UID", {}, "text", "event-1"],
["DTSTART", {}, "date-time", "2025-07-18T09:00:00Z"],
["DTEND", {}, "date-time", "2025-07-18T10:00:00Z"],
["SUMMARY", {}, "text", "Team Meeting"],
["DESCRIPTION", {}, "text", "Discuss roadmap"],
["LOCATION", {}, "text", "Zoom"],
["ORGANIZER", { cn: "Alice" }, "cal-address", "mailto:alice@example.com"],
[
"ATTENDEE",
{ cn: "Bob", partstat: "ACCEPTED" },
"cal-address",
"mailto:bob@example.com",
],
["X-OPENPAAS-VIDEOCONFERENCE", {}, "text", "https://meet.link"],
["STATUS", {}, "text", "CONFIRMED"],
["SEQUENCE", {}, "integer", "2"],
["DTSTAMP", {}, "date-time", "2025-07-18T08:00:00Z"],
] as unknown as [string, Record<string, string>, string, any];
const result = parseCalendarEvent(rawData, baseColor, calendarId);
expect(result.uid).toBe("event-1");
expect(result.title).toBe("Team Meeting");
expect(result.description).toBe("Discuss roadmap");
expect(result.location).toBe("Zoom");
expect(result.start).toBe("2025-07-18T09:00:00Z");
expect(result.end).toBe("2025-07-18T10:00:00Z");
expect(result.stamp).toBe("2025-07-18T08:00:00Z");
expect(result.sequence).toBe(2);
expect(result.color).toBe(baseColor);
expect(result.status).toBe("CONFIRMED");
expect(result.x_openpass_videoconference).toBe("https://meet.link");
expect(result.organizer).toEqual({
cn: "Alice",
cal_address: "alice@example.com",
});
expect(result.attendee).toEqual([
{
cn: "Bob",
cal_address: "bob@example.com",
partstat: "ACCEPTED",
rsvp: "",
role: "",
cutype: "",
},
]);
});
it("appends recurrence-id to UID if present", () => {
const rawData: any = [
["UID", {}, "text", "event-2"],
["RECURRENCE-ID", {}, "date-time", "2025-07-18T09:00:00Z"],
["DTSTART", {}, "date-time", "2025-07-18T09:00:00Z"],
];
const result = parseCalendarEvent(rawData, baseColor, calendarId);
expect(result.uid).toBe("event-2/2025-07-18T09:00:00Z");
});
it("returns error if UID or start is missing", () => {
const rawDataMissingUid: any = [
["DTSTART", {}, "date-time", "2025-07-18T09:00:00Z"],
];
const result = parseCalendarEvent(rawDataMissingUid, baseColor, calendarId);
expect(result.error).toMatch(/missing crucial event param/);
const rawDataMissingStart: any = [["UID", {}, "text", "event-3"]];
const result2 = parseCalendarEvent(
rawDataMissingStart,
baseColor,
calendarId
);
expect(result2.error).toMatch(/missing crucial event param/);
});
it("handles optional organizer and attendee fields gracefully", () => {
const rawData = [
["UID", {}, "text", "event-4"],
["DTSTART", {}, "date-time", "2025-07-18T09:00:00Z"],
["ATTENDEE", {}, "cal-address", "mailto:john@example.com"],
["ORGANIZER", {}, "cal-address", "mailto:jane@example.com"],
] as unknown as [string, Record<string, string>, string, any];
const result = parseCalendarEvent(rawData, baseColor, calendarId);
expect(result.attendee).toEqual([
{
cn: "",
cal_address: "john@example.com",
partstat: "",
rsvp: "",
role: "",
cutype: "",
},
]);
expect(result.organizer).toEqual({
cn: "",
cal_address: "jane@example.com",
});
});
});
+2 -2
View File
@@ -45,8 +45,8 @@ describe("HandleLogin", () => {
const preloadedState = {
user: {
userData: {
sub: "cmoussu",
email: "cmoussu@linagora.com",
sub: "test",
email: "test@test.com",
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
openpaasId: "667037022b752d0026472254",
},
+3 -2070
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -56,6 +56,9 @@
"last 1 safari version"
]
},
"engines": {
"node": "24.x"
},
"devDependencies": {
"@babel/preset-env": "^7.28.0",
"@babel/preset-react": "^7.27.1",