const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const test = require('node:test'); const MemoPages = require('../public/js/memo-pages.js'); test('备忘录页只从 URL 读取安全的真实家谱和备忘录编号', () => { assert.equal( MemoPages.getCurrentGenealogyId('?genealogyId=2060000000000000001&memoId=2060000000000000002'), '2060000000000000001' ); assert.equal( MemoPages.getCurrentMemoId('?genealogyId=2060000000000000001&memoId=2060000000000000002'), '2060000000000000002' ); assert.equal(MemoPages.getCurrentGenealogyId(''), ''); assert.equal(MemoPages.getCurrentMemoId('?memoId=unsafe'), ''); }); test('备忘录写入只构造 YAML MemoBody 并转换后端时间格式', () => { assert.deepEqual(MemoPages.buildMemoBody({ memoTitle: ' 祭祖提醒 ', memoContent: ' 准备供品 ', remindTime: '2026-07-24T09:30', completed: '1', mediaOssIds: '2060000000000000003,2060000000000000004', sortOrder: '3', status: '0', memoId: 'should-not-send', appUserId: 'should-not-send' }), { memoTitle: '祭祖提醒', memoContent: '准备供品', remindTime: '2026-07-24 09:30:00', completed: '1', mediaOssIds: '2060000000000000003,2060000000000000004', sortOrder: 3, status: '0' }); }); test('备忘录校验标题、时间、完成状态、附件、排序和可重读状态', () => { assert.equal(MemoPages.validateMemoBody({ memoTitle: '' }), '请填写备忘录标题'); assert.equal( MemoPages.validateMemoBody({ memoTitle: '提醒', remindTime: '2026-07-24T09:30:00+08:00' }), '提醒时间格式无效' ); assert.equal( MemoPages.validateMemoBody({ memoTitle: '提醒', remindTime: '2026-02-30 09:30:00' }), '提醒时间格式无效' ); assert.equal( MemoPages.validateMemoBody({ memoTitle: '提醒', completed: '2' }), '完成状态只能是未完成或已完成' ); assert.equal( MemoPages.validateMemoBody({ memoTitle: '提醒', mediaOssIds: '101, 102' }), '附件上传结果无效' ); assert.equal( MemoPages.validateMemoBody(MemoPages.buildMemoBody({ memoTitle: '提醒', sortOrder: '1.5' })), '排序值必须是安全整数' ); assert.equal( MemoPages.validateMemoBody({ memoTitle: '提醒', status: '1' }), '当前 PC 无法重新读取停用备忘录,暂不开放停用' ); assert.equal(MemoPages.validateMemoBody({ memoTitle: '提醒', completed: '0', status: '0' }), ''); assert.equal(MemoPages.validateMemoBody({ memoTitle: '提醒', completed: '1', status: '0' }), ''); }); test('备忘录响应使用 PC MemoVo 并拒绝不安全的数字长整型', () => { assert.deepEqual(MemoPages.normalizeMemo({ memoId: '2060000000000000001', genealogyId: '2060000000000000002', genealogyNo: 'G20260729001', genealogyName: '叶氏家谱', surname: '叶', appUserId: '2060000000000000003', appUserNickName: '叶子', appUserPhone: '19100000000', memoTitle: '祭祖提醒', memoContent: '准备供品', remindTime: '2026-07-24 09:30:00', completed: '1', mediaOssIds: '2060000000000000004', sortOrder: 1, status: '0', remark: '年度事项' }), { memoId: '2060000000000000001', genealogyId: '2060000000000000002', genealogyNo: 'G20260729001', genealogyName: '叶氏家谱', surname: '叶', appUserId: '2060000000000000003', appUserNickName: '叶子', appUserPhone: '19100000000', memoTitle: '祭祖提醒', memoContent: '准备供品', remindTime: '2026-07-24 09:30:00', completed: '1', mediaOssIds: '2060000000000000004', sortOrder: 1, status: '0', remark: '年度事项' }); assert.equal(MemoPages.normalizeMemo({ memoId: Number('2060000000000000001'), genealogyId: '2', memoTitle: '提醒', completed: '0', status: '0' }), null); }); test('备忘录渲染业务字段但不暴露手机号、OSS ID 或未转义内容', () => { const memo = MemoPages.normalizeMemo({ memoId: '1', genealogyId: '2', appUserId: '3', appUserNickName: '叶子', appUserPhone: '19100000000', memoTitle: '', memoContent: '准备供品', remindTime: '2026-07-24 09:30:00', completed: '1', mediaOssIds: '4,5', sortOrder: 1, status: '0', remark: '年度事项' }); const html = MemoPages.renderMemoDetail(memo); assert.doesNotMatch(html, /