import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { collectWechatGeneratedImages, extractMindspaceCoverPath, verifyFreshWechatPageThumbnails, } from './generated-thumbnail.mjs'; function generatedImageMessages({ jobId = 'job-1', htmlSrc = 'images/fresh.webp' } = {}) { const result = { ok: true, jobId, source: { mimeType: 'image/webp' }, asset: { id: `asset-${jobId}`, htmlSrc, publicUrl: `https://example.com/MindSpace/user/public/${htmlSrc}`, workspaceRelativePath: `public/${htmlSrc}`, }, }; return [{ role: 'assistant', content: [ { id: `call-${jobId}`, type: 'toolRequest', toolCall: { value: { name: 'sandbox-fs__generate_image', arguments: { purpose: 'hero' } } }, }, { id: `call-${jobId}`, type: 'toolResponse', toolResult: { status: 'success', value: { content: [{ type: 'text', text: JSON.stringify(result) }] }, }, }, ], }]; } test('fresh page thumbnail must reference a current-run generated image', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-fresh-cover-')); try { const htmlPath = path.join(root, 'page.html'); fs.writeFileSync( htmlPath, '', 'utf8', ); const images = collectWechatGeneratedImages(generatedImageMessages()); assert.equal(images.length, 1); assert.equal(extractMindspaceCoverPath(fs.readFileSync(htmlPath, 'utf8')), 'images/fresh.webp'); const result = verifyFreshWechatPageThumbnails( [{ localPath: htmlPath, relativePath: 'public/page.html' }], images, ); assert.equal(result.ok, true); assert.equal(result.matches[0].image.jobId, 'job-1'); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('old cover path and sharing one generated image across two pages fail closed', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-stale-cover-')); try { const first = path.join(root, 'one.html'); const second = path.join(root, 'two.html'); fs.writeFileSync(first, ''); fs.writeFileSync(second, ''); const images = collectWechatGeneratedImages(generatedImageMessages()); const reused = verifyFreshWechatPageThumbnails( [ { localPath: first, relativePath: 'public/one.html' }, { localPath: second, relativePath: 'public/two.html' }, ], images, ); assert.equal(reused.ok, false); assert.equal(reused.reason, 'cover_not_from_current_run'); fs.writeFileSync(first, ''); const stale = verifyFreshWechatPageThumbnails( [{ localPath: first, relativePath: 'public/one.html' }], images, ); assert.equal(stale.ok, false); assert.equal(stale.reason, 'cover_not_from_current_run'); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('auxiliary admin pages do not require a separate generated thumbnail', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-aux-cover-')); try { const front = path.join(root, 'survey.html'); const admin = path.join(root, 'survey-admin.html'); fs.writeFileSync(front, ''); fs.writeFileSync(admin, ''); const result = verifyFreshWechatPageThumbnails( [ { localPath: front, relativePath: 'public/survey.html' }, { localPath: admin, relativePath: 'public/survey-admin.html' }, ], collectWechatGeneratedImages(generatedImageMessages()), ); assert.equal(result.ok, true); assert.equal(result.matches.length, 1); assert.equal(result.skippedArtifacts.length, 1); } finally { fs.rmSync(root, { recursive: true, force: true }); } });