[#37] fixed bug found by @chibenwa
This commit is contained in:
@@ -4,6 +4,7 @@ import { jest } from "@jest/globals";
|
|||||||
import CalendarApp from "../../src/components/Calendar/Calendar";
|
import CalendarApp from "../../src/components/Calendar/Calendar";
|
||||||
import * as appHooks from "../../src/app/hooks";
|
import * as appHooks from "../../src/app/hooks";
|
||||||
import { ThunkDispatch } from "@reduxjs/toolkit";
|
import { ThunkDispatch } from "@reduxjs/toolkit";
|
||||||
|
import preview from "jest-preview";
|
||||||
|
|
||||||
describe("MiniCalendar", () => {
|
describe("MiniCalendar", () => {
|
||||||
const day = new Date();
|
const day = new Date();
|
||||||
@@ -54,6 +55,8 @@ describe("MiniCalendar", () => {
|
|||||||
|
|
||||||
it("renders mini calendar with the week in gray (except for today) when full calendar in week view", async () => {
|
it("renders mini calendar with the week in gray (except for today) when full calendar in week view", async () => {
|
||||||
renderCalendar();
|
renderCalendar();
|
||||||
|
preview.debug();
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const sunday = new Date(today);
|
const sunday = new Date(today);
|
||||||
sunday.setDate(today.getDate() - today.getDay());
|
sunday.setDate(today.getDate() - today.getDay());
|
||||||
@@ -61,9 +64,9 @@ describe("MiniCalendar", () => {
|
|||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
const date = new Date(sunday);
|
const date = new Date(sunday);
|
||||||
date.setDate(sunday.getDate() + i);
|
date.setDate(sunday.getDate() + i);
|
||||||
const tile = screen
|
const tile = (await screen.findAllByText(date.getDate())).find(
|
||||||
.getAllByText(date.getDate())
|
(el) => el.tagName.toLowerCase() === "abbr"
|
||||||
.find((el) => el.tagName.toLowerCase() === "abbr");
|
);
|
||||||
if (date.getTime() !== today.setHours(0, 0, 0, 0)) {
|
if (date.getTime() !== today.setHours(0, 0, 0, 0)) {
|
||||||
expect(tile?.parentElement).toHaveClass("selectedWeek");
|
expect(tile?.parentElement).toHaveClass("selectedWeek");
|
||||||
}
|
}
|
||||||
@@ -104,10 +107,95 @@ describe("MiniCalendar", () => {
|
|||||||
renderCalendar();
|
renderCalendar();
|
||||||
|
|
||||||
const dot = document.querySelector(".event-dot");
|
const dot = document.querySelector(".event-dot");
|
||||||
console.log(dot?.parentElement?.children[0].innerHTML);
|
|
||||||
expect(dot?.parentElement?.children[0].innerHTML).toBe(
|
expect(dot?.parentElement?.children[0].innerHTML).toBe(
|
||||||
day.getDate().toString()
|
day.getDate().toString()
|
||||||
);
|
);
|
||||||
expect(dot).toBeInTheDocument();
|
expect(dot).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Found Bugs", () => {
|
||||||
|
const day = new Date();
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
const dispatch = jest.fn() as ThunkDispatch<any, any, any>;
|
||||||
|
jest.spyOn(appHooks, "useAppDispatch").mockReturnValue(dispatch);
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderCalendar = () => {
|
||||||
|
const preloadedState = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
name: "Calendar 1",
|
||||||
|
color: "#FF0000",
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: day.toISOString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
renderWithProviders(<CalendarApp />, preloadedState);
|
||||||
|
};
|
||||||
|
|
||||||
|
it("gray day stays when day mode, click today, then change the month bar to august and come back to july", async () => {
|
||||||
|
renderCalendar();
|
||||||
|
const dayViewButton = await screen.findByTitle(/day view/i);
|
||||||
|
fireEvent.click(dayViewButton);
|
||||||
|
const nextMonthButton = screen.getByText(">");
|
||||||
|
const previousMonthButton = screen.getByText("<");
|
||||||
|
fireEvent.click(nextMonthButton);
|
||||||
|
fireEvent.click(previousMonthButton);
|
||||||
|
preview.debug();
|
||||||
|
const shownDay = screen.getByText((content, element) => {
|
||||||
|
return (
|
||||||
|
element?.className.toLowerCase().includes("fc-daygrid-day-number") ??
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const selectedTile = screen.getByText((content, element) => {
|
||||||
|
return element?.className.includes("selectedWeek") ?? false;
|
||||||
|
});
|
||||||
|
const supposedSelectedTile = screen
|
||||||
|
.getAllByText((content, element) => {
|
||||||
|
return element?.tagName.toLowerCase() === "abbr";
|
||||||
|
})
|
||||||
|
.find((el) => el.innerHTML === shownDay.innerHTML);
|
||||||
|
|
||||||
|
expect(selectedTile.children[0].innerHTML).toBe(
|
||||||
|
supposedSelectedTile?.innerHTML
|
||||||
|
);
|
||||||
|
expect(supposedSelectedTile?.parentElement).toHaveClass("selectedWeek");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("in month view going to next month, side panel is not updated on second click to following month both components are updated with the side panel view jumping 2 months", async () => {
|
||||||
|
renderCalendar();
|
||||||
|
|
||||||
|
const monthViewButton = await screen.findByTitle(/month view/i);
|
||||||
|
fireEvent.click(monthViewButton);
|
||||||
|
const nextMonthButton = await screen.findByTitle(/Next month/i);
|
||||||
|
const previousMonthButton = await screen.findByTitle(/Previous month/i);
|
||||||
|
fireEvent.click(nextMonthButton);
|
||||||
|
const miniCalMonth = await screen.findByTitle(/mini calendar month/i);
|
||||||
|
const fullCalMonth = screen.getByText((content, element) => {
|
||||||
|
return element?.className.includes("fc-toolbar-title") ?? false;
|
||||||
|
});
|
||||||
|
expect(miniCalMonth.innerHTML).toBe(fullCalMonth.innerHTML);
|
||||||
|
fireEvent.click(nextMonthButton);
|
||||||
|
expect(miniCalMonth.innerHTML).toBe(fullCalMonth.innerHTML);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -114,6 +114,9 @@ main {
|
|||||||
.selectedWeek {
|
.selectedWeek {
|
||||||
background-color: lightgrey;
|
background-color: lightgrey;
|
||||||
}
|
}
|
||||||
|
.react-calendar__month-view__days__day--neighboringMonth {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
/* sidebar header */
|
/* sidebar header */
|
||||||
.sidebar-calendar h2 {
|
.sidebar-calendar h2 {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { push } from "redux-first-history";
|
|||||||
export default function CalendarApp() {
|
export default function CalendarApp() {
|
||||||
const calendarRef = useRef<CalendarApi | null>(null);
|
const calendarRef = useRef<CalendarApi | null>(null);
|
||||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||||
|
const [selectedMiniDate, setSelectedMiniDate] = useState(new Date());
|
||||||
const tokens = useAppSelector((state) => state.user.tokens);
|
const tokens = useAppSelector((state) => state.user.tokens);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
@@ -56,7 +57,6 @@ export default function CalendarApp() {
|
|||||||
const [selectedCalendars, setSelectedCalendars] = useState<string[]>(
|
const [selectedCalendars, setSelectedCalendars] = useState<string[]>(
|
||||||
Object.keys(calendars).filter((id) => id.split("/")[0] === userId)
|
Object.keys(calendars).filter((id) => id.split("/")[0] === userId)
|
||||||
);
|
);
|
||||||
const fetchedIdsRef = useRef<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const calendarRange = getCalendarRange(selectedDate);
|
const calendarRange = getCalendarRange(selectedDate);
|
||||||
|
|
||||||
@@ -108,56 +108,45 @@ export default function CalendarApp() {
|
|||||||
setSelectedRange(null);
|
setSelectedRange(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMonthUp = () => {
|
||||||
|
setSelectedMiniDate(
|
||||||
|
new Date(selectedMiniDate.getFullYear(), selectedMiniDate.getMonth() - 1)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const handleMonthDown = () => {
|
||||||
|
setSelectedMiniDate(
|
||||||
|
new Date(selectedMiniDate.getFullYear(), selectedMiniDate.getMonth() + 1)
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<div className="calendar-label">
|
<div className="calendar-label">
|
||||||
<div className="calendar-label">
|
<div className="calendar-label">
|
||||||
<span>
|
<span title="mini calendar month">
|
||||||
{selectedDate.toLocaleDateString("us-us", {
|
{selectedMiniDate.toLocaleDateString("en-us", {
|
||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button onClick={handleMonthUp}><</button>
|
||||||
onClick={() =>
|
<button onClick={handleMonthDown}>></button>
|
||||||
setSelectedDate(
|
|
||||||
new Date(
|
|
||||||
selectedDate.getFullYear(),
|
|
||||||
selectedDate.getMonth() - 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() =>
|
|
||||||
setSelectedDate(
|
|
||||||
new Date(
|
|
||||||
selectedDate.getFullYear(),
|
|
||||||
selectedDate.getMonth() + 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<ReactCalendar
|
<ReactCalendar
|
||||||
key={selectedDate.toDateString()}
|
key={selectedMiniDate.toDateString()}
|
||||||
showNeighboringMonth={false}
|
|
||||||
calendarType="gregory"
|
calendarType="gregory"
|
||||||
formatShortWeekday={(locale, date) =>
|
formatShortWeekday={(locale, date) =>
|
||||||
date.toLocaleDateString(locale, { weekday: "narrow" })
|
date.toLocaleDateString(locale, { weekday: "narrow" })
|
||||||
}
|
}
|
||||||
value={selectedDate}
|
value={selectedMiniDate}
|
||||||
onClickDay={(date) => {
|
onClickDay={(date) => {
|
||||||
setSelectedDate(date);
|
setSelectedDate(date);
|
||||||
|
setSelectedMiniDate(date);
|
||||||
calendarRef.current?.gotoDate(date);
|
calendarRef.current?.gotoDate(date);
|
||||||
}}
|
}}
|
||||||
prevLabel={null}
|
prevLabel={null}
|
||||||
|
showNeighboringMonth={true}
|
||||||
nextLabel={null}
|
nextLabel={null}
|
||||||
showNavigation={false}
|
showNavigation={false}
|
||||||
tileClassName={({ date }) => {
|
tileClassName={({ date }) => {
|
||||||
@@ -169,7 +158,10 @@ export default function CalendarApp() {
|
|||||||
}
|
}
|
||||||
const selected = new Date(selectedDate);
|
const selected = new Date(selectedDate);
|
||||||
selected.setHours(0, 0, 0, 0);
|
selected.setHours(0, 0, 0, 0);
|
||||||
if (calendarRef.current?.view.type === "timeGridWeek") {
|
if (
|
||||||
|
calendarRef.current?.view.type === "timeGridWeek" ||
|
||||||
|
calendarRef.current?.view.type === undefined
|
||||||
|
) {
|
||||||
const startOfWeek = new Date(selected);
|
const startOfWeek = new Date(selected);
|
||||||
startOfWeek.setDate(selected.getDate() - selected.getDay()); // Sunday
|
startOfWeek.setDate(selected.getDate() - selected.getDay()); // Sunday
|
||||||
startOfWeek.setHours(0, 0, 0, 0);
|
startOfWeek.setHours(0, 0, 0, 0);
|
||||||
@@ -246,10 +238,24 @@ export default function CalendarApp() {
|
|||||||
hour12: false,
|
hour12: false,
|
||||||
}}
|
}}
|
||||||
datesSet={(arg) => {
|
datesSet={(arg) => {
|
||||||
const today = new Date();
|
if (arg.view.type === "timeGridDay") {
|
||||||
setSelectedDate(
|
setSelectedDate(new Date(arg.start));
|
||||||
today > arg.start && today < arg.end ? today : arg.start
|
setSelectedMiniDate(new Date(arg.start));
|
||||||
);
|
} else if (arg.view.type === "timeGridWeek") {
|
||||||
|
// In week view, retain selectedDate if it's in current range, otherwise set to start
|
||||||
|
if (selectedDate < arg.start || selectedDate > arg.end) {
|
||||||
|
setSelectedDate(new Date(arg.start));
|
||||||
|
setSelectedMiniDate(new Date(arg.start));
|
||||||
|
}
|
||||||
|
} else if (arg.view.type === "dayGridMonth") {
|
||||||
|
setSelectedDate(new Date(arg.start));
|
||||||
|
const midTimestamp =
|
||||||
|
(arg.start.getTime() + arg.end.getTime()) / 2;
|
||||||
|
setSelectedMiniDate(new Date(midTimestamp));
|
||||||
|
} else {
|
||||||
|
setSelectedDate(new Date(arg.start));
|
||||||
|
setSelectedMiniDate(new Date(arg.start));
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
dayHeaderContent={(arg) => {
|
dayHeaderContent={(arg) => {
|
||||||
const date = arg.date.getDate();
|
const date = arg.date.getDate();
|
||||||
|
|||||||
Reference in New Issue
Block a user