const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const test = require('node:test'); const NotificationPages = require('../public/js/notification-pages.js'); function notificationFixture(overrides) { return Object.assign({ notificationId: '2060000000000000001', genealogyId: '2060000000000000002', genealogyNo: 'G20260729001', genealogyName: '叶氏家谱', senderUserId: '2060000000000000003', senderNickName: '叶子', senderPhone: '19100000000', noticeType: 'family_feed_comment', noticeTitle: '新的评论', noticeContent: '有人评论了家族动态', bizType: 'family_feed_comment', bizId: '2060000000000000004', bizSummary: '家族圈评论', publishTime: '2026-07-29 10:30:00', readStatus: '0', readTime: null, status: '0', remark: '' }, overrides || {}); } test('通知筛选只允许全部、未读和已读三种查询', () => { assert.deepEqual(NotificationPages.buildNotificationQuery(''), {}); assert.deepEqual(NotificationPages.buildNotificationQuery('0'), { readStatus: '0' }); assert.deepEqual(NotificationPages.buildNotificationQuery('1'), { readStatus: '1' }); assert.deepEqual(NotificationPages.buildNotificationQuery('unsafe'), {}); }); test('通知列表只接受 PC 的非分页数组并规范完整 NotificationView', () => { const record = notificationFixture(); assert.deepEqual(NotificationPages.normalizeNotifications([record]), [ NotificationPages.normalizeNotification(record) ]); assert.deepEqual(NotificationPages.normalizeNotifications({ rows: [record] }), []); assert.equal(NotificationPages.normalizeNotification({ ...record, notificationId: Number('2060000000000000001') }), null); assert.equal(NotificationPages.normalizeNotification({ ...record, readStatus: '2' }), null); }); test('通知可选业务 ID 接受 null 但拒绝不安全数字', () => { assert.ok(NotificationPages.normalizeNotification(notificationFixture({ genealogyId: null, senderUserId: null, bizId: null }))); assert.equal(NotificationPages.normalizeNotification(notificationFixture({ bizId: Number('2060000000000000004') })), null); }); test('未读数只接受非负安全整数', () => { assert.equal(NotificationPages.getUnreadCount(3), 3); assert.equal(NotificationPages.getUnreadCount('3'), 3); assert.equal(NotificationPages.getUnreadCount(-1), 0); assert.equal(NotificationPages.getUnreadCount(1.5), 0); assert.equal(NotificationPages.getUnreadCount(Number.MAX_SAFE_INTEGER + 1), 0); }); test('通知列表和详情转义正文且不暴露手机号或内部 ID', () => { const record = NotificationPages.normalizeNotification(notificationFixture({ noticeTitle: '', noticeContent: '通知正文' })); const rowHtml = NotificationPages.renderNotificationRow(record); const detailHtml = NotificationPages.renderNotificationDetail(record); assert.doesNotMatch(rowHtml + detailHtml, /