#!/usr/bin/env npx tsx
/**
* Generate HTML comparison page for evaluation recordings.
*/
import Handlebars from "handlebars";
import * as fs from "fs/promises";
import * as path from "path";
const SCENARIOS_DIR = path.join(import.meta.dirname, "scenarios");
const TEMPLATE_PATH = path.join(import.meta.dirname, "template.html");
async function getFileSize(filePath: string): Promise {
try {
const stat = await fs.stat(filePath);
return `${(stat.size / 1024).toFixed(1)}KB`;
} catch {
return null;
}
}
function baselineUrl(scenario: string, filename: string): string {
const repo = process.env.GITHUB_REPOSITORY || "dwmkerr/shellwright";
const branch = process.env.GITHUB_HEAD_REF || "main";
return `https://raw.githubusercontent.com/${repo}/${branch}/evaluations/scenarios/${scenario}/${filename}`;
}
interface ArtifactData {
artifactName: string;
baselineLocalSize: string | null;
baselineLocalUrl: string;
baselineCicdSize: string | null;
baselineCicdUrl: string;
recordedSize: string | null;
recordedPath: string;
}
interface ScenarioData {
name: string;
artifacts: ArtifactData[];
artifactCount: number;
}
async function discoverArtifacts(scenarioDir: string, scenarioName: string): Promise {
const files = await fs.readdir(scenarioDir);
const artifactFiles = files.filter(
(f) => (f.endsWith(".gif") || f.endsWith(".png")) && !f.startsWith("baseline-")
);
artifactFiles.sort();
return Promise.all(
artifactFiles.map(async (filename) => {
const ext = path.extname(filename);
const base = path.basename(filename, ext);
const baselineLocalFile = `baseline-local-${base}${ext}`;
const baselineCicdFile = `baseline-cicd-${base}${ext}`;
return {
artifactName: filename,
baselineLocalSize: await getFileSize(path.join(scenarioDir, baselineLocalFile)),
baselineLocalUrl: baselineUrl(scenarioName, baselineLocalFile),
baselineCicdSize: await getFileSize(path.join(scenarioDir, baselineCicdFile)),
baselineCicdUrl: baselineUrl(scenarioName, baselineCicdFile),
recordedSize: await getFileSize(path.join(scenarioDir, filename)),
recordedPath: `./${scenarioName}/${filename}`,
};
})
);
}
async function main() {
const entries = await fs.readdir(SCENARIOS_DIR, { withFileTypes: true });
const scenarios: ScenarioData[] = await Promise.all(
entries
.filter((e) => e.isDirectory())
.map(async (e) => {
const artifacts = await discoverArtifacts(
path.join(SCENARIOS_DIR, e.name),
e.name
);
return {
name: e.name,
artifacts,
artifactCount: artifacts.length,
};
})
);
const templateSrc = await fs.readFile(TEMPLATE_PATH, "utf-8");
const template = Handlebars.compile(templateSrc);
const html = template({ scenarios });
await fs.writeFile(path.join(SCENARIOS_DIR, "index.html"), html);
console.log("Generated index.html");
}
main().catch(console.error);