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

190 lines
8.7 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('视频维护资格只接受服务端返回的内容或管理布尔能力', () => {
const script = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'video-pages.js'), 'utf8');
assert.equal(VideoPages.canEditVideos({ canEditContent: true }), true);
assert.equal(VideoPages.canEditVideos({ canManage: true }), true);
assert.equal(VideoPages.canEditVideos({ canEditContent: 'true', canManage: false }), false);
assert.match(script, /setManagementAccess\(canEditVideos\(result\[0\]\)\)/);
});
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, /data-video-form data-video-management hidden novalidate/);
assert.match(editPage, /class="field-required"/);
assert.match(editPage, /<div class="form-status" data-video-form-status/);
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);
});
test('视频编辑将权限读取、校验、保存中和失败状态接入公共状态组件', () => {
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 script = fs.readFileSync(path.join(root, 'public', 'js', 'video-pages.js'), 'utf8');
assert.match(listPage, /data-video-list[^>]*>[\s\S]*data-api-state="loading"/);
assert.match(listPage, /data-video-detail[^>]*>[\s\S]*data-api-state="empty"/);
assert.match(editPage, /data-api-state="loading"[^>]*data-video-permission-placeholder/);
assert.match(script, /root\.ProfileUI && root\.ProfileUI\.setApiState/);
assert.match(script, /function setPermissionPlaceholder\(type, message\)/);
assert.match(script, /setVideoListState\('loading', '正在加载视频…'\)/);
assert.match(script, /setVideoDetailState\('loading', '正在加载视频详情…'\)/);
assert.match(script, /setVideoListState\('empty', '暂无家族视频'\)/);
assert.match(script, /setVideoListState\('forbidden', '当前账号无权查看该家谱视频。'\)/);
assert.match(script, /setVideoDetailState\(\n\s*getApiStateType\(error\)/);
assert.match(script, /正在读取家谱权限…', 'loading'/);
assert.match(script, /setPermissionPlaceholder\('forbidden', '当前账号没有视频维护权限。'\)/);
assert.match(script, /setFormStatus\(validation, 'error'\)/);
assert.match(script, /setWritePending\(true, '正在保存…'\)/);
assert.match(script, /getApiStateType\(error\)/);
});