* #708 apply strictier linting rules and fix simple eslint bugs * #708 fix eslint errors relate to promise * #708 fix eslint import/no-extraneous-dependencies * #708 fix eslint errors of react-hook * #708 enable eslint check for typescript --------- Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
This commit is contained in:
@@ -1,115 +1,115 @@
|
||||
import * as calendarsApi from "@/features/Calendars/CalendarApi";
|
||||
import * as eventThunks from "@/features/Calendars/services";
|
||||
import EventPopover from "@/features/Events/EventModal";
|
||||
import { api } from "@/utils/apiUtils";
|
||||
import { DateSelectArg } from "@fullcalendar/core";
|
||||
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||
import * as calendarsApi from '@/features/Calendars/CalendarApi'
|
||||
import * as eventThunks from '@/features/Calendars/services'
|
||||
import EventPopover from '@/features/Events/EventModal'
|
||||
import { api } from '@/utils/apiUtils'
|
||||
import { DateSelectArg } from '@fullcalendar/core'
|
||||
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { renderWithProviders } from '../../utils/Renderwithproviders'
|
||||
|
||||
jest.mock("@/utils/apiUtils");
|
||||
jest.mock('@/utils/apiUtils')
|
||||
|
||||
describe("EventPopover", () => {
|
||||
describe('EventPopover', () => {
|
||||
beforeEach(() => {
|
||||
sessionStorage.clear();
|
||||
});
|
||||
sessionStorage.clear()
|
||||
})
|
||||
|
||||
const mockOnClose = jest.fn();
|
||||
const mockSetSelectedRange = jest.fn();
|
||||
const mockCalendarRef = { current: { select: jest.fn() } } as any;
|
||||
const mockOnClose = jest.fn()
|
||||
const mockSetSelectedRange = jest.fn()
|
||||
const mockCalendarRef = { current: { select: jest.fn() } } as any
|
||||
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "test",
|
||||
email: "test@test.com",
|
||||
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
sub: 'test',
|
||||
email: 'test@test.com',
|
||||
sid: 'aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro',
|
||||
openpaasId: '667037022b752d0026472254'
|
||||
},
|
||||
organiserData: {
|
||||
cn: "test",
|
||||
cal_address: "test@test.com",
|
||||
},
|
||||
cn: 'test',
|
||||
cal_address: 'test@test.com'
|
||||
}
|
||||
},
|
||||
calendars: {
|
||||
list: {
|
||||
"667037022b752d0026472254/cal1": {
|
||||
id: "667037022b752d0026472254/cal1",
|
||||
name: "Calendar 1",
|
||||
color: "#FF0000",
|
||||
},
|
||||
"667037022b752d0026472254/cal2": {
|
||||
id: "667037022b752d0026472254/cal2",
|
||||
name: "Calendar 2",
|
||||
color: "#00FF00",
|
||||
'667037022b752d0026472254/cal1': {
|
||||
id: '667037022b752d0026472254/cal1',
|
||||
name: 'Calendar 1',
|
||||
color: '#FF0000'
|
||||
},
|
||||
'667037022b752d0026472254/cal2': {
|
||||
id: '667037022b752d0026472254/cal2',
|
||||
name: 'Calendar 2',
|
||||
color: '#00FF00'
|
||||
}
|
||||
},
|
||||
pending: false,
|
||||
},
|
||||
};
|
||||
pending: false
|
||||
}
|
||||
}
|
||||
|
||||
const mockUsers = [
|
||||
{
|
||||
id: "john@example.com",
|
||||
objectType: "user",
|
||||
id: 'john@example.com',
|
||||
objectType: 'user',
|
||||
emailAddresses: [
|
||||
{
|
||||
value: "john@example.com",
|
||||
type: "default",
|
||||
},
|
||||
value: 'john@example.com',
|
||||
type: 'default'
|
||||
}
|
||||
],
|
||||
names: [
|
||||
{
|
||||
displayName: "John Doe",
|
||||
type: "default",
|
||||
},
|
||||
],
|
||||
displayName: 'John Doe',
|
||||
type: 'default'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "jane@example.com",
|
||||
objectType: "user",
|
||||
id: 'jane@example.com',
|
||||
objectType: 'user',
|
||||
emailAddresses: [
|
||||
{
|
||||
value: "jane@example.com",
|
||||
type: "default",
|
||||
},
|
||||
value: 'jane@example.com',
|
||||
type: 'default'
|
||||
}
|
||||
],
|
||||
names: [
|
||||
{
|
||||
displayName: "Jane Smith",
|
||||
type: "default",
|
||||
},
|
||||
],
|
||||
displayName: 'Jane Smith',
|
||||
type: 'default'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "room1@example.com",
|
||||
objectType: "resource",
|
||||
id: 'room1@example.com',
|
||||
objectType: 'resource',
|
||||
emailAddresses: [
|
||||
{
|
||||
value: "room1@example.com",
|
||||
type: "default",
|
||||
},
|
||||
value: 'room1@example.com',
|
||||
type: 'default'
|
||||
}
|
||||
],
|
||||
names: [
|
||||
{
|
||||
displayName: "Room 1",
|
||||
type: "default",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
(api.post as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUsers),
|
||||
});
|
||||
displayName: 'Room 1',
|
||||
type: 'default'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
;(api.post as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUsers)
|
||||
})
|
||||
|
||||
const defaultSelectedRange = {
|
||||
startStr: "2025-07-18T09:00",
|
||||
endStr: "2025-07-18T10:00",
|
||||
start: new Date("2025-07-18T09:00"),
|
||||
end: new Date("2025-07-18T10:00"),
|
||||
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;
|
||||
resource: undefined
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
const renderPopover = (selectedRange = defaultSelectedRange) => {
|
||||
renderWithProviders(
|
||||
@@ -122,461 +122,459 @@ describe("EventPopover", () => {
|
||||
calendarRef={mockCalendarRef}
|
||||
/>,
|
||||
preloadedState
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
it("renders correctly with inputs and calendar options", () => {
|
||||
renderPopover();
|
||||
it('renders correctly with inputs and calendar options', () => {
|
||||
renderPopover()
|
||||
|
||||
// Check dialog title
|
||||
expect(screen.getByText("event.createEvent")).toBeInTheDocument();
|
||||
expect(screen.getByText('event.createEvent')).toBeInTheDocument()
|
||||
|
||||
// Check inputs exist by their roles
|
||||
const titleInput = screen.getByRole("textbox", { name: /title/i });
|
||||
expect(titleInput).toBeInTheDocument();
|
||||
const titleInput = screen.getByRole('textbox', { name: /title/i })
|
||||
expect(titleInput).toBeInTheDocument()
|
||||
|
||||
// Description input is only visible after clicking "Add description" button
|
||||
const addDescriptionButton = screen.getByRole("button", {
|
||||
name: "event.form.addDescription",
|
||||
});
|
||||
expect(addDescriptionButton).toBeInTheDocument();
|
||||
const addDescriptionButton = screen.getByRole('button', {
|
||||
name: 'event.form.addDescription'
|
||||
})
|
||||
expect(addDescriptionButton).toBeInTheDocument()
|
||||
|
||||
// In normal mode calendar is a SectionPreviewRow (button), not combobox
|
||||
expect(
|
||||
screen.getByRole("button", { name: "Calendar 1" })
|
||||
).toBeInTheDocument();
|
||||
screen.getByRole('button', { name: 'Calendar 1' })
|
||||
).toBeInTheDocument()
|
||||
|
||||
// Check button
|
||||
expect(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
).toBeInTheDocument();
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
).toBeInTheDocument()
|
||||
|
||||
// Extended mode
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
|
||||
|
||||
// Back button appears
|
||||
expect(screen.getByLabelText("show less")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('show less')).toBeInTheDocument()
|
||||
|
||||
// Extended labels appear
|
||||
expect(screen.getAllByText("event.form.repeat")).toHaveLength(1);
|
||||
expect(screen.getAllByText("event.form.notification")).toHaveLength(1);
|
||||
expect(screen.getAllByText("event.form.visibleTo")).toHaveLength(1);
|
||||
expect(screen.getAllByText("event.form.showMeAs")).toHaveLength(1);
|
||||
});
|
||||
expect(screen.getAllByText('event.form.repeat')).toHaveLength(1)
|
||||
expect(screen.getAllByText('event.form.notification')).toHaveLength(1)
|
||||
expect(screen.getAllByText('event.form.visibleTo')).toHaveLength(1)
|
||||
expect(screen.getAllByText('event.form.showMeAs')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it("fills start from selectedRange", () => {
|
||||
it('fills start from selectedRange', () => {
|
||||
renderPopover({
|
||||
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,
|
||||
} as unknown as DateSelectArg);
|
||||
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
|
||||
} as unknown as DateSelectArg)
|
||||
|
||||
// Expand to show date/time inputs (normal mode shows DateTimeSummary)
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
|
||||
expect(screen.getByTestId("start-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("start-time-input")).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
|
||||
expect(screen.getByTestId('start-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('start-time-input')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("updates inputs on change", () => {
|
||||
renderPopover();
|
||||
it('updates inputs on change', () => {
|
||||
renderPopover()
|
||||
|
||||
fireEvent.change(screen.getByLabelText("event.form.title"), {
|
||||
target: { value: "My Event" },
|
||||
});
|
||||
expect(screen.getByLabelText("event.form.title")).toHaveValue("My Event");
|
||||
fireEvent.change(screen.getByLabelText('event.form.title'), {
|
||||
target: { value: 'My Event' }
|
||||
})
|
||||
expect(screen.getByLabelText('event.form.title')).toHaveValue('My Event')
|
||||
|
||||
// Click "Add description" button first
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "event.form.addDescription" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'event.form.addDescription' })
|
||||
)
|
||||
|
||||
fireEvent.change(screen.getByLabelText("event.form.description"), {
|
||||
target: { value: "Event Description" },
|
||||
});
|
||||
expect(screen.getByLabelText("event.form.description")).toHaveValue(
|
||||
"Event Description"
|
||||
);
|
||||
fireEvent.change(screen.getByLabelText('event.form.description'), {
|
||||
target: { value: 'Event Description' }
|
||||
})
|
||||
expect(screen.getByLabelText('event.form.description')).toHaveValue(
|
||||
'Event Description'
|
||||
)
|
||||
|
||||
// Expand location section (normal mode shows SectionPreviewRow)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "event.form.locationPlaceholder" })
|
||||
);
|
||||
fireEvent.change(screen.getByLabelText("event.form.location"), {
|
||||
target: { value: "Conference Room" },
|
||||
});
|
||||
expect(screen.getByLabelText("event.form.location")).toHaveValue(
|
||||
"Conference Room"
|
||||
);
|
||||
});
|
||||
screen.getByRole('button', { name: 'event.form.locationPlaceholder' })
|
||||
)
|
||||
fireEvent.change(screen.getByLabelText('event.form.location'), {
|
||||
target: { value: 'Conference Room' }
|
||||
})
|
||||
expect(screen.getByLabelText('event.form.location')).toHaveValue(
|
||||
'Conference Room'
|
||||
)
|
||||
})
|
||||
|
||||
it("changes selected calendar", async () => {
|
||||
renderPopover();
|
||||
it('changes selected calendar', async () => {
|
||||
renderPopover()
|
||||
|
||||
// Expand to show calendar combobox (normal mode shows SectionPreviewRow)
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
|
||||
const select = screen.getByLabelText("event.form.calendar");
|
||||
fireEvent.mouseDown(select); // Open menu
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
|
||||
const select = screen.getByLabelText('event.form.calendar')
|
||||
fireEvent.mouseDown(select) // Open menu
|
||||
|
||||
const option = await screen.findByText("Calendar 2");
|
||||
fireEvent.click(option);
|
||||
const option = await screen.findByText('Calendar 2')
|
||||
fireEvent.click(option)
|
||||
|
||||
const calendarSelect = screen.getByRole("combobox", { name: /Calendar/i });
|
||||
expect(calendarSelect).toHaveTextContent("Calendar 2");
|
||||
});
|
||||
it("adds a attendee", async () => {
|
||||
jest.useFakeTimers();
|
||||
const calendarSelect = screen.getByRole('combobox', { name: /Calendar/i })
|
||||
expect(calendarSelect).toHaveTextContent('Calendar 2')
|
||||
})
|
||||
it('adds a attendee', async () => {
|
||||
jest.useFakeTimers()
|
||||
try {
|
||||
jest
|
||||
.spyOn(calendarsApi, "getCalendars")
|
||||
.mockReturnValue({ json: jest.fn() });
|
||||
renderPopover();
|
||||
fireEvent.change(screen.getByLabelText("event.form.title"), {
|
||||
target: { value: "newEvent" },
|
||||
});
|
||||
const select = screen.getByLabelText("peopleSearch.label");
|
||||
.spyOn(calendarsApi, 'getCalendars')
|
||||
.mockReturnValue({ json: jest.fn() })
|
||||
renderPopover()
|
||||
fireEvent.change(screen.getByLabelText('event.form.title'), {
|
||||
target: { value: 'newEvent' }
|
||||
})
|
||||
const select = screen.getByLabelText('peopleSearch.label')
|
||||
|
||||
act(() => {
|
||||
select.focus();
|
||||
fireEvent.mouseDown(select);
|
||||
userEvent.type(select, "john");
|
||||
});
|
||||
select.focus()
|
||||
fireEvent.mouseDown(select)
|
||||
userEvent.type(select, 'john')
|
||||
})
|
||||
await act(async () => {
|
||||
jest.advanceTimersByTime(400);
|
||||
});
|
||||
await waitFor(() => expect(api.post).toHaveBeenCalledTimes(1));
|
||||
jest.advanceTimersByTime(400)
|
||||
})
|
||||
await waitFor(() => expect(api.post).toHaveBeenCalledTimes(1))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("John Doe")).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('John Doe')).toBeInTheDocument()
|
||||
})
|
||||
await act(async () => {
|
||||
userEvent.click(screen.getByText("John Doe"));
|
||||
});
|
||||
userEvent.click(screen.getByText('John Doe'))
|
||||
})
|
||||
|
||||
const spy = jest
|
||||
.spyOn(eventThunks, "putEventAsync")
|
||||
.mockImplementation((payload) => {
|
||||
const promise = Promise.resolve(payload);
|
||||
(promise as any).unwrap = () => promise;
|
||||
return () => promise as any;
|
||||
});
|
||||
.spyOn(eventThunks, 'putEventAsync')
|
||||
.mockImplementation(payload => {
|
||||
const promise = Promise.resolve(payload)
|
||||
;(promise as any).unwrap = () => promise
|
||||
return () => promise as any
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "actions.save" }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'actions.save' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
const receivedPayload = spy.mock.calls[0][0];
|
||||
const receivedPayload = spy.mock.calls[0][0]
|
||||
|
||||
expect(receivedPayload.cal).toEqual(
|
||||
preloadedState.calendars.list["667037022b752d0026472254/cal1"]
|
||||
);
|
||||
preloadedState.calendars.list['667037022b752d0026472254/cal1']
|
||||
)
|
||||
|
||||
expect(receivedPayload.newEvent.attendee).toHaveLength(2);
|
||||
expect(receivedPayload.newEvent.attendee).toHaveLength(2)
|
||||
expect(receivedPayload.newEvent.attendee).toStrictEqual([
|
||||
{
|
||||
cn: "test",
|
||||
cal_address: "test@test.com",
|
||||
partstat: "ACCEPTED",
|
||||
rsvp: "FALSE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
cn: 'test',
|
||||
cal_address: 'test@test.com',
|
||||
partstat: 'ACCEPTED',
|
||||
rsvp: 'FALSE',
|
||||
role: 'CHAIR',
|
||||
cutype: 'INDIVIDUAL'
|
||||
},
|
||||
{
|
||||
cn: "John Doe",
|
||||
cal_address: "john@example.com",
|
||||
partstat: "NEEDS-ACTION",
|
||||
rsvp: "FALSE",
|
||||
role: "REQ-PARTICIPANT",
|
||||
cutype: "INDIVIDUAL",
|
||||
},
|
||||
]);
|
||||
cn: 'John Doe',
|
||||
cal_address: 'john@example.com',
|
||||
partstat: 'NEEDS-ACTION',
|
||||
rsvp: 'FALSE',
|
||||
role: 'REQ-PARTICIPANT',
|
||||
cutype: 'INDIVIDUAL'
|
||||
}
|
||||
])
|
||||
} finally {
|
||||
jest.useRealTimers();
|
||||
jest.useRealTimers()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
it("adds a resource", async () => {
|
||||
jest.useFakeTimers();
|
||||
it('adds a resource', async () => {
|
||||
jest.useFakeTimers()
|
||||
try {
|
||||
renderPopover();
|
||||
fireEvent.change(screen.getByLabelText("event.form.title"), {
|
||||
target: { value: "newEventWithResource" },
|
||||
});
|
||||
renderPopover()
|
||||
fireEvent.change(screen.getByLabelText('event.form.title'), {
|
||||
target: { value: 'newEventWithResource' }
|
||||
})
|
||||
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const resourceCombobox = screen.getByPlaceholderText(
|
||||
"resourceSearch.placeholder"
|
||||
);
|
||||
'resourceSearch.placeholder'
|
||||
)
|
||||
|
||||
act(() => {
|
||||
resourceCombobox.focus();
|
||||
fireEvent.mouseDown(resourceCombobox);
|
||||
});
|
||||
await userEvent.type(resourceCombobox, "room");
|
||||
resourceCombobox.focus()
|
||||
fireEvent.mouseDown(resourceCombobox)
|
||||
})
|
||||
await userEvent.type(resourceCombobox, 'room')
|
||||
|
||||
await act(async () => {
|
||||
jest.advanceTimersByTime(400);
|
||||
});
|
||||
jest.advanceTimersByTime(400)
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Room 1")).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('Room 1')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
await userEvent.click(screen.getByText("Room 1"));
|
||||
await userEvent.click(screen.getByText('Room 1'))
|
||||
|
||||
const spy = jest
|
||||
.spyOn(eventThunks, "putEventAsync")
|
||||
.mockImplementation((payload) => {
|
||||
const promise = Promise.resolve(payload);
|
||||
(promise as any).unwrap = () => promise;
|
||||
return () => promise as any;
|
||||
});
|
||||
.spyOn(eventThunks, 'putEventAsync')
|
||||
.mockImplementation(payload => {
|
||||
const promise = Promise.resolve(payload)
|
||||
;(promise as any).unwrap = () => promise
|
||||
return () => promise as any
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "actions.save" }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'actions.save' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
const receivedPayload = spy.mock.calls[0][0];
|
||||
const receivedPayload = spy.mock.calls[0][0]
|
||||
|
||||
expect(receivedPayload.newEvent.attendee).toHaveLength(2); // Organizer + 1 resource
|
||||
expect(receivedPayload.newEvent.attendee).toHaveLength(2) // Organizer + 1 resource
|
||||
expect(receivedPayload.newEvent.attendee[1]).toStrictEqual({
|
||||
cn: "Room 1",
|
||||
cal_address: "room1@example.com",
|
||||
partstat: "NEEDS-ACTION",
|
||||
rsvp: "TRUE",
|
||||
role: "REQ-PARTICIPANT",
|
||||
cutype: "RESOURCE",
|
||||
});
|
||||
cn: 'Room 1',
|
||||
cal_address: 'room1@example.com',
|
||||
partstat: 'NEEDS-ACTION',
|
||||
rsvp: 'TRUE',
|
||||
role: 'REQ-PARTICIPANT',
|
||||
cutype: 'RESOURCE'
|
||||
})
|
||||
} finally {
|
||||
jest.useRealTimers();
|
||||
jest.useRealTimers()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
it("dispatches putEventAsync and calls onClose when Save is clicked", async () => {
|
||||
renderPopover();
|
||||
it('dispatches putEventAsync and calls onClose when Save is clicked', async () => {
|
||||
renderPopover()
|
||||
const newEvent = {
|
||||
title: "Meeting",
|
||||
title: 'Meeting',
|
||||
allday: false,
|
||||
uid: "6045c603-11ab-43c5-bc30-0641420bb3a8",
|
||||
description: "Discuss project",
|
||||
location: "Zoom",
|
||||
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||
timezone: "Europe/Paris",
|
||||
transp: "TRANSPARENT",
|
||||
};
|
||||
uid: '6045c603-11ab-43c5-bc30-0641420bb3a8',
|
||||
description: 'Discuss project',
|
||||
location: 'Zoom',
|
||||
organizer: { cn: 'test', cal_address: 'test@test.com' },
|
||||
timezone: 'Europe/Paris',
|
||||
transp: 'TRANSPARENT'
|
||||
}
|
||||
|
||||
// Fill inputs
|
||||
fireEvent.change(screen.getByLabelText("event.form.title"), {
|
||||
target: { value: newEvent.title },
|
||||
});
|
||||
fireEvent.change(screen.getByLabelText('event.form.title'), {
|
||||
target: { value: newEvent.title }
|
||||
})
|
||||
// Click "Add description" button first
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "event.form.addDescription" })
|
||||
);
|
||||
fireEvent.change(screen.getByLabelText("event.form.description"), {
|
||||
target: { value: newEvent.description },
|
||||
});
|
||||
screen.getByRole('button', { name: 'event.form.addDescription' })
|
||||
)
|
||||
fireEvent.change(screen.getByLabelText('event.form.description'), {
|
||||
target: { value: newEvent.description }
|
||||
})
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "event.form.locationPlaceholder" })
|
||||
);
|
||||
fireEvent.change(screen.getByLabelText("event.form.location"), {
|
||||
target: { value: newEvent.location },
|
||||
});
|
||||
screen.getByRole('button', { name: 'event.form.locationPlaceholder' })
|
||||
)
|
||||
fireEvent.change(screen.getByLabelText('event.form.location'), {
|
||||
target: { value: newEvent.location }
|
||||
})
|
||||
const spy = jest
|
||||
.spyOn(eventThunks, "putEventAsync")
|
||||
.mockImplementation((payload) => {
|
||||
const promise = Promise.resolve(payload);
|
||||
(promise as any).unwrap = () => promise;
|
||||
return () => promise as any;
|
||||
});
|
||||
.spyOn(eventThunks, 'putEventAsync')
|
||||
.mockImplementation(payload => {
|
||||
const promise = Promise.resolve(payload)
|
||||
;(promise as any).unwrap = () => promise
|
||||
return () => promise as any
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "actions.save" }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'actions.save' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
expect(spy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
const receivedPayload = spy.mock.calls[0][0];
|
||||
const receivedPayload = spy.mock.calls[0][0]
|
||||
|
||||
expect(receivedPayload.cal).toEqual(
|
||||
preloadedState.calendars.list["667037022b752d0026472254/cal1"]
|
||||
);
|
||||
preloadedState.calendars.list['667037022b752d0026472254/cal1']
|
||||
)
|
||||
|
||||
expect(receivedPayload.newEvent.title).toBe(newEvent.title);
|
||||
expect(receivedPayload.newEvent.description).toBe(newEvent.description);
|
||||
expect(receivedPayload.newEvent.location).toBe(newEvent.location);
|
||||
expect(receivedPayload.newEvent.organizer).toEqual(newEvent.organizer);
|
||||
expect(receivedPayload.newEvent.title).toBe(newEvent.title)
|
||||
expect(receivedPayload.newEvent.description).toBe(newEvent.description)
|
||||
expect(receivedPayload.newEvent.location).toBe(newEvent.location)
|
||||
expect(receivedPayload.newEvent.organizer).toEqual(newEvent.organizer)
|
||||
expect(receivedPayload.newEvent.color).toEqual(
|
||||
preloadedState.calendars.list["667037022b752d0026472254/cal1"].color
|
||||
);
|
||||
preloadedState.calendars.list['667037022b752d0026472254/cal1'].color
|
||||
)
|
||||
|
||||
// onClose should be called
|
||||
expect(mockOnClose).toHaveBeenCalledWith(true);
|
||||
});
|
||||
expect(mockOnClose).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
it("calls onClose with refresh = false when Cancel clicked", () => {
|
||||
renderPopover();
|
||||
it('calls onClose with refresh = false when Cancel clicked', () => {
|
||||
renderPopover()
|
||||
|
||||
// Cancel button only appears in expanded mode
|
||||
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /Cancel/i }));
|
||||
fireEvent.click(screen.getByRole('button', { name: /Cancel/i }))
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalledWith(false);
|
||||
});
|
||||
expect(mockOnClose).toHaveBeenCalledWith(false)
|
||||
})
|
||||
|
||||
it("BUGFIX: Prefill Calendar field", async () => {
|
||||
renderPopover();
|
||||
it('BUGFIX: Prefill Calendar field', async () => {
|
||||
renderPopover()
|
||||
// In normal mode calendar is a SectionPreviewRow (button) with calendar name
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.getByRole("button", { name: "Calendar 1" })
|
||||
).toHaveTextContent("Calendar 1")
|
||||
);
|
||||
});
|
||||
screen.getByRole('button', { name: 'Calendar 1' })
|
||||
).toHaveTextContent('Calendar 1')
|
||||
)
|
||||
})
|
||||
|
||||
describe("EventModal - Drag and Drop Scenarios", () => {
|
||||
describe('EventModal - Drag and Drop Scenarios', () => {
|
||||
// Test 2.1: Drag from allday slot (single day)
|
||||
it("sets allday=true when drag from allday slot (single day)", async () => {
|
||||
it('sets allday=true when drag from allday slot (single day)', async () => {
|
||||
const selectedRange = {
|
||||
startStr: "2025-07-18",
|
||||
endStr: "2025-07-19",
|
||||
start: new Date("2025-07-18"),
|
||||
end: new Date("2025-07-19"),
|
||||
allDay: true,
|
||||
} as unknown as DateSelectArg;
|
||||
startStr: '2025-07-18',
|
||||
endStr: '2025-07-19',
|
||||
start: new Date('2025-07-18'),
|
||||
end: new Date('2025-07-19'),
|
||||
allDay: true
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
renderPopover(selectedRange);
|
||||
renderPopover(selectedRange)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
|
||||
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
|
||||
await waitFor(() => {
|
||||
expect(allDayCheckbox).toBeChecked();
|
||||
});
|
||||
});
|
||||
expect(allDayCheckbox).toBeChecked()
|
||||
})
|
||||
})
|
||||
|
||||
// Test 2.2: Drag from allday slot (multiple days)
|
||||
it("sets allday=true and shows 2 date fields when drag from allday slot (multiple days)", async () => {
|
||||
it('sets allday=true and shows 2 date fields when drag from allday slot (multiple days)', async () => {
|
||||
const selectedRange = {
|
||||
startStr: "2025-07-18",
|
||||
endStr: "2025-07-21",
|
||||
start: new Date("2025-07-18"),
|
||||
end: new Date("2025-07-21"),
|
||||
allDay: true,
|
||||
} as unknown as DateSelectArg;
|
||||
startStr: '2025-07-18',
|
||||
endStr: '2025-07-21',
|
||||
start: new Date('2025-07-18'),
|
||||
end: new Date('2025-07-21'),
|
||||
allDay: true
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
renderPopover(selectedRange);
|
||||
renderPopover(selectedRange)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
|
||||
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
|
||||
await waitFor(() => {
|
||||
expect(allDayCheckbox).toBeChecked();
|
||||
});
|
||||
expect(allDayCheckbox).toBeChecked()
|
||||
})
|
||||
|
||||
// Verify only date fields are shown
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("start-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-date-input")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId("start-time-input")
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId("end-time-input")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
expect(screen.getByTestId('start-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-date-input')).toBeInTheDocument()
|
||||
expect(screen.queryByTestId('start-time-input')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('end-time-input')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
// Test 2.3: Drag from week view (single day)
|
||||
it("keeps allday=false when drag from week view (single day)", async () => {
|
||||
it('keeps allday=false when drag from week view (single day)', async () => {
|
||||
const 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,
|
||||
} as unknown as DateSelectArg;
|
||||
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
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
renderPopover(selectedRange);
|
||||
renderPopover(selectedRange)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
|
||||
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
|
||||
await waitFor(() => {
|
||||
expect(allDayCheckbox).not.toBeChecked();
|
||||
});
|
||||
expect(allDayCheckbox).not.toBeChecked()
|
||||
})
|
||||
|
||||
// Verify time fields are shown
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("start-time-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-time-input")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
expect(screen.getByTestId('start-time-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-time-input')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
// Test 2.4: Drag from week view (multiple days) - CRITICAL TEST
|
||||
it("keeps allday=false and shows 4 fields when drag from week view (multiple days)", async () => {
|
||||
it('keeps allday=false and shows 4 fields when drag from week view (multiple days)', async () => {
|
||||
const selectedRange = {
|
||||
startStr: "2025-07-18T09:00",
|
||||
endStr: "2025-07-20T10:00",
|
||||
start: new Date("2025-07-18T09:00"),
|
||||
end: new Date("2025-07-20T10:00"),
|
||||
allDay: false,
|
||||
} as unknown as DateSelectArg;
|
||||
startStr: '2025-07-18T09:00',
|
||||
endStr: '2025-07-20T10:00',
|
||||
start: new Date('2025-07-18T09:00'),
|
||||
end: new Date('2025-07-20T10:00'),
|
||||
allDay: false
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
renderPopover(selectedRange);
|
||||
renderPopover(selectedRange)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
|
||||
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
|
||||
await waitFor(() => {
|
||||
expect(allDayCheckbox).not.toBeChecked(); // CRITICAL: should NOT be checked
|
||||
});
|
||||
expect(allDayCheckbox).not.toBeChecked() // CRITICAL: should NOT be checked
|
||||
})
|
||||
|
||||
// Verify all 4 fields are shown
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("start-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("start-time-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-time-input")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
expect(screen.getByTestId('start-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('start-time-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-time-input')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
// Test 2.5: Drag from week view (multiple days) - fallback path
|
||||
it("handles drag from week view (multiple days) with Date objects only", async () => {
|
||||
it('handles drag from week view (multiple days) with Date objects only', async () => {
|
||||
const selectedRange = {
|
||||
start: new Date("2025-07-18T09:00"),
|
||||
end: new Date("2025-07-20T10:00"),
|
||||
allDay: false,
|
||||
} as unknown as DateSelectArg;
|
||||
start: new Date('2025-07-18T09:00'),
|
||||
end: new Date('2025-07-20T10:00'),
|
||||
allDay: false
|
||||
} as unknown as DateSelectArg
|
||||
|
||||
renderPopover(selectedRange);
|
||||
renderPopover(selectedRange)
|
||||
fireEvent.click(
|
||||
screen.getByRole("button", { name: "common.moreOptions" })
|
||||
);
|
||||
screen.getByRole('button', { name: 'common.moreOptions' })
|
||||
)
|
||||
|
||||
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
|
||||
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
|
||||
await waitFor(() => {
|
||||
expect(allDayCheckbox).not.toBeChecked();
|
||||
});
|
||||
expect(allDayCheckbox).not.toBeChecked()
|
||||
})
|
||||
|
||||
// Verify all 4 fields are shown
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("start-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("start-time-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-date-input")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("end-time-input")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
expect(screen.getByTestId('start-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('start-time-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-date-input')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('end-time-input')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user