133 lines
5.3 KiB
JavaScript
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, /<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);
|
|
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, '正在刷新…'\)/);
|
|
});
|