test(android-e2e): reveal automation canaries by visibility probe - #2370
test(android-e2e): reveal automation canaries by visibility probe#2370thymikee wants to merge 3 commits into
Conversation
`smoke:automation-system` revealed its canaries with a single blind `scroll down <amount>` and then acted on them immediately. `scroll` is a gesture, not an offset — the command's own contract says "app scroll physics determine the final content offset" — so one amount cannot guarantee the target is on screen, least of all right after the landscape/portrait round-trip has relaid the list out. Both open Android smoke failures sit on that seam: - step 34 `press id="automation-press"` → `selector_not_found`, right after `scroll down 0.7`. Reproduced on #2360 and #2361 (disjoint diffs), on `main` at bd08e6e, and on #2356 at the identical line, so the orientation fix does not cover it. - the post-alert canary after `scroll down 1`, which #2356 records as still open. The iOS scenario already reveals the same canaries correctly, probing `is visible` and scrolling again until the element is on screen. That policy was iOS-only; this moves it to the shared live-device layer as `createVisibilityScroll` and gives the Android scenario the same reveal. Its unit test moves with it. No production code changes, and the press and diff assertions still have to pass against a real element — the scroll budget is bounded and a genuinely absent canary still fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz
Size Report
Startup median (7 runs, lower is better):
|
…vidence The first CI run of the visibility search refuted the scroll-position hypothesis it was built on. `id="automation-press"` failed with `selector_not_found` after four probes and three 0.75-viewport scrolls — the element was not in the accessibility tree at all, not merely off screen. Two consequences, both fixed here. The search only scrolls DOWN, so a canary the rotation round-trip left ABOVE the viewport is unreachable no matter how many attempts it spends. Both Android reveals now anchor with `scroll top` first, the idiom the scenario already uses after system UI perturbs the route, so the search starts from a known position and the target can only be below it. The probes run with `allowFailure`, so the budget-exhausted `assert.fail` never reached the harness's failed-step evidence capture: the Android artifact fell from 143,676 to 12,086 bytes and lost the screenshot, snapshot and device facts that name what was on screen instead. The search now spends one final probe as a real step before failing, which restores all three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz
The first run refuted the hypothesis this PR was built onAndroid smoke on
Two things follow, both pushed in 1. The search only scrolls down. A canary the rotation round-trip left above the viewport is unreachable however many attempts it spends. Both Android reveals now anchor with 2. I regressed the evidence, and that is on me. The probes run with So the next Android failure, if there is one, arrives with a snapshot of what was actually on screen and the Validated at Generated by Claude Code |
|
Superseded by #2369, which merged as #2369 reaches the same conclusion and covers more ground: Worth recording from this PR's one CI run, since it cost an emulator cycle to learn:
Generated by Claude Code |
|
The Android reveal fix already landed in #2369, which also checks the input results and alert canaries. This PR now conflicts with that change. Its shared helper also scrolls after any non-stalled failure, losing the typed error check now on main; transport or permission failures must not be treated as an off-screen element. I suggest closing this as superseded. Any later helper extraction should preserve all current visibility checks and fail immediately on unexpected errors. |
Summary
smoke:automation-systemrevealed its canaries with a single blindscroll down <amount>and then acted on them immediately.scrollis a gesture, not an offset — the command's own metadata says "app scroll physics determine the final content offset" — so one amount cannot guarantee the target is on screen, least of all right after the landscape/portrait round-trip has relaid the list out.Both open Android smoke failures sit on that seam:
scroll down 0.7press id="automation-press"selector_not_foundscroll down 1snapshot -ifor the diff baselineOpen automation alertStep 34 is not the orientation family. It reproduces on #2360 and #2361 (disjoint diffs), on
mainatbd08e6e, and — decisively — on #2356 at the identical linelive-automation-scenario.ts:130, so the orientation fix does not cover it. #2359 records the device as being in portrait at that failure, which rules out the "still landscape" reading. The post-alert one is the family #2356 lists under "What this does not explain".The iOS scenario already does this correctly — it probes
is visibleand scrolls again until the element is on screen, with the comment "an offscreen node can exist in the accessibility tree, so a successfulwait <selector>is not sufficient evidence to skip scrolling." That policy was iOS-only. This moves it to the shared live-device layer ascreateVisibilityScrolland gives the Android scenario the same reveal; the unit test moves with it.No production code changes. This is not a suppression: the scroll budget stays bounded at 4 attempts, and the press and diff assertions still have to pass against a real element, so a genuinely absent canary still fails.
Validation
At
120d8ad:pnpm check:toolingpasses (format, lint, typecheck, layering, depgraph, gate-manifest, production-exports, tmpdir-leaks, xctest-selection, mcp-metadata, build, bundle-owner-files, package).pnpm check:fallow— no issues in the 5 changed files.pnpm check:affected --run— all runnable checks passed. The moved unit test passes undernode --test. No baseline,.fallowrcor gate-manifest edits were needed.Not validated on a device from here — this container has no emulator, so the Android lane in CI on this PR is the first real exercise of the change. If step 34 still fails after it, the visibility probes now name which canary was off screen and after how many scrolls, which the blind scroll never did.
Refs #2350, #2356, #2359. Unblocks #2360 and #2361, whose only red check is this scenario.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz
Generated by Claude Code