Adds hashes & base64 encoded images

This commit is contained in:
Henning Dieterichs
2026-06-16 01:10:59 +02:00
committed by Henning Dieterichs
parent a2c29d6297
commit cf0e90192a

View File

@@ -20,7 +20,7 @@
* node test/componentFixtures/cssOrderScan.mts [--out <dir>] [--fixture-id-regex <rx>]
*/
import { copyFile, mkdir, rm, writeFile } from 'node:fs/promises';
import { copyFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { bisectConflict, type FixtureEntry, readServeUrl, Renderer } from './cssOrderShared.mts';
@@ -98,15 +98,23 @@ function slugify(fixtureId: string): string {
return fixtureId.replace(/[^a-zA-Z0-9._-]+/g, '_');
}
/** Markdown image source for a captured render, honoring `--image-base-url`. */
function imageSource(args: Args, hash: string, relativePath: string | undefined): string | undefined {
/**
* A Markdown link (not an embedded image) to a captured render. Honors
* `--image-base-url` when set; otherwise inlines the PNG as a base64 `data:`
* URI so the report stays self-contained without bloating it with `<img>`s.
*/
async function imageLink(args: Args, label: string, hash: string, relativePath: string | undefined): Promise<string | undefined> {
if (args.imageBaseUrl) {
return `${args.imageBaseUrl.replace(/\/$/, '')}/${hash}`;
return `[${label}](${args.imageBaseUrl.replace(/\/$/, '')}/${hash})`;
}
return relativePath;
if (!relativePath) {
return undefined;
}
const bytes = await readFile(join(args.out, relativePath));
return `[${label}](data:image/png;base64,${bytes.toString('base64')})`;
}
function renderMarkdown(args: Args, problems: readonly Problem[], totals: { scanned: number; errored: number }): string {
async function renderMarkdown(args: Args, problems: readonly Problem[], totals: { scanned: number; errored: number }): Promise<string> {
const lines: string[] = [];
const clean = totals.scanned - problems.length - totals.errored;
@@ -177,15 +185,14 @@ function renderMarkdown(args: Args, problems: readonly Problem[], totals: { scan
}
lines.push(`- Later document (wins): ${fileLink(p.laterFile)} — document #${p.laterIndex}`);
lines.push(`- Earlier document (loses): ${fileLink(p.earlierFile)} — document #${p.earlierIndex}`);
lines.push(`- Image hash: \`${p.baselineHash.slice(0, 12)}\` (baseline) → \`${p.reversedHash.slice(0, 12)}\` (reversed)`, '');
lines.push(`- Image hash: \`${p.baselineHash.slice(0, 12)}\` (baseline) → \`${p.reversedHash.slice(0, 12)}\` (reversed)`);
const baseSrc = imageSource(args, p.baselineHash, p.baselineImage);
const revSrc = imageSource(args, p.reversedHash, p.reversedImage);
if (baseSrc && revSrc) {
lines.push('| Baseline (product order) | Reversed order |');
lines.push('| --- | --- |');
lines.push(`| ![baseline](${baseSrc}) | ![reversed](${revSrc}) |`, '');
const baseLink = await imageLink(args, 'baseline image', p.baselineHash, p.baselineImage);
const revLink = await imageLink(args, 'reversed image', p.reversedHash, p.reversedImage);
if (baseLink && revLink) {
lines.push(`- Images: ${baseLink} (product order) · ${revLink} (reversed order)`);
}
lines.push('');
}
return lines.join('\n');
@@ -237,6 +244,7 @@ async function main(): Promise<void> {
}
const n = files.length;
process.stdout.write(`\n[${i + 1}/${candidates.length}] Localizing ${base.fixtureId} (${n} documents)...\n`);
process.stdout.write(` hashes: baseline=${base.imageHash} reversed=${rev.imageHash}\n`);
let probeCount = 0;
const { later, earlier } = await bisectConflict(renderer, base.fixtureId, n, base.imageHash!, ({ fromIndex, toIndex, differs, ms }) => {
const verdict = differs ? 'DIFFERS' : 'same';
@@ -274,7 +282,7 @@ async function main(): Promise<void> {
process.stdout.write(` → #${earlier} ${fileBaseName(files[earlier] ?? '?')} loses to #${later} ${fileBaseName(files[later] ?? '?')}\n`);
}
const markdown = renderMarkdown(args, problems, { scanned: baseline.entries.length, errored });
const markdown = await renderMarkdown(args, problems, { scanned: baseline.entries.length, errored });
await writeFile(join(args.out, 'report.md'), `${markdown}\n`, 'utf8');
await writeFile(join(args.out, 'report.json'), `${JSON.stringify({ generatedAt: new Date().toISOString(), commit: GITHUB_SHA, scanned: baseline.entries.length, errored, problems }, undefined, '\t')}\n`, 'utf8');