Skip to content

fix(selectors): resolve a wrapper chain's control for uniqueness reads - #2501

Merged
thymikee merged 1 commit into
mainfrom
fix/wait-wrapper-chain-2498
Sep 12, 2026
Merged

thymikee merged 1 commit into
mainfrom
fix/wait-wrapper-chain-2498

Conversation

@thymikee

@thymikee thymikee commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

Summary

wait already succeeds on main; what still fails on the reported screen is every read that insists on one match. A SwiftUI toolbar wrapper and its button share one identifier, a regular iOS snapshot omits unverified hittability, so the ladder that relates a wrapper to its control cannot fire: press taps the button while is visible and get attrs report Selector did not match and screenshot --crop-on refuses with "matched 2 nodes". #2482 collapsed that chain for mutating resolution only.

This exports the collapse (resolveUnverifiedWrapperControl) and applies it at the read door: readUnique and cropTarget resolve the control instead of refusing. Rows that resolve before a refusal are untouched, and a candidate set the rule does not recognise as one control - a cell and the button inside it, matches in distinct subtrees - still refuses.

Replay was the second door. Verification re-resolves a recorded selector under the same row's refusal rules, so a step whose screen had not changed verified as IDENTITY_MISMATCH on its first replay; it now names the collapsed control, the node dispatch acted on.

ADR 0011 is amended: its 2026-08-07 clause still described get/is/wait as runner querySelector reads. 11 files, +431/-31.

Closes #2498

Validation

  • pnpm check:affected --run at bab4435 (rebased onto origin/main d80fb35): 563 files / 4084 tests pass. An earlier run at the pre-rebase commit had one failure under concurrent load from other worktrees on this host and passed on rerun.
  • Live iOS Simulator (iOS 26.2) with a SwiftUI fixture whose toolbar wrapper shares its button's identifier. Before: is visible and get attrs selector-not-matched, screenshot --crop-on matched 2 nodes. After: is visible passes, get attrs/get text resolve the Button, crop is 35x36, wait and press unchanged, is hidden fails with actual={"visible":true}, find … list still lists both nodes, and a distinct-subtree duplicate still refuses.
  • Mutation-checked: disabling the collapse or its ancestry-chain guard fails the new tests.
  • Unresolved scope: on XCTest-backed captures where the wrapper reports hittable: true, reads and acts both refuse. That is fix(selectors): collapse an unverified-hittability wrapper chain to its control #2482's existing boundary and is unchanged here.

A control reported through its own accessibility wrapper answers a selector
twice, and a regular iOS snapshot omits unverified hittability, so the ladder
that relates a wrapper to its control cannot fire. #2482 collapsed that chain for
mutating resolution only: `press` tapped the toolbar button while `is visible`
and `get attrs` reported "Selector did not match" and `screenshot --crop-on`
refused the same screen as two nodes.

Export the collapse beside the classification that asks for it and apply it where
a read row's answer was a refusal. Rows that resolve before any refusal are
untouched, and a candidate set the rule does not recognize as one control - a
cell and the button inside it, or matches in distinct subtrees - still refuses.

Replay verifies a recorded target by resolving its recorded selector again under
the same row's refusal rules, so a step whose screen had not changed verified as
an identity mismatch on its first replay. Verification names the collapsed control
too, which is the node dispatch acted on and the node the recorded identity
carries.
@github-actions

github-actions Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.49 MB 4.49 MB +334 B
Package (unpacked) 4.49 MB 4.49 MB +334 B
Package (download) 1.32 MB 1.32 MB +145 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.3 ms 27.0 ms +0.7 ms
CLI --help 72.5 ms 72.9 ms +0.5 ms

@thymikee
thymikee force-pushed the fix/wait-wrapper-chain-2498 branch from 16b925b to bab4435 Compare September 11, 2026 16:50
@thymikee

thymikee commented Sep 11, 2026 •

Copy link
Copy Markdown
Member Author

No findings at bab4435. Uniqueness reads and replay now resolve the same wrapper control while distinct subtrees and genuinely separate controls still refuse; the reported live simulator run covers is/get/crop and the regression tests cover replay. Ready for human review and merge; current-head checks pass.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 11, 2026
@thymikee
thymikee merged commit de8703b into main Sep 12, 2026
18 checks passed
@thymikee
thymikee deleted the fix/wait-wrapper-chain-2498 branch September 12, 2026 05:44
@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-12 05:45 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wait still refuses an unverified-hittability wrapper chain (native runner path)

1 participant