Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
import { act, fireEvent, screen, waitFor } from "@testing-library/react";
|
||||||
|
import { renderWithProviders } from "../utils/Renderwithproviders";
|
||||||
|
import CalendarLayout from "../../src/components/Calendar/CalendarLayout";
|
||||||
|
|
||||||
|
describe("Event Error Handling", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
const start = new Date(today);
|
||||||
|
start.setHours(10, 0, 0, 0);
|
||||||
|
const end = new Date(today);
|
||||||
|
end.setHours(11, 0, 0, 0);
|
||||||
|
|
||||||
|
const erroredState = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
sid: "mockSid",
|
||||||
|
openpaasId: "user1",
|
||||||
|
},
|
||||||
|
tokens: { accessToken: "token" },
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"user1/cal1": {
|
||||||
|
name: "Calendar personal",
|
||||||
|
id: "user1/cal1",
|
||||||
|
color: { light: "#FF0000", dark: "#000" },
|
||||||
|
ownerEmails: ["alice@example.com"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
id: "event1",
|
||||||
|
calId: "user1/cal1",
|
||||||
|
uid: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
start: start.toISOString(),
|
||||||
|
end: start.toISOString(),
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
organizer: {
|
||||||
|
cn: "Alice",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
attendee: [
|
||||||
|
{
|
||||||
|
cn: "Alice",
|
||||||
|
partstat: "ACCEPTED",
|
||||||
|
rsvp: "TRUE",
|
||||||
|
role: "REQ-PARTICIPANT",
|
||||||
|
cutype: "INDIVIDUAL",
|
||||||
|
cal_address: "alice@example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it("BUGFIX: does not re-report errors after clearing error snackbar", async () => {
|
||||||
|
const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
|
||||||
|
|
||||||
|
await act(async () =>
|
||||||
|
renderWithProviders(<CalendarLayout />, erroredState)
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText("Test Event"));
|
||||||
|
expect(screen.getByRole("alert")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
const closeButton = screen.queryByRole("button", { name: "common.ok" });
|
||||||
|
|
||||||
|
if (closeButton) {
|
||||||
|
const initialWarnCount = consoleWarnSpy.mock.calls.length;
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(closeButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
const afterCloseWarnCount = consoleWarnSpy.mock.calls.length;
|
||||||
|
|
||||||
|
expect(afterCloseWarnCount).toBe(initialWarnCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
consoleWarnSpy.mockRestore();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export class EventErrorHandler {
|
export class EventErrorHandler {
|
||||||
private errors = new Map<string, string>();
|
private errors = new Map<string, string>();
|
||||||
|
private reportedEvents = new Set<string>();
|
||||||
private onErrorCallback?: (messages: string[]) => void;
|
private onErrorCallback?: (messages: string[]) => void;
|
||||||
|
|
||||||
setErrorCallback(callback: (messages: string[]) => void) {
|
setErrorCallback(callback: (messages: string[]) => void) {
|
||||||
@@ -7,7 +8,8 @@ export class EventErrorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reportError(eventId: string, message: string) {
|
reportError(eventId: string, message: string) {
|
||||||
if (!this.errors.has(eventId)) {
|
if (!this.reportedEvents.has(eventId)) {
|
||||||
|
this.reportedEvents.add(eventId);
|
||||||
this.errors.set(eventId, message);
|
this.errors.set(eventId, message);
|
||||||
console.warn(`[EventErrorHandler] ${eventId}: ${message}`);
|
console.warn(`[EventErrorHandler] ${eventId}: ${message}`);
|
||||||
this.emit();
|
this.emit();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
|
||||||
import { Card, Typography } from "@mui/material";
|
import { Card, Typography } from "@mui/material";
|
||||||
|
import { useRef, useEffect } from "react";
|
||||||
import { EventErrorHandler } from "../../Error/EventErrorHandler";
|
import { EventErrorHandler } from "../../Error/EventErrorHandler";
|
||||||
|
|
||||||
export function ErrorEventChip({
|
export function ErrorEventChip({
|
||||||
@@ -11,9 +11,21 @@ export function ErrorEventChip({
|
|||||||
errorHandler: EventErrorHandler;
|
errorHandler: EventErrorHandler;
|
||||||
error: any;
|
error: any;
|
||||||
}) {
|
}) {
|
||||||
const message =
|
const hasReported = useRef(false);
|
||||||
error instanceof Error ? error.message : "Unknown error during rendering";
|
|
||||||
errorHandler.reportError(event._def.extendedProps.uid || event.id, message);
|
useEffect(() => {
|
||||||
|
if (!hasReported.current) {
|
||||||
|
const message =
|
||||||
|
error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: `${error.class} error during rendering ${event._def.extendedProps.uid || event.id}`;
|
||||||
|
errorHandler.reportError(
|
||||||
|
event._def.extendedProps.uid || event.id,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
hasReported.current = true;
|
||||||
|
}
|
||||||
|
}, [event, errorHandler, error]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
|||||||
Reference in New Issue
Block a user