import { test } from 'node:test' import assert from 'node:assert/strict' import { formatNotificationTime, formatUnreadBadge, groupNotificationsByDay, hasNewNotification, readLastNotifiedId, writeLastNotifiedId, } from '../src/layout/notification-bell-model.ts' function createStorage() { const store = new Map() return { getItem: (key: string) => (store.has(key) ? (store.get(key) as string) : null), setItem: (key: string, value: string) => { store.set(key, String(value)) }, removeItem: (key: string) => { store.delete(key) }, } } function setupWindow() { const localStorage = createStorage() const globalScope = globalThis as Record const previous = globalScope.window globalScope.window = { localStorage } return { localStorage, restore: () => { globalScope.window = previous }, } } test('test_未读徽标:0 与非法值不显示、超过 99 显示 99+', () => { assert.equal(formatUnreadBadge(0), '') assert.equal(formatUnreadBadge(-3), '') assert.equal(formatUnreadBadge(null), '') assert.equal(formatUnreadBadge(undefined), '') assert.equal(formatUnreadBadge(Number.NaN), '') assert.equal(formatUnreadBadge(1), '1') assert.equal(formatUnreadBadge(99), '99') assert.equal(formatUnreadBadge(100), '99+') }) test('test_新通知判定:latestId 需大于已提醒 id', () => { assert.equal(hasNewNotification(0, 0), false) assert.equal(hasNewNotification(null, 5), false) assert.equal(hasNewNotification(5, 5), false) assert.equal(hasNewNotification(4, 5), false) assert.equal(hasNewNotification(6, 5), true) assert.equal(hasNewNotification(6, 0), true) assert.equal(hasNewNotification(6, null), true) }) test('test_已提醒 id 按管理员读写并容错', () => { setupWindow() assert.equal(readLastNotifiedId(7), 0, '未写入时按 0 处理') writeLastNotifiedId(7, 88) assert.equal(readLastNotifiedId(7), 88) assert.equal(readLastNotifiedId(8), 0, '不同管理员互不影响') writeLastNotifiedId(7, 0) assert.equal(readLastNotifiedId(7), 88, '非法 id 不覆盖已有值') window.localStorage.setItem('admin-notification:last-notified-id:7', 'broken') assert.equal(readLastNotifiedId(7), 0, '损坏值按 0 处理') assert.equal(readLastNotifiedId(null), readLastNotifiedId('0'), '空 uid 归一为 0 号键') }) test('test_时间展示:今天/昨天/更早', () => { const now = new Date(2026, 8, 13, 15, 30) assert.equal(formatNotificationTime(new Date(2026, 8, 13, 9, 5).toISOString(), now), '09:05') assert.equal(formatNotificationTime(new Date(2026, 8, 12, 23, 59).toISOString(), now), '昨天 23:59') assert.equal(formatNotificationTime(new Date(2026, 8, 1, 8, 0).toISOString(), now), '09-01 08:00') assert.equal(formatNotificationTime(null, now), '') assert.equal(formatNotificationTime('not-a-date', now), '') }) test('test_按年月日分组:今天/昨天/更早,组内保持原顺序', () => { const now = new Date(2026, 8, 13, 15, 30) const items = [ { id: 4, createdAt: new Date(2026, 8, 13, 15, 0).toISOString() }, { id: 3, createdAt: new Date(2026, 8, 13, 9, 0).toISOString() }, { id: 2, createdAt: new Date(2026, 8, 12, 23, 0).toISOString() }, { id: 1, createdAt: new Date(2026, 8, 1, 8, 0).toISOString() }, ] const groups = groupNotificationsByDay(items, now) assert.equal(groups.length, 3) assert.deepEqual( groups.map((group) => [group.day, group.label]), [ ['2026-09-13', '今天'], ['2026-09-12', '昨天'], ['2026-09-01', '2026年9月1日'], ], ) assert.deepEqual( groups[0].items.map((item) => item.id), [4, 3], '同一天的多条合为一组且保持倒序', ) }) test('test_按年月日分组:时间缺失/非法归入未知时间组', () => { const now = new Date(2026, 8, 13, 15, 30) const groups = groupNotificationsByDay( [ { id: 2, createdAt: null }, { id: 1, createdAt: 'not-a-date' }, ], now, ) assert.equal(groups.length, 1) assert.equal(groups[0].day, '') assert.equal(groups[0].label, '未知时间') assert.deepEqual( groups[0].items.map((item) => item.id), [2, 1], ) })