218 lines
7.9 KiB
JavaScript
218 lines
7.9 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const test = require('node:test');
|
|
|
|
const FamilyHomePages = require('../public/js/family-home-pages.js');
|
|
|
|
const genealogyId = '2062179707935264769';
|
|
const root = path.resolve(__dirname, '..');
|
|
|
|
function overviewFixture(overrides) {
|
|
return Object.assign({
|
|
genealogyId,
|
|
genealogyNo: 'G20260729001',
|
|
genealogyName: '叶氏家谱',
|
|
surname: '叶',
|
|
ancestralHall: '南阳堂',
|
|
originPlace: '四川成都',
|
|
regionCode: '510100',
|
|
regionName: '成都市',
|
|
regionFullName: '四川省 成都市',
|
|
addressDetail: '高新区',
|
|
coverOssId: '2062179707935264700',
|
|
intro: '叶氏源流',
|
|
ownerUserId: '2062179707935264701',
|
|
visibility: '1',
|
|
joinMode: '1',
|
|
memberCount: 12,
|
|
personCount: 36,
|
|
status: '0',
|
|
roleType: 'owner',
|
|
canManage: true,
|
|
canEditContent: true,
|
|
memberStatus: '0',
|
|
joinTime: '2026-07-29 12:00:00'
|
|
}, overrides);
|
|
}
|
|
|
|
test('家谱主页只保留 AppGenealogyVo 的安全展示字段并匹配当前上下文', () => {
|
|
assert.deepEqual(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture(),
|
|
genealogyId
|
|
), {
|
|
genealogyId,
|
|
genealogyNo: 'G20260729001',
|
|
genealogyName: '叶氏家谱',
|
|
surname: '叶',
|
|
ancestralHall: '南阳堂',
|
|
originPlace: '四川成都',
|
|
regionFullName: '四川省 成都市',
|
|
memberCount: 12,
|
|
personCount: 36,
|
|
canManage: true,
|
|
canEditContent: true
|
|
});
|
|
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ genealogyId: '2062179707935264770' }),
|
|
genealogyId
|
|
), null);
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ genealogyId: Number.MAX_SAFE_INTEGER + 1 }),
|
|
genealogyId
|
|
), null);
|
|
});
|
|
|
|
test('家谱主页拒绝停用、空名称和非法计数响应', () => {
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ status: '1' }),
|
|
genealogyId
|
|
), null);
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ genealogyName: '' }),
|
|
genealogyId
|
|
), null);
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ memberCount: -1 }),
|
|
genealogyId
|
|
), null);
|
|
assert.equal(FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({ personCount: Number.MAX_SAFE_INTEGER + 1 }),
|
|
genealogyId
|
|
), null);
|
|
});
|
|
|
|
test('家谱概览渲染转义文本并隐藏内部用户与文件编号', () => {
|
|
const overview = FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture({
|
|
genealogyName: '<叶氏家谱>',
|
|
ancestralHall: '<南阳堂>'
|
|
}),
|
|
genealogyId
|
|
);
|
|
const html = FamilyHomePages.renderFamilyOverview(overview);
|
|
|
|
assert.match(html, /<叶氏家谱>/);
|
|
assert.match(html, /<南阳堂>/);
|
|
assert.match(html, /成员 12 人/);
|
|
assert.match(html, /世系人物 36 人/);
|
|
assert.doesNotMatch(html, /ownerUserId|coverOssId|206217970793526470[01]/);
|
|
});
|
|
|
|
test('家谱管理入口只接受后端布尔能力字段', () => {
|
|
assert.equal(FamilyHomePages.shouldShowFamilyManagement(
|
|
FamilyHomePages.normalizeFamilyOverview(overviewFixture({ canManage: true }), genealogyId)
|
|
), true);
|
|
assert.equal(FamilyHomePages.shouldShowFamilyManagement(
|
|
FamilyHomePages.normalizeFamilyOverview(overviewFixture({ canManage: 'true' }), genealogyId)
|
|
), false);
|
|
});
|
|
|
|
test('家谱主页只把缺失登录态和 401 视为登录失效', () => {
|
|
assert.equal(FamilyHomePages.shouldRedirectToLogin({
|
|
getToken() { return 'token'; }
|
|
}, { status: 403 }), false);
|
|
assert.equal(FamilyHomePages.shouldRedirectToLogin({
|
|
getToken() { return 'token'; }
|
|
}, { status: 401 }), true);
|
|
assert.equal(FamilyHomePages.shouldRedirectToLogin({
|
|
getToken() { return ''; }
|
|
}), true);
|
|
assert.equal(FamilyHomePages.isForbidden({ status: 403 }), true);
|
|
assert.equal(FamilyHomePages.isForbidden({ status: 401 }), false);
|
|
});
|
|
|
|
test('家谱主页只读取当前家谱概览和世系树', async () => {
|
|
const calls = [];
|
|
const tree = [{
|
|
personId: '2062179707935264770',
|
|
genealogyId,
|
|
name: '始祖',
|
|
spouses: [],
|
|
children: []
|
|
}];
|
|
const result = await FamilyHomePages.loadFamilyHome({
|
|
genealogyOverview(receivedId) {
|
|
calls.push(['overview', receivedId]);
|
|
return Promise.resolve(overviewFixture());
|
|
},
|
|
lineageTree(receivedId) {
|
|
calls.push(['tree', receivedId]);
|
|
return Promise.resolve(tree);
|
|
}
|
|
}, genealogyId);
|
|
|
|
assert.deepEqual(calls, [
|
|
['overview', genealogyId],
|
|
['tree', genealogyId]
|
|
]);
|
|
assert.deepEqual(result.overview, FamilyHomePages.normalizeFamilyOverview(
|
|
overviewFixture(),
|
|
genealogyId
|
|
));
|
|
assert.deepEqual(result.tree, tree);
|
|
});
|
|
|
|
test('家谱主页以 PC 工作台分组开放已接入功能且不制造旧 APP 伪功能', () => {
|
|
const source = fs.readFileSync(path.join(root, 'profile-family-home.html'), 'utf8');
|
|
const script = fs.readFileSync(path.join(root, 'public', 'js', 'family-home-pages.js'), 'utf8');
|
|
|
|
assert.doesNotMatch(source, /data-feature-status="pending"|pending-pages\.js/);
|
|
assert.doesNotMatch(source, /四川武胜汤氏族/);
|
|
assert.doesNotMatch(source, /href="profile-invite\.html"/);
|
|
assert.doesNotMatch(source, /href="profile-document/);
|
|
assert.match(source, /PC 暂未开放邀请/);
|
|
assert.match(source, /class="module-card is-unavailable" aria-disabled="true">\s*<span class="icon">邀<\/span>/);
|
|
assert.match(source, /重要证件/);
|
|
assert.match(source, /当前 PC 接口未提供家谱证件的列表、上传或维护能力/);
|
|
assert.match(source, /<h3>删除家谱<\/h3>/);
|
|
assert.match(source, /当前 PC 家谱契约未提供删除接口,暂不能查看或执行删除操作。/);
|
|
assert.doesNotMatch(source, /data-genealogy-delete|deleteGenealogy/);
|
|
assert.match(source, /亲友往来(贺礼簿)/);
|
|
assert.match(source, /备忘录(家族恩人)/);
|
|
assert.match(source, /当前 PC 不区分独立分类/);
|
|
assert.match(source, /data-family-home-title/);
|
|
assert.match(source, /data-family-home-overview/);
|
|
assert.match(source, /data-family-home-member-count/);
|
|
assert.match(source, /data-family-home-person-count/);
|
|
assert.match(source, /data-family-home-management/);
|
|
assert.match(source, /data-lineage-home-tree/);
|
|
assert.match(source, /data-family-home-overview[^>]*>[\s\S]*data-api-state="loading"/);
|
|
assert.match(source, /data-lineage-home-tree[^>]*>[\s\S]*data-api-state="loading"/);
|
|
assert.match(source, /src="public\/js\/lineage-pages\.js"/);
|
|
assert.match(source, /src="public\/js\/family-home-pages\.js"/);
|
|
assert.match(script, /root\.ProfileUI && root\.ProfileUI\.setApiState/);
|
|
assert.match(script, /setHomeState\('\[data-family-home-overview\]', 'loading', '正在加载家谱概览…'\)/);
|
|
assert.match(script, /setHomeState\('\[data-lineage-home-tree\]', 'loading', '正在加载世系树…'\)/);
|
|
assert.match(script, /setHomeState\('\[data-lineage-home-tree\]', 'empty', '暂无世系树'\)/);
|
|
assert.match(script, /treeHtml = Array\.isArray\(result\) \? root\.LineagePages\.renderLineageTreeHtml\(result\) : '';/);
|
|
assert.match(script, /if \(!treeHtml\) \{/);
|
|
assert.match(script, /当前账号无权查看该家谱世系树。/);
|
|
|
|
[
|
|
'profile-feed.html',
|
|
'profile-tree.html',
|
|
'profile-generation.html',
|
|
'profile-article.html',
|
|
'profile-album.html',
|
|
'profile-video.html',
|
|
'profile-merit.html',
|
|
'profile-ceremony.html',
|
|
'profile-gift.html',
|
|
'profile-growth.html',
|
|
'profile-relative.html',
|
|
'profile-memo.html',
|
|
'profile-family-admin.html',
|
|
'profile-services.html'
|
|
].forEach((href) => {
|
|
assert.match(
|
|
source,
|
|
new RegExp('href="' + href.replace('.', '\\.') + '"[^>]*data-genealogy-context-link'),
|
|
`${href} 缺少家谱上下文`
|
|
);
|
|
});
|
|
assert.match(source, /<h3>会员与订单<\/h3>/);
|
|
assert.match(source, /关联当前家谱创建会员订单,并查看已有订单。/);
|
|
});
|