import { spawnSync } from "node:child_process"; import { existsSync, readdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; import { ROOT } from "../lib/common.ts"; import { readdirScenes, type Scene } from "./runner.ts"; describe("README demo scenes", () => { it("executes the CLI entrypoint instead of silently skipping it", () => { const result = spawnSync( process.execPath, [join(ROOT, "scripts/demo/runner.ts"), "missing-demo-entrypoint-probe"], { cwd: ROOT, encoding: "utf8", timeout: 10_000 }, ); expect(result.error).toBeUndefined(); expect(result.status).toBe(1); expect(result.stderr).toContain("FAIL missing-demo-entrypoint-probe:"); expect(result.stderr).toContain("no demo/scene.json"); }); it("every scene is well-formed and its recordings are committed", () => { for (const name of readdirScenes()) { const dir = join(ROOT, "extensions", name); const scene = JSON.parse( readFileSync(join(dir, "demo", "scene.json"), "utf8"), ) as Scene; expect(scene.title, name).toBeTruthy(); expect(scene.extensions[0], `${name}: protagonist first`).toBe(name); expect(scene.steps.length, name).toBeGreaterThan(0); expect( scene.steps.some((step) => step.expect), `${name}: at least one expect`, ).toBe(true); for (const step of scene.steps) { if (step.expect) { expect(() => new RegExp(step.expect ?? "", "u")).not.toThrow(); expect( step.hold ?? 6, `${name}: reading pause`, ).toBeGreaterThanOrEqual(6); } if (step.hold !== undefined) expect( step.hold, `${name}: pause fits renderer idle limit`, ).toBeLessThanOrEqual(60); } expect( existsSync(join(dir, "demo", "SCENE.md")), `${name}: SCENE.md`, ).toBe(true); expect( existsSync(join(dir, "assets", "demo.cast")), `${name}: cast`, ).toBe(true); expect(existsSync(join(dir, "assets", "demo.gif")), `${name}: gif`).toBe( true, ); expect( readFileSync(join(dir, "README.md"), "utf8"), `${name}: README embeds the demo`, ).toContain("assets/demo.gif"); } }); it("no README embeds a demo without a scene behind it", () => { const root = join(ROOT, "extensions"); const scenes = new Set(readdirScenes()); for (const name of readdirSync(root)) { const readme = join(root, name, "README.md"); if (!existsSync(readme) || scenes.has(name)) continue; expect( readFileSync(readme, "utf8"), `${name}: demo.gif without demo/scene.json`, ).not.toContain("demo.gif"); expect( existsSync(join(root, name, "assets", "demo.gif")), `${name}: orphan assets/demo.gif`, ).toBe(false); } }); });