CI: Windows smoke test of the installed app (#19) #30

Merged
jared merged 6 commits from ci-windows-smoke into main 2026-09-30 10:59:38 -04:00
Owner

Closes #19: a Windows smoke test that installs the NSIS bundle on the windows runner and drives the installed app over WebView2's DevTools port with playwright-core.

Run it

From Actions → Windows smoke → Run workflow:

  • no ref: tests the published nightly installer.
  • ref = a branch: builds that branch on the runner, then tests it (about 35 min).

Checks (scripts/windows-smoke.mjs)

  • boots to the login screen;
  • the local server's listening address;
  • microphone allowed for the app;
  • call page on its own origin and isolated from the app (when the build has desktopCallOrigin, #27);
  • Credential Manager round trip (when the build has the secure_session_* commands, #28, restoring whatever was stored);
  • microphone refused to a foreign page (#26).

Features a build doesn't have are reported n/a. Results and screenshots are uploaded as an artifact.

App change: opt-in only

LOTUS_WEBVIEW2_DEBUG_PORT=<port> makes the app add --remote-debugging-port=<port> --use-fake-device-for-media-stream to its WebView2 arguments.

  • Why it's needed: WebView2's own WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS is ignored because the app sets its arguments explicitly (seen on the runner). The VM also has no microphone.
  • Without the variable: the arguments are exactly as before.
  • Validation: only ports ≥ 1024 are accepted; anything else is ignored (unit-tested).

Runner quirks handled

  • Checkout: a second actions/checkout in one job fails on the Windows host runner, so the branch to build goes into a git worktree.
  • Session 0: the app runs in session 0 as a service, and WebView2 works fine there.

Result on the current nightly code (run 2272)

  • pass: app page, login screen, microphone for the app;
  • server listening on ::1 only: confirms the IPv6-only binding that #27 fixes;
  • n/a: call-page isolation and keychain (not in main yet);
  • info: a foreign page still gets the microphone (fixed by #26).

🤖 Generated with Claude Code

https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA

Closes **#19**: a Windows smoke test that installs the NSIS bundle on the `windows` runner and drives the **installed app** over WebView2's DevTools port with playwright-core. ## Run it From **Actions → Windows smoke → Run workflow**: - **no `ref`:** tests the published nightly installer. - **`ref` = a branch:** builds that branch on the runner, then tests it (about 35 min). ## Checks (`scripts/windows-smoke.mjs`) - boots to the login screen; - the local server's listening address; - microphone allowed for the app; - call page on its own origin and isolated from the app (when the build has `desktopCallOrigin`, #27); - Credential Manager round trip (when the build has the `secure_session_*` commands, #28, restoring whatever was stored); - microphone refused to a foreign page (#26). Features a build doesn't have are reported **n/a**. Results and screenshots are uploaded as an artifact. ## App change: opt-in only `LOTUS_WEBVIEW2_DEBUG_PORT=<port>` makes the app add `--remote-debugging-port=<port> --use-fake-device-for-media-stream` to its WebView2 arguments. - **Why it's needed:** WebView2's own `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` is ignored because the app sets its arguments explicitly (seen on the runner). The VM also has no microphone. - **Without the variable:** the arguments are exactly as before. - **Validation:** only ports ≥ 1024 are accepted; anything else is ignored (unit-tested). ## Runner quirks handled - **Checkout:** a second `actions/checkout` in one job fails on the Windows host runner, so the branch to build goes into a `git worktree`. - **Session 0:** the app runs in session 0 as a service, and WebView2 works fine there. ## Result on the current nightly code (run 2272) - **pass:** app page, login screen, microphone for the app; - **server listening on `::1` only:** confirms the IPv6-only binding that #27 fixes; - **n/a:** call-page isolation and keychain (not in `main` yet); - **info:** a foreign page still gets the microphone (fixed by #26). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared added 6 commits 2026-09-30 10:59:36 -04:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
WebView2's WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS is ignored because the app
sets its browser arguments explicitly (seen on the runner: the WebView2
command line had only the app's arguments). The app now appends
--remote-debugging-port only when LOTUS_WEBVIEW2_DEBUG_PORT holds a valid
port (>= 1024); otherwise the arguments are exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
A second actions/checkout in the same job fails on the Windows host runner
(Access is denied on the cached action's pack file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
The CI VM has no microphone (getUserMedia → NotFoundError). With
LOTUS_WEBVIEW2_DEBUG_PORT set the app also passes
--use-fake-device-for-media-stream; permission requests still go through
the real PermissionRequested handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
jared merged commit 61ab464b45 into main 2026-09-30 10:59:38 -04:00
Sign in to join this conversation.