Files
jiapu/tests/help-pages.test.js
T
fizzleaf 309598bfa6 feat(api): 添加帮助中心反馈系统和VIP服务功能
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、
  siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法
- 添加帮助文章和站点资讯的参数验证逻辑
- 更新测试文件添加新的API方法测试用例
- 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用
- 更新加入家谱页面为完整的申请流程界面
- 修改资讯详情页面为站点资讯展示页面
- 更新AxiosRequestUtil中认证处理逻辑
- 添加世系树渲染的HTML生成函数用于页面复用
- 更新文档中的API契约说明和页面规划
2026-07-30 16:04:48 +08:00

117 lines
4.4 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);
});
test('帮助中心使用真实 PC 列表和详情,不再展示硬编码问答', () => {
const page = read('help.html');
assert.match(page, /data-help-list/);
assert.match(page, /data-help-status/);
assert.match(page, /public\/js\/help-pages\.js/);
assert.doesNotMatch(page, /如何创建第一本家谱|如何邀请亲人一起维护/);
assert.doesNotMatch(page, /data-feature-status="pending"|pending-pages\.js/);
});