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, repairUnambiguousFreshWechatPageThumbnail, verifyFreshWechatPageThumbnails, } from './generated-thumbnail.mjs'; function generatedImageMessages({ jobId = 'job-1', htmlSrc = 'images/fresh.webp' } = {}) { const result = { ok: true, purpose: 'hero', 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 }); } }); test('one current-run hero repairs one page from the current write snapshot and re-verifies', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-repair-cover-')); try { const htmlPath = path.join(root, 'page.html'); const diskHtml = 'disk copy'; const currentRunHtml = 'current run copy'; fs.writeFileSync(htmlPath, diskHtml, 'utf8'); const artifacts = [{ localPath: htmlPath, relativePath: 'public/page.html' }]; const images = collectWechatGeneratedImages(generatedImageMessages()); const failed = verifyFreshWechatPageThumbnails(artifacts, images); assert.equal(failed.reason, 'missing_generated_cover'); const repaired = repairUnambiguousFreshWechatPageThumbnail({ artifacts, images, currentRunHtmlArtifacts: [{ relativePath: 'public/page.html', content: currentRunHtml }], verificationReason: failed.reason, }); assert.equal(repaired.ok, true); assert.equal(repaired.restoredCurrentRunHtml, true); const written = fs.readFileSync(htmlPath, 'utf8'); assert.match(written, /current run copy/); assert.doesNotMatch(written, /disk copy/); assert.equal(extractMindspaceCoverPath(written), 'images/fresh.webp'); assert.equal(verifyFreshWechatPageThumbnails(artifacts, images).ok, true); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('thumbnail repair refuses an ambiguous page-to-image mapping without changing the page', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-ambiguous-repair-')); try { const htmlPath = path.join(root, 'page.html'); const original = ''; fs.writeFileSync(htmlPath, original, 'utf8'); const artifacts = [{ localPath: htmlPath, relativePath: 'public/page.html' }]; const images = collectWechatGeneratedImages([ ...generatedImageMessages({ jobId: 'job-1', htmlSrc: 'images/one.webp' }), ...generatedImageMessages({ jobId: 'job-2', htmlSrc: 'images/two.webp' }), ]); const repaired = repairUnambiguousFreshWechatPageThumbnail({ artifacts, images, verificationReason: 'missing_generated_cover', }); assert.equal(repaired.ok, false); assert.equal(repaired.reason, 'ambiguous_page_image_mapping'); assert.equal(fs.readFileSync(htmlPath, 'utf8'), original); } finally { fs.rmSync(root, { recursive: true, force: true }); } });