172 lines
7.0 KiB
TypeScript
172 lines
7.0 KiB
TypeScript
/**
|
|
* NotificationStore Tests
|
|
*
|
|
* Tests for Zustand-based global notification system.
|
|
* Covers onClick callback, duration defaults, and state management.
|
|
*
|
|
* Note: Zustand state updates require re-calling getState() to get fresh state.
|
|
*/
|
|
|
|
import { describe, it, beforeEach, afterEach, mock } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { useNotificationStore } from "../../src/store/notificationStore.ts";
|
|
|
|
describe("NotificationStore", () => {
|
|
beforeEach(() => {
|
|
// Clear all notifications before each test
|
|
useNotificationStore.getState().clearAll();
|
|
});
|
|
|
|
afterEach(() => {
|
|
useNotificationStore.getState().clearAll();
|
|
});
|
|
|
|
describe("addNotification", () => {
|
|
it("should add notification with default duration 5000ms", () => {
|
|
const id = useNotificationStore.getState().addNotification({ type: "info", message: "test" });
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.ok(notification, "notification should exist");
|
|
assert.equal(notification?.duration, 5000, "default duration should be 5000ms");
|
|
});
|
|
|
|
it("should add notification with onClick callback", () => {
|
|
const onClick = mock.fn();
|
|
const id = useNotificationStore.getState().addNotification({
|
|
type: "warning",
|
|
message: "clickable notification",
|
|
onClick,
|
|
});
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.ok(notification, "notification should exist");
|
|
assert.equal(notification?.onClick, onClick, "onClick should be stored");
|
|
});
|
|
|
|
it("should include onClick in notification object", () => {
|
|
const onClick = () => {};
|
|
const id = useNotificationStore.getState().addNotification({
|
|
type: "success",
|
|
message: "test",
|
|
onClick,
|
|
});
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.ok(notification?.onClick, "onClick should be present on notification");
|
|
});
|
|
|
|
it("should allow custom duration override", () => {
|
|
const id = useNotificationStore.getState().addNotification({
|
|
type: "error",
|
|
message: "test",
|
|
duration: 10000,
|
|
});
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.equal(notification?.duration, 10000, "custom duration should be applied");
|
|
});
|
|
});
|
|
|
|
describe("convenience methods", () => {
|
|
it("warning should use 10000ms duration", () => {
|
|
const id = useNotificationStore.getState().warning("warning message", "Warning Title");
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.ok(notification, "notification should exist");
|
|
assert.equal(notification?.type, "warning", "type should be warning");
|
|
assert.equal(notification?.duration, 10000, "warning duration should be 10000ms");
|
|
assert.equal(notification?.title, "Warning Title", "title should be set");
|
|
});
|
|
|
|
it("error should use 8000ms duration", () => {
|
|
const id = useNotificationStore.getState().error("error message");
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.equal(notification?.duration, 8000, "error duration should be 8000ms");
|
|
});
|
|
|
|
it("success should use default 5000ms duration", () => {
|
|
const id = useNotificationStore.getState().success("success message");
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.equal(notification?.duration, 5000, "success duration should be 5000ms");
|
|
});
|
|
|
|
it("info should use default 5000ms duration", () => {
|
|
const id = useNotificationStore.getState().info("info message");
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.equal(notification?.duration, 5000, "info duration should be 5000ms");
|
|
});
|
|
});
|
|
|
|
describe("removeNotification", () => {
|
|
it("should remove notification by id", () => {
|
|
const id = useNotificationStore
|
|
.getState()
|
|
.addNotification({ type: "info", message: "to remove" });
|
|
assert.equal(
|
|
useNotificationStore.getState().notifications.length,
|
|
1,
|
|
"should have 1 notification"
|
|
);
|
|
useNotificationStore.getState().removeNotification(id);
|
|
assert.equal(
|
|
useNotificationStore.getState().notifications.length,
|
|
0,
|
|
"should have 0 notifications after removal"
|
|
);
|
|
});
|
|
|
|
it("should not error when removing non-existent id", () => {
|
|
useNotificationStore.getState().removeNotification(999);
|
|
assert.equal(
|
|
useNotificationStore.getState().notifications.length,
|
|
0,
|
|
"should still have 0 notifications"
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("clearAll", () => {
|
|
it("should clear all notifications", () => {
|
|
useNotificationStore.getState().addNotification({ type: "info", message: "one" });
|
|
useNotificationStore.getState().addNotification({ type: "info", message: "two" });
|
|
useNotificationStore.getState().addNotification({ type: "info", message: "three" });
|
|
assert.equal(
|
|
useNotificationStore.getState().notifications.length,
|
|
3,
|
|
"should have 3 notifications"
|
|
);
|
|
useNotificationStore.getState().clearAll();
|
|
assert.equal(
|
|
useNotificationStore.getState().notifications.length,
|
|
0,
|
|
"should have 0 after clearAll"
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("notification structure", () => {
|
|
it("should include all required fields", () => {
|
|
const onClick = () => {};
|
|
const id = useNotificationStore.getState().addNotification({
|
|
type: "warning",
|
|
message: "structured test",
|
|
title: "Title",
|
|
duration: 15000,
|
|
dismissible: false,
|
|
onClick,
|
|
});
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.ok(notification, "notification should exist");
|
|
assert.equal(typeof notification?.id, "number", "id should be number");
|
|
assert.equal(notification?.type, "warning", "type should match");
|
|
assert.equal(notification?.message, "structured test", "message should match");
|
|
assert.equal(notification?.title, "Title", "title should match");
|
|
assert.equal(notification?.duration, 15000, "duration should match");
|
|
assert.equal(notification?.dismissible, false, "dismissible should match");
|
|
assert.equal(typeof notification?.createdAt, "number", "createdAt should be number");
|
|
assert.equal(notification?.onClick, onClick, "onClick should match");
|
|
});
|
|
|
|
it("should have dismissible true by default", () => {
|
|
const id = useNotificationStore.getState().addNotification({ type: "info", message: "test" });
|
|
const notification = useNotificationStore.getState().notifications.find((n) => n.id === id);
|
|
assert.equal(notification?.dismissible, true, "dismissible should default to true");
|
|
});
|
|
});
|
|
});
|