#708 apply strictier linting rules (#717)

* #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:
lethemanh
2026-04-01 22:15:10 +07:00
committed by GitHub
parent 2bff6aae78
commit cadfa70e60
321 changed files with 27452 additions and 27600 deletions
+233 -233
View File
@@ -1,422 +1,422 @@
import { InfoRow } from "@/components/Event/InfoRow";
import { LONG_DATE_FORMAT } from "@/components/Event/utils/dateTimeFormatters";
import * as eventThunks from "@/features/Calendars/services";
import EventUpdateModal from "@/features/Events/EventUpdateModal";
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
import dayjs from "dayjs";
import { renderWithProviders } from "../../utils/Renderwithproviders";
import { InfoRow } from '@/components/Event/InfoRow'
import { LONG_DATE_FORMAT } from '@/components/Event/utils/dateTimeFormatters'
import * as eventThunks from '@/features/Calendars/services'
import EventUpdateModal from '@/features/Events/EventUpdateModal'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import dayjs from 'dayjs'
import { renderWithProviders } from '../../utils/Renderwithproviders'
describe("Event Full Display", () => {
const mockOnClose = jest.fn();
const day = new Date("2025-01-15T10:00:00.000Z"); // Fixed date in UTC: Jan 15, 2025 10:00 AM UTC
describe('Event Full Display', () => {
const mockOnClose = jest.fn()
const day = new Date('2025-01-15T10:00:00.000Z') // Fixed date in UTC: Jan 15, 2025 10:00 AM UTC
beforeEach(() => {
jest.clearAllMocks();
});
jest.clearAllMocks()
})
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: "First Calendar",
color: "#FF0000",
'667037022b752d0026472254/cal1': {
id: '667037022b752d0026472254/cal1',
name: 'First Calendar',
color: '#FF0000',
events: {
event1: {
uid: "event1",
title: "Test Event",
calId: "667037022b752d0026472254/cal1",
uid: 'event1',
title: 'Test Event',
calId: '667037022b752d0026472254/cal1',
start: day.toISOString(),
end: day.toISOString(),
organizer: { cn: "test", cal_address: "test@test.com" },
organizer: { cn: 'test', cal_address: 'test@test.com' },
attendee: [
{
cn: "test",
cal_address: "test@test.com",
partstat: "NEEDS-ACTION",
rsvp: "TRUE",
role: "REQ-PARTICIPANT",
cutype: "INDIVIDUAL",
cn: 'test',
cal_address: 'test@test.com',
partstat: 'NEEDS-ACTION',
rsvp: 'TRUE',
role: 'REQ-PARTICIPANT',
cutype: 'INDIVIDUAL'
},
{
cn: "John",
cal_address: "john@test.com",
partstat: "NEEDS-ACTION",
rsvp: "TRUE",
role: "REQ-PARTICIPANT",
cutype: "INDIVIDUAL",
},
],
},
},
cn: 'John',
cal_address: 'john@test.com',
partstat: 'NEEDS-ACTION',
rsvp: 'TRUE',
role: 'REQ-PARTICIPANT',
cutype: 'INDIVIDUAL'
}
]
}
}
},
"otherCal/cal": {
id: "otherCal/cal",
name: "Calendar 1",
color: "#FF0000",
'otherCal/cal': {
id: 'otherCal/cal',
name: 'Calendar 1',
color: '#FF0000',
events: {
event1: {
uid: "event1",
calId: "otherCal/cal",
title: "Test Event Other cal",
uid: 'event1',
calId: 'otherCal/cal',
title: 'Test Event Other cal',
start: day.toISOString(),
end: day.toISOString(),
organizer: { cn: "john", cal_address: "john@test.com" },
},
},
},
},
},
};
organizer: { cn: 'john', cal_address: 'john@test.com' }
}
}
}
}
}
}
it("renders correctly event data with fixed timezone", () => {
it('renders correctly event data with fixed timezone', () => {
// Use fixed timezone UTC for consistent test results across all environments
const fixedDate = new Date("2025-01-15T10:00:00.000Z"); // 10AM UTC
const endDate = new Date(fixedDate.getTime() + 3600000); // 11AM UTC
const fixedDate = new Date('2025-01-15T10:00:00.000Z') // 10AM UTC
const endDate = new Date(fixedDate.getTime() + 3600000) // 11AM UTC
// With UTC timezone set, formatLocalDateTime produces predictable values
const expectedStart = "2025-01-15T10:00"; // 10:00 AM UTC
const expectedEnd = "2025-01-15T11:00"; // 11:00 AM UTC
const expectedStart = '2025-01-15T10:00' // 10:00 AM UTC
const expectedEnd = '2025-01-15T11:00' // 11:00 AM UTC
const stateWithFixedDate = {
...preloadedState,
calendars: {
pending: false,
list: {
"667037022b752d0026472254/cal1": {
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
'667037022b752d0026472254/cal1': {
...preloadedState.calendars.list['667037022b752d0026472254/cal1'],
events: {
event1: {
...preloadedState.calendars.list[
"667037022b752d0026472254/cal1"
'667037022b752d0026472254/cal1'
].events.event1,
start: fixedDate.toISOString(),
end: endDate.toISOString(),
timezone: "UTC",
},
},
},
},
},
};
timezone: 'UTC'
}
}
}
}
}
}
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
stateWithFixedDate
);
)
expect(screen.getByDisplayValue("Test Event")).toBeInTheDocument();
expect(screen.getByDisplayValue('Test Event')).toBeInTheDocument()
// Expand to show date/time inputs (normal mode shows DateTimeSummary)
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
const startDateInput = screen.getByTestId("start-date-input");
const startTimeInput = screen.getByTestId("start-time-input");
const endTimeInput = screen.getByTestId("end-time-input");
const startDateInput = screen.getByTestId('start-date-input')
const startTimeInput = screen.getByTestId('start-time-input')
const endTimeInput = screen.getByTestId('end-time-input')
expect(startDateInput).toBeInTheDocument();
expect(startTimeInput).toBeInTheDocument();
expect(endTimeInput).toBeInTheDocument();
expect(startDateInput).toBeInTheDocument()
expect(startTimeInput).toBeInTheDocument()
expect(endTimeInput).toBeInTheDocument()
expect(startDateInput).toHaveValue(
dayjs(expectedStart).format(LONG_DATE_FORMAT)
);
expect(startTimeInput).toHaveValue(dayjs(expectedStart).format("HH:mm"));
)
expect(startTimeInput).toHaveValue(dayjs(expectedStart).format('HH:mm'))
expect(endTimeInput).toHaveValue(dayjs(expectedEnd).format("HH:mm"));
expect(endTimeInput).toHaveValue(dayjs(expectedEnd).format('HH:mm'))
expect(screen.getByText("First Calendar")).toBeInTheDocument();
});
it("calls onClose when Cancel clicked", () => {
expect(screen.getByText('First Calendar')).toBeInTheDocument()
})
it('calls onClose when Cancel clicked', () => {
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedState
);
fireEvent.click(screen.getAllByTestId("CloseIcon")[0]);
)
fireEvent.click(screen.getAllByTestId('CloseIcon')[0])
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
});
it("toggle Show More reveals extra fields", async () => {
expect(mockOnClose).toHaveBeenCalledWith({}, 'backdropClick')
})
it('toggle Show More reveals extra fields', async () => {
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedState
);
)
act(() => {
fireEvent.click(
screen.getByRole("button", { name: "common.moreOptions" })
);
});
screen.getByRole('button', { name: 'common.moreOptions' })
)
})
await waitFor(() => {
expect(screen.getByText("event.form.notification")).toBeInTheDocument();
});
expect(screen.getByText('event.form.notification')).toBeInTheDocument()
})
// EventDisplay modal doesn't have Repeat checkbox, only RepeatEvent component
// which shows repetition settings when repetition data exists
// Since test event has no repetition data, RepeatEvent component won't show Repeat checkbox
fireEvent.click(screen.getByRole("button", { name: /Show Less/i }));
});
fireEvent.click(screen.getByRole('button', { name: /Show Less/i }))
})
it("can edit title when user is organizer", () => {
it('can edit title when user is organizer', () => {
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedState
);
const titleField = screen.getByLabelText("event.form.title");
fireEvent.change(titleField, { target: { value: "New Title" } });
expect(screen.getByDisplayValue("New Title")).toBeInTheDocument();
});
it("toggle all-day updates end date correctly", () => {
)
const titleField = screen.getByLabelText('event.form.title')
fireEvent.change(titleField, { target: { value: 'New Title' } })
expect(screen.getByDisplayValue('New Title')).toBeInTheDocument()
})
it('toggle all-day updates end date correctly', () => {
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedState
);
)
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
const allDayCheckbox = screen.getByLabelText("event.form.allDay");
fireEvent.click(allDayCheckbox);
expect(allDayCheckbox).toBeChecked();
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
const allDayCheckbox = screen.getByLabelText('event.form.allDay')
fireEvent.click(allDayCheckbox)
expect(allDayCheckbox).toBeChecked()
const expectedDate = dayjs(day).format(LONG_DATE_FORMAT);
const expectedDate = dayjs(day).format(LONG_DATE_FORMAT)
const startDateInput = screen.getByTestId("start-date-input");
const endDateInput = screen.getByTestId("end-date-input");
const startDateInput = screen.getByTestId('start-date-input')
const endDateInput = screen.getByTestId('end-date-input')
expect(startDateInput).toHaveValue(expectedDate);
expect(endDateInput).toHaveValue(expectedDate);
});
expect(startDateInput).toHaveValue(expectedDate)
expect(endDateInput).toHaveValue(expectedDate)
})
it("saves event and moves it when calendar is changed", async () => {
it('saves event and moves it when calendar is changed', async () => {
const spyPut = 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
})
const spyMove = jest
.spyOn(eventThunks, "moveEventAsync")
.mockImplementation((payload) => {
const promise = Promise.resolve(payload);
(promise as any).unwrap = () => promise;
return () => promise as any;
});
.spyOn(eventThunks, 'moveEventAsync')
.mockImplementation(payload => {
const promise = Promise.resolve(payload)
;(promise as any).unwrap = () => promise
return () => promise as any
})
const testDate = new Date("2025-01-15T10:00:00.000Z");
const testEndDate = new Date("2025-01-15T11:00:00.000Z");
const testDate = new Date('2025-01-15T10:00:00.000Z')
const testEndDate = new Date('2025-01-15T11:00:00.000Z')
const preloadedTwoCals = {
...preloadedState,
calendars: {
pending: false,
list: {
"667037022b752d0026472254/cal1": {
id: "667037022b752d0026472254/cal1",
name: "Calendar One",
color: "#FF0000",
'667037022b752d0026472254/cal1': {
id: '667037022b752d0026472254/cal1',
name: 'Calendar One',
color: '#FF0000',
events: {
event1: {
uid: "event1",
title: "Test Event",
calId: "667037022b752d0026472254/cal1",
uid: 'event1',
title: 'Test Event',
calId: '667037022b752d0026472254/cal1',
start: testDate.toISOString(),
end: testEndDate.toISOString(),
organizer: { cn: "test", cal_address: "test@test.com" },
attendee: [{ cn: "test", cal_address: "test@test.com" }],
},
},
},
"667037022b752d0026472254/cal2": {
id: "667037022b752d0026472254/cal2",
name: "Calendar Two",
color: "#00FF00",
events: {},
organizer: { cn: 'test', cal_address: 'test@test.com' },
attendee: [{ cn: 'test', cal_address: 'test@test.com' }]
}
}
},
'667037022b752d0026472254/cal2': {
id: '667037022b752d0026472254/cal2',
name: 'Calendar Two',
color: '#00FF00',
events: {}
}
},
pending: false,
},
};
pending: false
}
}
await act(async () =>
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedTwoCals
)
);
)
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
const calendarSelect = screen.getByLabelText("event.form.calendar");
await act(async () => fireEvent.mouseDown(calendarSelect));
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
const calendarSelect = screen.getByLabelText('event.form.calendar')
await act(async () => fireEvent.mouseDown(calendarSelect))
const option = await screen.findByText("Calendar Two");
fireEvent.click(option);
const option = await screen.findByText('Calendar Two')
fireEvent.click(option)
await act(async () => {
fireEvent.click(screen.getByRole("button", { name: "actions.save" }));
});
fireEvent.click(screen.getByRole('button', { name: 'actions.save' }))
})
await waitFor(
() => {
expect(spyPut).toHaveBeenCalled();
expect(spyPut).toHaveBeenCalled()
},
{ timeout: 3000 }
);
)
await waitFor(
() => {
expect(spyMove).toHaveBeenCalled();
expect(spyMove).toHaveBeenCalled()
},
{ timeout: 3000 }
);
});
)
})
it("edit modal displays event time in original event timezone", () => {
it('edit modal displays event time in original event timezone', () => {
// GIVEN user timezone is UTC+2
// WHEN the user edits an event at 2PM UTC+7 (Asia/Bangkok)
// THEN the update modal displays the time as 2PM in Asia/Bangkok timezone
const eventDateUTC7 = new Date("2025-01-15T07:00:00.000Z"); // 7AM UTC = 2PM UTC+7
const eventDateUTC7 = new Date('2025-01-15T07:00:00.000Z') // 7AM UTC = 2PM UTC+7
const stateWithTimezone = {
...preloadedState,
calendars: {
pending: false,
list: {
"667037022b752d0026472254/cal1": {
id: "667037022b752d0026472254/cal1",
name: "Test Calendar",
color: "#FF0000",
'667037022b752d0026472254/cal1': {
id: '667037022b752d0026472254/cal1',
name: 'Test Calendar',
color: '#FF0000',
events: {
event1: {
uid: "event1",
title: "Timezone Edit Test",
calId: "667037022b752d0026472254/cal1",
uid: 'event1',
title: 'Timezone Edit Test',
calId: '667037022b752d0026472254/cal1',
start: eventDateUTC7.toISOString(),
end: new Date(eventDateUTC7.getTime() + 3600000).toISOString(),
timezone: "Asia/Bangkok",
timezone: 'Asia/Bangkok',
allday: false,
organizer: { cn: "test", cal_address: "test@test.com" },
attendee: [{ cn: "test", cal_address: "test@test.com" }],
},
},
},
organizer: { cn: 'test', cal_address: 'test@test.com' },
attendee: [{ cn: 'test', cal_address: 'test@test.com' }]
}
}
}
},
pending: false,
},
};
pending: false
}
}
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
stateWithTimezone
);
)
// Expand to show timezone selector (normal mode hides it)
fireEvent.click(screen.getByRole("button", { name: "common.moreOptions" }));
fireEvent.click(screen.getByRole('button', { name: 'common.moreOptions' }))
// The timezone select should have Asia/Bangkok selected
const timeZone = screen.getByDisplayValue(/Asia\/Bangkok/i);
expect(timeZone).toBeInTheDocument();
});
const timeZone = screen.getByDisplayValue(/Asia\/Bangkok/i)
expect(timeZone).toBeInTheDocument()
})
it("InfoRow renders error style when error prop is true", () => {
renderWithProviders(<InfoRow icon={<span>i</span>} text="Bad" error />);
expect(screen.getByText("Bad")).toBeInTheDocument();
});
it('InfoRow renders error style when error prop is true', () => {
renderWithProviders(<InfoRow icon={<span>i</span>} text="Bad" error />)
expect(screen.getByText('Bad')).toBeInTheDocument()
})
it("can remove an attendee with the close button", () => {
it('can remove an attendee with the close button', () => {
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
preloadedState
);
)
const removeBtn = screen.getAllByTestId("CloseIcon").pop()!;
fireEvent.click(removeBtn);
const removeBtn = screen.getAllByTestId('CloseIcon').pop()!
fireEvent.click(removeBtn)
expect(screen.queryByText(/John/)).not.toBeInTheDocument();
});
expect(screen.queryByText(/John/)).not.toBeInTheDocument()
})
it("renders video conference info when x_openpass_videoconference exists", () => {
it('renders video conference info when x_openpass_videoconference exists', () => {
const videoState = {
...preloadedState,
calendars: {
pending: false,
list: {
"667037022b752d0026472254/cal1": {
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
'667037022b752d0026472254/cal1': {
...preloadedState.calendars.list['667037022b752d0026472254/cal1'],
events: {
event1: {
...preloadedState.calendars.list[
"667037022b752d0026472254/cal1"
'667037022b752d0026472254/cal1'
].events.event1,
x_openpass_videoconference: "https://meet.test/video",
},
},
},
},
},
};
x_openpass_videoconference: 'https://meet.test/video'
}
}
}
}
}
}
renderWithProviders(
<EventUpdateModal
open={true}
onClose={mockOnClose}
calId={"667037022b752d0026472254/cal1"}
eventId={"event1"}
calId={'667037022b752d0026472254/cal1'}
eventId={'event1'}
/>,
videoState
);
)
expect(
screen.getByText("event.form.joinVisioConference")
).toBeInTheDocument();
});
});
screen.getByText('event.form.joinVisioConference')
).toBeInTheDocument()
})
})