const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const test = require('node:test'); const CeremonyPages = require('../public/js/ceremony-pages.js'); test('我的邀请响应保留完整展示字段并保持业务 ID 为字符串', () => { assert.deepEqual(CeremonyPages.normalizeInvitation({ invitationId: '2060000000000000001', genealogyId: '2060000000000000002', ceremonyId: '2060000000000000003', inviteeUserId: '2060000000000000004', inviteStatus: 'PENDING', inviteVersion: 2, deliveredTime: '2026-07-29T09:00:00+08:00', readTime: null, responseTime: null, ceremonyTitle: '家族答谢宴', ceremonyTime: '2026-08-08T18:00:00+08:00', location: '锦江厅', locationAddress: '成都市锦江区示例路 8 号', longitude: 104.0668, latitude: 30.5728 }), { invitationId: '2060000000000000001', genealogyId: '2060000000000000002', ceremonyId: '2060000000000000003', inviteeUserId: '2060000000000000004', inviteStatus: 'PENDING', inviteVersion: 2, deliveredTime: '2026-07-29T09:00:00+08:00', readTime: '', responseTime: '', ceremonyTitle: '家族答谢宴', ceremonyTime: '2026-08-08T18:00:00+08:00', location: '锦江厅', locationAddress: '成都市锦江区示例路 8 号', longitude: 104.0668, latitude: 30.5728 }); }); test('邀请响应拒绝缺少稳定 ID、非法状态和不安全数字长 ID', () => { assert.equal(CeremonyPages.normalizeInvitation({ invitationId: '1', genealogyId: '2', inviteeUserId: '4', inviteStatus: 'PENDING' }), null); assert.equal(CeremonyPages.normalizeInvitation({ invitationId: '1', genealogyId: '2', ceremonyId: '3', inviteeUserId: '4', inviteStatus: 'UNKNOWN' }), null); assert.equal(CeremonyPages.normalizeInvitation({ invitationId: Number('2060000000000000001'), genealogyId: '2', ceremonyId: '3', inviteeUserId: '4', inviteStatus: 'PENDING' }), null); }); test('YAML 未声明必返的 inviteeUserId 缺失时仍可用活动上下文响应', () => { const invitation = CeremonyPages.normalizeInvitation({ invitationId: '1', genealogyId: '2', ceremonyId: '3', inviteStatus: 'PENDING' }); assert.notEqual(invitation, null); assert.equal(invitation.inviteeUserId, undefined); assert.equal(CeremonyPages.canRespondToInvitation(invitation), true); }); test('响应邀请只允许提交 YAML 定义的 inviteStatus 字段', () => { assert.deepEqual(CeremonyPages.buildInvitationResponseBody({ inviteStatus: 'ACCEPTED', invitationId: '2060000000000000001', inviteVersion: 2 }), { inviteStatus: 'ACCEPTED' }); assert.deepEqual(CeremonyPages.buildInvitationResponseBody({ inviteStatus: 'DECLINED' }), { inviteStatus: 'DECLINED' }); assert.equal(CeremonyPages.validateInvitationResponseBody({ inviteStatus: 'PENDING' }), '邀请只能选择接受或拒绝'); }); test('只有待响应邀请显示接受和拒绝动作', () => { assert.equal(CeremonyPages.canRespondToInvitation({ inviteStatus: 'PENDING' }), true); assert.equal(CeremonyPages.canRespondToInvitation({ inviteStatus: 'ACCEPTED' }), false); assert.equal(CeremonyPages.canRespondToInvitation({ inviteStatus: 'DECLINED' }), false); assert.equal(CeremonyPages.canRespondToInvitation({ inviteStatus: 'CANCELED' }), false); }); test('邀请列表渲染转义内容、展示详情但不直接暴露内部 ID 和坐标', () => { const invitation = CeremonyPages.normalizeInvitation({ invitationId: '2060000000000000001', genealogyId: '2060000000000000002', ceremonyId: '2060000000000000003', inviteeUserId: '2060000000000000004', inviteStatus: 'PENDING', inviteVersion: 1, ceremonyTitle: '', ceremonyTime: '2026-08-08T18:00:00+08:00', location: '锦江厅', locationAddress: '成都市锦江区示例路 8 号', longitude: 104.0668, latitude: 30.5728 }); const row = CeremonyPages.renderInvitationRow(invitation); const detail = CeremonyPages.renderInvitationDetail(invitation); assert.doesNotMatch(row, /