# Standalone login renderer host tests From the repository root: ```sh python3 tests/web_login_ui/run.py # Optional compiler selection: CC=clang python3 tests/web_login_ui/run.py ``` Requires Python 3, a C11 compiler supporting Linux shared libraries, and Node.js 24 on PATH. No pip/npm packages, ESP-IDF installation, network, device, or live HTTP routes are needed. Do not run Python with `-O` (checks use assertions). The runner compiles the actual `src/web_login_ui.c` and header with `-Wall -Wextra -Werror` and tiny ESP/httpd stubs in an automatically removed temporary directory. It checks NULL handling, all response setter failures (stop immediately without sending), send error propagation, content type, security headers, and the eight additional-header-slot budget. It parses the captured HTML to reject external assets and compares the CSP script hash against SHA256 of the exact rendered inline script bytes, including surrounding newlines. JavaScript tests still run on a hash mismatch so it does not hide behavioral test results. `browser.cjs` executes that rendered script in Node's VM using DOM/fetch doubles, real Response/ReadableStream, UTF-8 encoders/decoders, and AbortController. It covers no automatic requests, challenge/custom-header and CSRF JSON submission, redirect, wrong credentials/fresh challenges, status errors and manual-only Retry-After backoff, malformed/oversized responses, network failure/timeout, input byte limits, duplicate submission, and pagehide/pageshow generation safety (including late fetches and late body reads), attempt-abort cleanup on every error status, disabled pending inputs, and clearing re-entered passwords. Error bodies carry a marker that must never appear in displayed error text. Limitations: this is not a real browser, ESP-IDF HTTP server, authentication backend, or hardware test. It does not validate route registration, cookies, TLS, native form validation, browser CSP enforcement, layout/accessibility, or actual bfcache behavior. Timers and clock advancement are deterministic doubles; fetch doubles can intentionally ignore abort to exercise stale completion paths. Error-body stream abortion is modeled with fetch abort listeners, not real socket cleanup. Clearing DOM fields/JavaScript references is best-effort secret lifetime reduction, not guaranteed erasure of garbage-collected strings or browser internals. The 16/64-byte field limits bound maximally escaped JSON to 509 bytes, so the separate >512-byte request guard is not independently reachable with valid fields; the suite tests worst-case expansion rather than bypassing those field checks. Nothing here exposes a route or regenerates protected web assets.