feat(IMP-13): A-3 — build-time frame preview generator (capture_slide_screenshot salvage)
scripts/generate_frame_previews.py iterates figma_to_html_agent/blocks/{frame_id}/index.html,
renders preview.png via Selenium headless (capture_slide_screenshot pattern reuse), and writes
_preview_manifest.json (schema v1) with idempotent stale-detect (mtime+sha256). Build-time only
— no runtime pipeline integration, no AI calls, no MDX/Jinja regen. Stage 2 baseline (commit
56619a0): total=33, renderable=20, missing_index_html=13, orphan=1 (1171281192).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
tests/test_generate_frame_previews.py
Normal file
50
tests/test_generate_frame_previews.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""IMP-13 u7 smoke — discovery, source invariants, dry-run, idempotency, manifest schema."""
|
||||
from __future__ import annotations
|
||||
import json, os, re, sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
SCRIPT_PATH = REPO_ROOT / "scripts" / "generate_frame_previews.py"
|
||||
sys.path.insert(0, str(SCRIPT_PATH.parent))
|
||||
import generate_frame_previews as gfp # noqa: E402
|
||||
|
||||
def _fixture(root: Path) -> Path:
|
||||
blocks = root / "blocks"
|
||||
(blocks / "FRAME_A").mkdir(parents=True)
|
||||
(blocks / "FRAME_A" / "index.html").write_text("<html><body class=slide></body></html>", encoding="utf-8")
|
||||
(blocks / "FRAME_A" / "preview.png").write_bytes(b"\x89PNG\r\n\x1a\n")
|
||||
(blocks / "FRAME_B").mkdir()
|
||||
(blocks / "ORPHAN").mkdir()
|
||||
(blocks / "ORPHAN" / "preview.png").write_bytes(b"x")
|
||||
return blocks
|
||||
|
||||
def test_discover_counts(tmp_path: Path) -> None:
|
||||
rows = gfp.discover(_fixture(tmp_path))
|
||||
assert [r.frame_id for r in rows] == ["FRAME_A", "FRAME_B", "ORPHAN"]
|
||||
assert sum(r.has_index for r in rows) == 1 and sum(r.has_preview for r in rows) == 2
|
||||
|
||||
def test_source_invariants() -> None:
|
||||
src = SCRIPT_PATH.read_text(encoding="utf-8")
|
||||
for t in ("anthropic", "openai", "jinja", "phase_z2", "slide_measurer"): assert t not in src, t
|
||||
for lit in ("1280", "720", "1400", "900"): assert not re.search(rf"(?<!\d){lit}(?!\d)", src), lit
|
||||
|
||||
def test_dry_run_prints_counts(tmp_path: Path, capsys) -> None:
|
||||
rc = gfp.main(["--blocks-dir", str(_fixture(tmp_path)), "--manifest", str(tmp_path / "m.json"), "--dry-run"])
|
||||
assert rc == 0 and "discovered: total=3 with_index_html=1 with_preview_png=2" in capsys.readouterr().out
|
||||
|
||||
def test_idempotency_unchanged(tmp_path: Path) -> None:
|
||||
row = gfp.discover(_fixture(tmp_path))[0]
|
||||
mt = row.index_html_path.stat().st_mtime
|
||||
os.utime(row.preview_png_path, (mt + 1, mt + 1))
|
||||
sha = gfp._sha256_file(row.index_html_path)
|
||||
assert gfp.is_unchanged(row, {"index_sha256": sha}) is True
|
||||
assert gfp.is_unchanged(row, {"index_sha256": "x"}) is False
|
||||
assert gfp.is_unchanged(row, None) is False
|
||||
|
||||
def test_manifest_schema(tmp_path: Path) -> None:
|
||||
blocks = tmp_path / "blocks"; (blocks / "F").mkdir(parents=True); (blocks / "F" / "preview.png").write_bytes(b"x")
|
||||
mf = tmp_path / "m.json"
|
||||
assert gfp.main(["--blocks-dir", str(blocks), "--manifest", str(mf)]) == 0
|
||||
data = json.loads(mf.read_text(encoding="utf-8"))
|
||||
assert set(data) >= {"schema", "generated_at", "blocks_dir", "summary", "frames"} and data["schema"] == 1
|
||||
assert set(data["summary"]) >= {"total", "renderable", "missing_index_html", "orphan", "rendered", "skipped_unchanged", "error"} and data["summary"]["orphan"] == 1 and data["frames"]["F"]["status"] == "orphan"
|
||||
Reference in New Issue
Block a user