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, /
]+alt="彭氏家谱封面"/); assert.match(html, /loading="lazy"/); assert.match(html, /signature=a&expires=1/); assert.match(html, /
彭氏家谱<\/figcaption>/); assert.doesNotMatch(html, /private-oss-key|ossId/); }); test('renders avatar initials when no authorized image exists', () => { assert.equal( MediaDisplay.renderAvatar(null, { name: '彭小雨' }), '' ); }); 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, /]+controls/); assert.match(gallery, /下载 record\.pdf/); });