Skip to content

test(e2e): poll the select and report the page - #13

Merged
arloliu merged 1 commit into
mainfrom
fix/console-choose-option-poll
Aug 30, 2026
Merged

test(e2e): poll the select and report the page#13
arloliu merged 1 commit into
mainfrom
fix/console-choose-option-poll

Conversation

@arloliu

@arloliu arloliu commented Aug 30, 2026

Copy link
Copy Markdown
Owner

The diagnosis this started from does not hold

console-oidc fails intermittently on the current lane with:

scenarios_console_test.go:173: choose Profile = "heap": no select is labelled Profile

The standing explanation was a render race: chooseOption reads once, and the
two waits before it cover something next to the Profile select rather than the
select itself, so a loaded runner has not rendered it yet.

internal/ui/static/app.js rules that out.

  • .panels (:931) renders only once phase is none of booting,
    navigating, signInRequired, error.
  • renderRequest (:1070) is inside .panels, and the Profile <label>
    (:1094) and the input.url <label> (:1140) are in the same
    ${limits ? ... : null} branch (:1092).
  • limits is set once (:434) and never set back to null.

So input.url holding a value entails the Profile label existing in that same
synchronous render. The second wait already covers the select. A slow render
cannot produce this message.

What does produce it

The console empties .panels wholesale, taking every label with it, in two
states:

  • request() (:401): a panel fetch answering 401 under oidc calls
    signIn(), which sets phase to navigating and assigns the login URL.
  • boot() (:369): a failed /v1/whoami sets phase to error.

The browser is then on the issuer's login form, where labels exist and none
holds a <select> — which is the message, verbatim, and it fails fast rather
than timing out, matching the 17.87s the lane recorded.

What this changes

chooseOption now polls the way waitFor polls, and its failure carries the
session report the way every other browser helper's failure already does.

Both readings were run against a scenario that navigates to the login before
choosing:

helper outcome
single-shot fails in 7.70s, no select is labelled Profile, names no page
polling same reason after the action deadline, then a request list ending at the issuer's /auth and /auth/local

The first row is the lane's failure reproduced exactly. The second is why this
is worth landing: the report names where the page went.

What this does not do

Polling does not rescue a page that has navigated away, so #12 may stay red
after this merges.
The poll closes a genuine single-shot read; the report is
what will identify the cause.

The next failure names the fetch that did it.

Only one candidate survives reading fetchJSON (:88): it sets status to 0
and rejected to true when fetch never produces a response, and request()
(:399) branches on res.status === 401. A transport failure therefore never
reaches signIn() — it records a panel error and leaves .panels standing.

That rules out the port-forward resets the lane's log shows inside
console-oidc's window (03:00:44, :45, :47, read: connection reset by peer).
A reset during a panel fetch keeps the page on the console; a reset during
boot()'s whoami leaves phase at error with no retry scheduled, because
only a not_ready answer schedules one, so the scenario would hang at a
waitFor for the full deadline rather than fail fast inside chooseOption.

What is left is a genuine 401 answered to a panel fetch on a load that already
carries a session cookie from a completed login.

Validation

mise run lint, mise run test, mise run check, and semlf --base origin/main all pass. mise run test:e2e ran on the current lane.

chooseOption evaluated its expression once,
and its failure named a missing label and nothing else.
Every other browser helper's failure carries the session report.

The console removes .panels wholesale in two states, and every label goes with it:
a panel fetch answering 401 under oidc calls signIn, which sets phase to "navigating" and assigns the login URL,
and a failed /v1/whoami sets phase to "error".
A browser that has left the console for the issuer's login form was therefore indistinguishable,
in the old message, from a control the page had not finished rendering.

The helper now polls the way waitFor polls.
Every early return in the expression comes before the assignment,
so evaluating it again sets the value at most once.

Both readings were run against a scenario that navigates to the login before choosing.
The single-shot read failed in 7.70s with "no select is labelled Profile" and named no page.
The polling read failed with the same reason after the action deadline,
followed by a request list ending at the issuer's /auth and /auth/local.
Polling does not rescue a page that has navigated away.
The report is what identifies the cause; the poll closes the single-shot read.
@arloliu
arloliu merged commit be8c2c7 into main Aug 30, 2026
6 checks passed
@arloliu
arloliu deleted the fix/console-choose-option-poll branch August 30, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant