JAA-ATS-Tool / scripts /verify_side_panel.py
saitejatirunagari's picture
fix: pinned musl Tectonic + guaranteed PDF fallback + panel/popup sync (v1.5.2)
355c4d1
Raw
History Blame
4.34 kB
#!/usr/bin/env python3
"""Deterministic static-analysis regression for Phase 08-03: persistent side
panel (R18). The extension JS can't run headless, so we assert the wiring
CONTRACT by source inspection (mirroring the 06/07 plans). ASCII-only output.
Proves:
* content.js injects an idempotent left-docked iframe panel hosting
popup/popup.html, with a collapse/dismiss toggle, handles TOGGLE_PANEL, and
keeps EXTRACT_JD; it never disables page interaction globally.
* manifest.json exposes the popup via web_accessible_resources, bumps the
version to 1.5.0, and retains the content script + default_popup launcher.
* popup.js keeps the background-owned run (ats_results + storage.onChanged +
getCurrentUrlKey), adds launcher/embed awareness (TOGGLE_PANEL + window.top),
and surfaces the 08-01 LaTeX compile-failure reason (pdf_error + compile_log).
Exit code: 0 when every assertion passes, 1 otherwise.
"""
import json
import os
import sys
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
EXT = os.path.join(REPO_ROOT, "extension")
CONTENT = os.path.join(EXT, "content.js")
MANIFEST = os.path.join(EXT, "manifest.json")
POPUP_JS = os.path.join(EXT, "popup", "popup.js")
_failures = []
def _read(path):
with open(path, encoding="utf-8") as fh:
return fh.read()
def check(condition, message):
if condition:
print(f" [PASS] {message}")
else:
print(f" [FAIL] {message}")
_failures.append(message)
def test_content_js():
print("[1] content.js injects a persistent left-docked iframe panel")
js = _read(CONTENT)
for token in ("injectSidePanel", "ats-side-panel-root",
"chrome.runtime.getURL", "popup/popup.html",
"TOGGLE_PANEL", "collapsed"):
check(token in js, f"content.js references '{token}'")
check("ats-side-panel-toggle" in js or "ats-side-panel-dismiss" in js,
"collapse/dismiss toggle present")
check("EXTRACT_JD" in js, "JD extraction listener preserved")
# Crude guard against blocking the whole page.
check("document.body.style.pointerEvents" not in js,
"does NOT globally disable page pointer events")
def test_manifest():
print("[2] manifest.json exposes popup + bumps version, keeps launcher")
m = json.loads(_read(MANIFEST))
war = m.get("web_accessible_resources")
check(bool(war), "web_accessible_resources present")
res = (war[0].get("resources") if war else []) or []
check(any("popup/popup.html" in r for r in res),
"popup/popup.html is web-accessible")
# Panel landed in 1.5.0; accept any >= 1.5.0 so follow-up patch bumps
# (1.5.1, 1.5.2, ...) don't break this check.
_vt = tuple(int(x) for x in str(m.get("version", "0")).split("."))
check(_vt >= (1, 5, 0), f"version >= 1.5.0 (got {m.get('version')})")
cs = m.get("content_scripts", [])
check(any("content.js" in (c.get("js") or []) for c in cs)
and any("<all_urls>" in (c.get("matches") or []) for c in cs),
"content.js still registered on <all_urls>")
check(bool(m.get("action", {}).get("default_popup")),
"default_popup retained (thin launcher)")
def test_popup_js():
print("[3] popup.js keeps background-owned run + adds launcher/embed + pdf_error")
js = _read(POPUP_JS)
for token in ("ats_results", "chrome.storage.onChanged", "getCurrentUrlKey"):
check(token in js, f"popup.js retains '{token}' (R15 run + live reflect)")
check("TOGGLE_PANEL" in js and "window.top" in js,
"popup.js has launcher/embed awareness (TOGGLE_PANEL + window.top)")
check("pdf_error" in js and "compile_log" in js,
"popup.js surfaces the 08-01 LaTeX compile-failure reason")
def main():
print("=" * 68)
print("Phase 08-03 verification: persistent left-docked side panel (R18)")
print("=" * 68)
test_content_js()
test_manifest()
test_popup_js()
print("-" * 68)
if _failures:
print(f"FAIL - {len(_failures)} check(s) failed:")
for f in _failures:
print(f" - {f}")
return 1
print("PASS - persistent side panel wiring verified (iframe panel + manifest "
"+ background-owned run + pdf_error surfacing)")
return 0
if __name__ == "__main__":
sys.exit(main())