import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import { toast } from "react-toastify";
import NotificationProvider, { notify } from "../../context/NotificationProvider";
import { SSEContext } from "../../context/SSEContext";
import { AuthContext } from "../../context/AuthContext";
// Mock axios to prevent import errors
jest.mock("axios");
// Mock react-toastify
jest.mock("react-toastify", () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
info: jest.fn(),
warning: jest.fn(),
dismiss: jest.fn(),
},
}));
describe("NotificationProvider", () => {
let mockSSEContext;
let mockAuthContext;
beforeEach(() => {
jest.clearAllMocks();
mockSSEContext = {
connected: true,
notifications: [],
on: jest.fn(),
off: jest.fn(),
subscribe: jest.fn().mockResolvedValue({ subscribed: [] }),
unsubscribe: jest.fn().mockResolvedValue({ unsubscribed: [] }),
clearNotification: jest.fn(),
clearAllNotifications: jest.fn(),
};
mockAuthContext = {
auth: {
isAuthenticated: true,
user: { id: "user123", name: "Test User" },
},
};
});
const renderWithProviders = (children) => {
return render(
{children}
);
};
test("renders children correctly", () => {
renderWithProviders(
Test Content
);
expect(screen.getByText("Test Content")).toBeInTheDocument();
});
test("subscribes to custom events via context", () => {
renderWithProviders(Test
);
// Verify custom event listeners were registered via context
expect(mockSSEContext.on).toHaveBeenCalledWith("eventUpdate", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("taskUpdate", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("streetUpdate", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("achievementUnlocked", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("newPost", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("newComment", expect.any(Function));
expect(mockSSEContext.on).toHaveBeenCalledWith("notification", expect.any(Function));
});
test("cleans up event listeners on unmount", () => {
const { unmount } = renderWithProviders(Test
);
unmount();
// Verify custom event listeners were removed via context
expect(mockSSEContext.off).toHaveBeenCalledWith("eventUpdate", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("taskUpdate", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("streetUpdate", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("achievementUnlocked", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("newPost", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("newComment", expect.any(Function));
expect(mockSSEContext.off).toHaveBeenCalledWith("notification", expect.any(Function));
});
test("does not subscribe when not connected", () => {
mockSSEContext.connected = false;
renderWithProviders(Test
);
// Event listeners should not be registered when not connected
expect(mockSSEContext.on).not.toHaveBeenCalled();
});
});
describe("notify utility", () => {
beforeEach(() => {
jest.clearAllMocks();
});
test("notify.success calls toast.success", () => {
notify.success("Test message");
expect(toast.success).toHaveBeenCalledWith("Test message", {});
});
test("notify.error calls toast.error", () => {
notify.error("Error message");
expect(toast.error).toHaveBeenCalledWith("Error message", {});
});
test("notify.info calls toast.info", () => {
notify.info("Info message");
expect(toast.info).toHaveBeenCalledWith("Info message", {});
});
test("notify.warning calls toast.warning", () => {
notify.warning("Warning message");
expect(toast.warning).toHaveBeenCalledWith("Warning message", {});
});
test("notify.success accepts custom options", () => {
const options = { autoClose: 3000, position: "bottom-right" };
notify.success("Test", options);
expect(toast.success).toHaveBeenCalledWith("Test", options);
});
test("notify.dismiss calls toast.dismiss with toastId", () => {
notify.dismiss("test-toast-id");
expect(toast.dismiss).toHaveBeenCalledWith("test-toast-id");
});
test("notify.dismissAll calls toast.dismiss without arguments", () => {
notify.dismissAll();
expect(toast.dismiss).toHaveBeenCalledWith();
});
});