Files
jiapu/tests/video-pages.test.js
T
fizzleaf fb1743aa2a feat(api): 完善家谱系统API客户端契约
- 实现家谱管理相关方法,包括创建、详情、概览、我的家谱和选项查询
- 添加家谱加入申请功能,支持申请、审核、取消和待审核列表操作
- 集成通知详情获取方法和通知ID安全验证机制
- 完善功德记录、谱文、相册、视频、祭祀活动的完整CRUD操作契约
- 实现家谱成员管理功能,包含成员列表、更新、移除和转让所有者操作
- 优化路径ID验证逻辑,拒绝不安全的数值ID并提供明确错误提示
- 更新测试用例以验证所有新增API方法的路径和请求体白名单机制
2026-07-29 16:57:27 +08:00

155 lines
6.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 VideoPages = require('../public/js/video-pages.js');
test('视频页只从 URL 读取真实家谱和视频编号', () => {
assert.equal(VideoPages.getCurrentGenealogyId('?genealogyId=2060000000000000001&videoId=2060000000000000002'), '2060000000000000001');
assert.equal(VideoPages.getCurrentVideoId('?genealogyId=2060000000000000001&videoId=2060000000000000002'), '2060000000000000002');
assert.equal(VideoPages.getCurrentGenealogyId(''), '');
assert.equal(VideoPages.getCurrentVideoId('?videoId=unsafe'), '');
});
test('视频写入只构造 YAML VideoBody 字段并保持 OSS ID 为字符串', () => {
assert.deepEqual(VideoPages.buildVideoBody({
videoTitle: ' 家族活动记录 ',
videoDesc: ' 清明祭祖活动视频 ',
coverOssId: '2060000000000000001',
videoOssId: '2060000000000000002',
durationSeconds: '181',
sortOrder: '3',
status: '0',
publisherUserId: 'should-not-send',
viewCount: 99
}), {
videoTitle: '家族活动记录',
videoDesc: '清明祭祖活动视频',
coverOssId: '2060000000000000001',
videoOssId: '2060000000000000002',
durationSeconds: 181,
sortOrder: 3,
status: '0'
});
});
test('视频校验标题、上传文件、时长、排序和状态', () => {
assert.equal(VideoPages.validateVideoBody({ videoTitle: '', videoOssId: '1' }), '请填写视频标题');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题' }), '请先选择并上传视频文件');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '0' }), '视频文件上传结果无效');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '1', coverOssId: 'abc' }), '封面上传结果无效');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '1', durationSeconds: -1 }), '视频时长不能小于 0');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '1', sortOrder: undefined, invalidSortOrder: true }), '排序值必须是安全整数');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '1', status: '1' }), '当前 PC 无法重新读取停用视频,暂不开放停用');
assert.equal(VideoPages.validateVideoBody({ videoTitle: '标题', videoOssId: '1', status: '0' }), '');
});
test('视频响应使用 PC VideoVo 字段并拒绝不安全长 ID', () => {
assert.deepEqual(VideoPages.normalizeVideo({
videoId: '2060000000000000001',
genealogyId: '2060000000000000002',
genealogyNo: 'G20260729001',
genealogyName: '叶氏家谱',
surname: '叶',
videoTitle: '祭祖活动记录',
videoDesc: '活动影像',
coverOssId: '2060000000000000003',
videoOssId: '2060000000000000004',
durationSeconds: 180,
publisherUserId: '2060000000000000005',
publisherNickName: '叶子',
publisherPhone: '19100000000',
publishTime: '2026-07-29 10:00:00',
viewCount: 12,
sortOrder: 1,
status: '0',
remark: '归档'
}), {
videoId: '2060000000000000001',
genealogyId: '2060000000000000002',
genealogyNo: 'G20260729001',
genealogyName: '叶氏家谱',
surname: '叶',
videoTitle: '祭祖活动记录',
videoDesc: '活动影像',
coverOssId: '2060000000000000003',
videoOssId: '2060000000000000004',
durationSeconds: 180,
publisherUserId: '2060000000000000005',
publisherNickName: '叶子',
publisherPhone: '19100000000',
publishTime: '2026-07-29 10:00:00',
viewCount: 12,
sortOrder: 1,
status: '0',
remark: '归档'
});
assert.equal(VideoPages.normalizeVideo({
videoId: Number('2060000000000000001'),
genealogyId: '2',
videoTitle: '标题',
videoOssId: '3',
status: '0'
}), null);
});
test('视频渲染展示业务信息但不直接暴露 OSS ID 和发布人手机号', () => {
const video = VideoPages.normalizeVideo({
videoId: '1',
genealogyId: '2',
videoTitle: '<script>alert(1)</script>',
videoDesc: '活动影像',
coverOssId: '3',
videoOssId: '4',
durationSeconds: 180,
publisherUserId: '5',
publisherNickName: '叶子',
publisherPhone: '19100000000',
publishTime: '2026-07-29 10:00:00',
viewCount: 12,
sortOrder: 1,
status: '0'
});
const html = VideoPages.renderVideoDetail(video, true);
assert.doesNotMatch(html, /<script>/);
assert.match(html, /活动影像/);
assert.match(html, /叶子/);
assert.match(html, /已上传/);
assert.doesNotMatch(html, />3</);
assert.doesNotMatch(html, />4</);
assert.doesNotMatch(html, /19100000000/);
});
test('视频文件元数据时长按秒取整且拒绝无效值', () => {
assert.equal(VideoPages.normalizeDurationSeconds(180.2), 181);
assert.equal(VideoPages.normalizeDurationSeconds(0), 0);
assert.equal(VideoPages.normalizeDurationSeconds(-1), undefined);
assert.equal(VideoPages.normalizeDurationSeconds(Infinity), undefined);
});
test('视频列表和编辑页开放真实 PC 功能且不允许手填 OSS ID', () => {
const root = path.join(__dirname, '..');
const listPage = fs.readFileSync(path.join(root, 'profile-video.html'), 'utf8');
const editPage = fs.readFileSync(path.join(root, 'profile-video-edit.html'), 'utf8');
const styles = fs.readFileSync(path.join(root, 'public', 'css', 'profile-module.css'), 'utf8');
assert.doesNotMatch(listPage, /data-feature-status="pending"/);
assert.match(listPage, /data-video-list/);
assert.match(listPage, /data-video-detail/);
assert.match(listPage, /data-video-management hidden/);
assert.match(listPage, /src="public\/js\/video-pages\.js"/);
assert.match(editPage, /data-video-form data-video-management hidden/);
assert.match(editPage, /name="videoTitle"/);
assert.match(editPage, /name="videoDesc"/);
assert.match(editPage, /name="coverOssId" type="hidden"/);
assert.match(editPage, /name="videoOssId" type="hidden"/);
assert.match(editPage, /name="durationSeconds"[^>]+readonly/);
assert.doesNotMatch(editPage, /name="(?:coverOssId|videoOssId)"[^>]*type="text"/);
assert.match(editPage, /public\/js\/md5\.js/);
assert.match(editPage, /public\/js\/upload-pages\.js/);
assert.match(editPage, /public\/js\/video-pages\.js/);
assert.match(styles, /\[data-video-management\]\[hidden\]\s*\{[^}]*display:\s*none\s*!important/s);
});