Files
jiapu/tests/media-display.test.js
T
2026-08-29 19:06:07 +08:00

81 lines
3.3 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const MediaDisplay = require('../public/js/media-display');
const imageFile = {
fileId: '2060000000000000001',
ossId: 'private-oss-key',
fileName: 'family-cover.jpg',
mediaType: 'image/jpeg',
fileSize: 1024,
accessUrl: 'https://files.example/family-cover.jpg?signature=a&expires=1',
expiresAt: '2026-08-28T03:00:00+08:00'
};
test('attachment galleries keep a human-sized thumbnail grid and preserve the whole image', () => {
const css = readFileSync(require.resolve('../public/css/public.css'), 'utf8');
const moduleCss = readFileSync(require.resolve('../public/css/profile-module.css'), 'utf8');
assert.match(css, /\.media-gallery\s*\{[^}]*grid-template-columns:\s*repeat\(auto-fill,\s*minmax\(min\(200px,\s*100%\),\s*280px\)\)/s);
assert.match(css, /\.media-gallery\s+\.media-frame\s+img\s*\{[^}]*object-fit:\s*contain/s);
assert.match(moduleCss, /:is\(\.article-cover-media,\s*\.album-cover-media,\s*\.ceremony-cover-media\)\s+img\s*\{[^}]*object-fit:\s*contain/s);
assert.match(moduleCss, /\.video-detail-media\s+video\s*\{[^}]*object-fit:\s*contain/s);
});
test('normalizes authorized file access without exposing storage identifiers', () => {
const normalized = MediaDisplay.normalizeFileAccess(imageFile);
assert.deepEqual(normalized, {
fileId: '2060000000000000001',
fileName: 'family-cover.jpg',
mediaType: 'image/jpeg',
fileSize: 1024,
accessUrl: imageFile.accessUrl,
expiresAt: imageFile.expiresAt
});
assert.equal('ossId' in normalized, false);
});
test('rejects unsafe and incomplete media URLs', () => {
assert.equal(MediaDisplay.normalizeFileAccess({ accessUrl: 'javascript:alert(1)' }), null);
assert.equal(MediaDisplay.normalizeFileAccess({ accessUrl: '/resource/oss/1' }), null);
assert.equal(MediaDisplay.normalizeFileAccess({ fileId: '1' }), null);
});
test('renders an accessible lazy image and escapes signed URLs', () => {
const html = MediaDisplay.renderImage(imageFile, {
alt: '彭氏家谱封面',
className: 'family-cover',
caption: '彭氏家谱'
});
assert.match(html, /<figure class="media-frame family-cover"/);
assert.match(html, /<img[^>]+alt="彭氏家谱封面"/);
assert.match(html, /loading="lazy"/);
assert.match(html, /signature=a&amp;expires=1/);
assert.match(html, /<figcaption>彭氏家谱<\/figcaption>/);
assert.doesNotMatch(html, /private-oss-key|ossId/);
});
test('renders avatar initials when no authorized image exists', () => {
assert.equal(
MediaDisplay.renderAvatar(null, { name: '彭小雨' }),
'<span class="media-avatar" aria-label="彭小雨的头像">彭</span>'
);
});
test('renders mixed media gallery with image, video and downloadable files', () => {
const gallery = MediaDisplay.renderGallery([
imageFile,
{ ...imageFile, fileId: '2', fileName: 'memory.mp4', mediaType: 'video/mp4', accessUrl: 'https://files.example/memory.mp4' },
{ ...imageFile, fileId: '3', fileName: 'record.pdf', mediaType: 'application/pdf', accessUrl: 'https://files.example/record.pdf' }
], { label: '成长日志附件' });
assert.match(gallery, /aria-label="成长日志附件"/);
assert.match(gallery, /<img/);
assert.match(gallery, /<video[^>]+controls/);
assert.match(gallery, /下载 record\.pdf/);
});