#!/usr/bin/env python3 """Are the consoles' and launcher's 21 native dialogs gone? — BL-024, 2026-08-20. S1 counted 79 native dialogs app-wide; its two tasks (T5.8 wizard, T7.9 creator) removed 58 and the audit found the remaining 21 on surfaces no S1 task named: admin.js (6), users.js (10), the launcher's inline script (5). They now go through `wp-dialog.js` — the T7.9 kit extracted as a shared, self-injecting component (guarded so the creator's inline copy still wins on its own page). Static half greps the counts; browser half drives the users console's dialogs with natives poisoned and proves they still work end to end. Used to drive this via the password-reset prompt specifically, because it was the one place on this page exercising wp-dialog.js's PROMPT variant (text input + client-side validate()) rather than its confirm variant. T10.4 (D15/D16) removed admin password reset entirely — there is no password to reset anymore — so that coverage moved with it. The prompt-with-validate() pattern itself is still exercised, just not on this page: see creator_dialogs_check.py for wp-creation-app.js's own wpPromptDialog() call sites. If users.html ever grows a new prompt-style dialog, it belongs back in this file. Boots its own throwaway SQLite + uvicorn + headless browser; run it alone. Exit 0 all passed, 1 a failure, 2 could not run. """ import io import os import re import sys import tempfile import time sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import cdp # noqa: E402 from browser_check import seed, start_server, chk, _PASS, _FAIL # noqa: E402 from qa_gate_check import api # noqa: E402 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) HTML = os.path.join(ROOT, "html") def ascii_(v, n=240): return re.sub(r"\s+", " ", str(v)).encode("ascii", "replace").decode()[:n] def strip_js(src): src = re.sub(r"/\*.*?\*/", "", src, flags=re.S) return "\n".join(re.sub(r"(?{throw new Error('native alert reached')};" "window.confirm=()=>{throw new Error('native confirm reached')};" "window.prompt=()=>{throw new Error('native prompt reached')};") chk("the console booted with a user table", page.eval("!!document.querySelector('table')")) print("\n3. destroy needs a real yes") page.eval("void deleteUser('user_bob','bob')") time.sleep(0.4) chk("the delete asks through the kit, spelling out what goes with it", page.eval("(() => { const o=document.getElementById('wp-dlg-overlay');" " return o.classList.contains('open')" " && /cannot be undone/.test(document.getElementById('wp-dlg-msg').textContent); })()")) page.eval("document.getElementById('wp-dlg-cancel').click()") time.sleep(0.6) st, users = api(base, "/api/auth/users", tok["root"]) chk("cancel means no: bob is still an account", st == 200 and any(u.get("username") == "bob" for u in (users or [])), ascii_([u.get("username") for u in (users or [])])) errs = [e for e in page.js_errors() if "beforeunload" not in e] chk("no JavaScript errors, and no path reached a native dialog (they throw here)", not errs, ascii_(errs[:3])) finally: if browser: browser.close() if server: server.terminate() print("\n" + "-" * 54) print("%d/%d checks passed." % (len(_PASS), len(_PASS) + len(_FAIL))) for f in _FAIL: print(" - " + f) return 1 if _FAIL else 0 if __name__ == "__main__": sys.exit(main())