Files
jiapu/tests/help-pages.test.js
T
2026-08-03 16:49:38 +08:00

133 lines
5.3 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const test = require('node:test');
const HelpPages = require('../public/js/help-pages.js');
const helpId = '2062179707935264769';
function read(relativePath) {
return fs.readFileSync(path.resolve(__dirname, '..', relativePath), 'utf8');
}
function helpFixture(overrides) {
return Object.assign({
helpId,
helpCategory: '账号与安全',
helpTitle: '如何修改登录密码?',
helpContent: '进入账号安全页,完成验证后修改密码。',
coverOssId: '2062179707935264701',
sortOrder: 10,
viewCount: 12,
status: '0',
remark: 'internal-only'
}, overrides);
}
test('帮助文章只保留 HelpArticleVo 的安全展示字段并保持长 ID 字符串', () => {
assert.deepEqual(HelpPages.normalizeHelpArticle(helpFixture()), {
helpId,
helpCategory: '账号与安全',
helpTitle: '如何修改登录密码?',
helpContent: '进入账号安全页,完成验证后修改密码。',
viewCount: '12'
});
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({
helpId: Number.MAX_SAFE_INTEGER + 1
})), null);
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({
viewCount: '9007199254740993123'
})).viewCount, '9007199254740993123');
});
test('帮助文章拒绝停用、空标题、空正文和非法浏览量', () => {
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({ status: '1' })), null);
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({ helpTitle: ' ' })), null);
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({ helpContent: '' })), null);
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({ viewCount: -1 })), null);
assert.equal(HelpPages.normalizeHelpArticle(helpFixture({ viewCount: '1.5' })), null);
});
test('帮助文章列表只接受直接数组且任一非法元素使整批失败', () => {
assert.equal(HelpPages.normalizeHelpArticleList([helpFixture()]).length, 1);
assert.deepEqual(HelpPages.normalizeHelpArticleList([]), []);
assert.deepEqual(HelpPages.normalizeHelpArticleList({
rows: [helpFixture()]
}), []);
assert.deepEqual(HelpPages.normalizeHelpArticleList([
helpFixture(),
helpFixture({ helpId: '' })
]), []);
});
test('帮助文章列表和详情转义响应且不暴露 OSS ID、排序、状态和备注', () => {
const article = helpFixture({
helpTitle: '<script>alert(1)</script>',
helpContent: '<img src=x onerror=alert(1)>\n第二行',
helpCategory: '<b>分类</b>',
coverOssId: 'secret-oss',
remark: 'secret-remark'
});
const listHtml = HelpPages.renderHelpArticleList([article]);
const detailHtml = HelpPages.renderHelpArticleDetail(article);
assert.match(listHtml, /&lt;script&gt;/);
assert.match(detailHtml, /&lt;img src=x onerror=alert\(1\)&gt;<br \/>第二行/);
assert.doesNotMatch(listHtml + detailHtml, /<script|<img|secret-oss|secret-remark|coverOssId|sortOrder|status|remark/);
});
test('帮助文章详情必须与列表中点击的真实 helpId 一致', async () => {
const calls = [];
const api = {
async helpArticleDetail(id) {
calls.push(id);
return helpFixture();
}
};
assert.equal((await HelpPages.loadHelpArticleDetail(api, helpId)).helpId, helpId);
assert.deepEqual(calls, [helpId]);
await assert.rejects(
HelpPages.loadHelpArticleDetail({
async helpArticleDetail() {
return helpFixture({ helpId: '2062179707935264770' });
}
}, helpId),
/详情响应与请求编号不一致/
);
});
test('帮助中心只把缺失登录态和 401 视为登录失效', () => {
assert.equal(HelpPages.shouldRedirectToLogin(null), true);
assert.equal(HelpPages.shouldRedirectToLogin({ getToken() { return ''; } }), true);
assert.equal(HelpPages.shouldRedirectToLogin({ getToken() { return 'token'; } }, { status: 401 }), true);
assert.equal(HelpPages.shouldRedirectToLogin({ getToken() { return 'token'; } }, { status: 403 }), false);
assert.equal(HelpPages.isForbidden({ status: 403 }), true);
assert.equal(HelpPages.isForbidden({ status: 401 }), false);
});
test('帮助中心使用真实 PC 列表和详情,不再展示硬编码问答', () => {
const page = read('help.html');
assert.match(page, /data-help-list/);
assert.match(page, /data-help-status/);
assert.match(page, /data-help-status[^>]*role="status"/);
assert.match(page, /data-api-state="loading"/);
assert.match(page, /public\/js\/help-pages\.js/);
assert.match(page, /public\/js\/profile-common\.js/);
assert.doesNotMatch(page, /如何创建第一本家谱|如何邀请亲人一起维护/);
assert.doesNotMatch(page, /data-feature-status="pending"|pending-pages\.js/);
});
test('帮助中心将加载、空数据、失败和无权限写入统一状态组件', () => {
const source = read('public/js/help-pages.js');
assert.match(source, /root\.ProfileUI && root\.ProfileUI\.setApiState/);
assert.match(source, /setApiState\(list, 'loading', '正在读取帮助文章…'\)/);
assert.match(source, /setApiState\(list, 'empty', '当前暂无帮助文章。'\)/);
assert.match(source, /setApiState\(panel, 'loading', '正在读取完整解答…'\)/);
assert.match(source, /isForbidden\(error\) \? 'forbidden' : 'error'/);
assert.match(source, /setPendingButton\(refresh, true, '正在刷新…'\)/);
});