# Browser Session and Terminal Selector Tests Run from the repository root: ```sh python3 tests/web_ui_session/run.py ``` Requires a host C compiler, Python 3, and Node with Fetch/Response/ReadableStream support (Node 18+). All compiler outputs and rendered scripts are temporary; no firmware build, generated assets, or device writes are performed. The runner compiles production `src/web_ui.c` with HTTPD and vendored-asset data doubles. It reuses the HTTPD stub text from `tests/web_login_ui/run.py`, without importing/executing that runner. Node executes the actual C-rendered application and inline asset-failure script, not a separately maintained implementation. Historical 8D.17 run: **126 behavior groups**, plus production renderer/HTML/CSP checks. Seven new quick groups cover mouse/focus/touch activation, single DOM ownership, focused-editor hover stability, Escape/outside dismissal, late reads/expiry, terminal input/drain isolation, full-page draft/promotion preservation, explicit Apply/Save and pending non-replay, Network secret exclusion/strict schema/401. `Element` focus/containment/hover and events are doubles, not browser event-dispatch proof. Optional geometry: `WEB_UI_CHROMIUM=/usr/bin/chromium-browser python3 tests/web_ui_session/run.py`. The fixture covers 36 cases at 320/600/900/1200px: full settings and quick panels plus dashboard card hit-testing, overflow/ellipsis, compact controls, status visibility, and full-page restoration. Quick panels use height 360px. The 2026-09-14 cosmetic update passed these Chromium fixtures and all 161 browser behavior groups; fixtures are not live-device validation. See [contextual-control contracts](../../docs/web_administration.md#broker-and-contextual-controls), [acceptance evidence and limits](../../docs/web_administration_acceptance.md), and [regression procedures](../../docs/user_administration_tests.md#integrated-web-administration-regression-procedure). Coverage: - Resource selection, NULL/invalid input, setter/send failure propagation, eight-header ceiling, no-store document/application, unchanged vendor caching, nosniff/no-referrer/frame denial, exact inline-loader CSP hash and login fallback. - Session validation before initial/retried/restored connections; memory-only CSRF header and empty ticket/logout bodies; safe-text username/absolute expiry. - 401 shutdown and navigation once; manual recovery on 403; bounded Retry-After display/backoff for capacity; network errors never assert successful logout. - Confirmed 204 logout, lost response confirmed by session 401, uncertain logout, cancellation, explicit recovery, and stale session/ticket/status/logout/WS work. - Pagehide/bfcache restoration, late response bodies, and superseded session checks. - Existing writer controls, 1,024-byte binary input chunks, raw binary output, observer input gating, and explicit Disconnect pausing reconnect. - Authentication/ticket response cap 512 bytes, existing status cap 3,072 bytes, 15-second request deadline, single status request in flight, bounded retry delay, and unchanged 5,000-line terminal scrollback. - Admin-only navigation, explicit protected-ticket open, 20 switches preserving serial socket/client/writer IDs, separate output and selected-only input. - Independent 64 KiB pending output limits, visible dropped-byte counters and resumed hidden output draining; 512-byte admin input frames and overflow close. - Admin close/reopen/remote exit isolation, 401/logout/expiry/pagehide cancellation, late tickets/callbacks, handshake timeout, selected resize and three listener cleanup/restore cycles. - Session identity changes (username, role or session-stable CSRF) force a clean document before view adoption, close old admin and prevent replacement-session logout; same-session restore retains both scrollbacks behind validation gating. - Undefined initial dimensions recover at unchanged bounds; failed fits never populate the cache, readiness retries stop at three, and teardown fences stale callbacks even after restore. - Read-only admin Settings/Serial: 10 selection cycles preserve both sockets/IDs, drain hidden output and block terminal input; exact eight-field/256-byte schema, explicit refresh, error/timeout containment, late cancellation/restore/identity, and concurrent serial reconnect without superseding admission. - 8D.9 typed Serial actions: draft validation, Reset-only confirmation, bounded JSON/CSRF, explicit working/persisted effects, automatic bounded result checks, failure/timeout containment, session fencing and preserved sockets/writer identity. - Lost-acknowledgement and replaced-result uncertainty survives repeated result checks, failed reads, refresh and navigation; a newly acknowledged explicit submission starts a new result context. - Immediate completion on the first GET, pending then completion, 10-attempt exhaustion and manual recovery, 15-second overall abort during fetch/body reads, delayed timers/replies, automatic read errors, visible stale snapshots during refresh and after refresh failure for every terminal outcome, late refresh cancellation, no routine confirmations and Reset cancellation. Navigation, pagehide/restore, logout, expiry and changed identity cancel checks without automatic resumption. - Repeated current Settings selection is a no-op during submission, between and during result checks, and during completion refresh: requests, timers, visible values/control state, final outcome and socket/writer identity remain intact. - Accounts: admin-only strict eight-user/1,024-byte list, no secret/key fields, confirmed identity-bound role/delete, automatic completion/list refresh, ten-check limit/manual recovery, stale/protected/failure and lost-acknowledgement handling, cancellation, and 401/identity isolation. The original 41 groups remain; the former self-denial assertion now checks enabled self actions and confirmation cancellation. - Second slice: exact create/password JSON and CSRF, 768-byte request ceiling, untrimmed 12–64 printable ASCII passwords including spaces/quotes/backslashes, confirmation and username validation, separate bodyless generation without mutation/list changes, strict 24-character base64url/96-byte generation response. - Generated acknowledgement binds value and operation/target identity; edits, regeneration, target/purpose changes reset it. 60-second lifetime, including delayed timer admission checks; submission/cancel/failure and all lifecycle wipes. Late headers/streamed bodies, concurrent reconnect and newer snapshots are fenced. - Self password/role/delete warnings and POST/poll 401 close both routes without success claims or proactive logout. Safe duplicate/full messages and no routine secret outputs, storage, clipboard writes or history APIs. **57 Node groups total**, plus renderer/HTML/CSP checks, reported PASS by the UI continuation agent (four added beyond its earlier 53-group slice 2 run). ## Automatic result-check budget After a valid POST acknowledgement, the UI waits **1,000 ms** before the first result GET and between completed pending-result checks. It makes **at most 10 GET attempts** and uses an independent **15,000 ms overall deadline**, measured with the monotonic browser clock from acknowledgement. Each attempt first revalidates the session; that time is included in the deadline. There is only one automatic check in flight. Delayed timer callbacks and replies also check this deadline. Expiry actively aborts the in-flight request and releases the UI for manual recovery; late completions cannot update the view. The first limit reached stops automatic checking. A read error also stops it. The budget does not cancel backend work and is not a server execution deadline. **POST is never automatically retried.** Lost acknowledgement requires explicit Check Result recovery; manual checks do not restart automatic polling. Exhausted or cancelled polling never resumes on navigation or bfcache restoration. Every known terminal result, including failure/cancellation, triggers one working snapshot refresh while retaining the operation outcome and any uncertainty warning. Snapshot refresh is outside the auto-check budget and retains the existing 15-second per-request bound (session validation and snapshot GET are separate requests). Settings remain visible but conflicting controls are disabled during work; old snapshots are explicitly stale during pending/uncertain work or a failed refresh. A successful refresh replaces the browser draft. Only Reset asks for confirmation among Serial actions, specifically because it overwrites saved configuration. Every Accounts mutation retains an explicit confirmation. Tests use a deterministic clock and individually fired timer callbacks, including callbacks invoked after cancellation and fetch/body doubles that ignore abort. These deliberately exercise fences beyond normal browser cancellation behavior. ## Integration and known gaps This covers 8D.3 session behavior, the 8D.6 selector, 8D.8 Settings and the 8D.9 Serial UI and both 8D.10 Accounts slices. Operation/generation responses are fetch doubles, not end-to-end execution of `web_serial_settings.c`, `web_account_settings.c`, dispatcher work, credential generation/derivation, serial reconfiguration or NVS persistence. The renderer still relies on its caller to authenticate resources; protected asset failures must be 401, never a redirect to HTML served as JavaScript. No Basic fallback is implemented here. Existing 8D.5 server authorization/protocols are unchanged. These tests model DOM, timers, fetch cancellation and WebSocket events. They do not prove real-browser CSP enforcement, script-loading errors, TLS/HTTPD behavior, actual bfcache policy, cookie expiry, server revocation, or hardware serial byte integrity, actual xterm escape parsing, hidden prompts, or desktop/mobile layout. See [Accounts contracts](../../docs/web_administration.md#accounts-and-authorized-keys) and [acceptance evidence](../../docs/web_administration_acceptance.md). The following are historical 8D.10 slice 2 reports, not current totals: parent build PASS 25.61 s, 95,908 B RAM / 1,694,237 B flash. The generated endpoint is independently optionally registered (23 handlers), with route-agent lifecycle 15 PASS for failure isolation/restart. UI 57/CSP and lifecycle 15 results are agent-attributed, not claims of the parent's additional reruns. The former pending target-signoff gate is superseded by the 8D.22 acceptance; timer runtime measurements remain unreported. No new sanitizer/device execution or target resource reserve is claimed. Browser secret references are dropped and never persisted/logged, but JavaScript cannot securely wipe engine-managed strings.