309598bfa6
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、 siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法 - 添加帮助文章和站点资讯的参数验证逻辑 - 更新测试文件添加新的API方法测试用例 - 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用 - 更新加入家谱页面为完整的申请流程界面 - 修改资讯详情页面为站点资讯展示页面 - 更新AxiosRequestUtil中认证处理逻辑 - 添加世系树渲染的HTML生成函数用于页面复用 - 更新文档中的API契约说明和页面规划
117 lines
4.4 KiB
JavaScript
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, /<script>/);
|
|
assert.match(detailHtml, /<img src=x onerror=alert\(1\)><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/);
|
|
});
|