Skip to content

fix(ios): find a popover dismiss region in one query instead of reading every element - #2901

Merged
thymikee merged 3 commits into
mainfrom
fix/ios-webview-wait-runner-busy-2491
Sep 24, 2026
Merged

thymikee merged 3 commits into
mainfrom
fix/ios-webview-wait-runner-busy-2491

Conversation

@thymikee

@thymikee thymikee commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes smoke:webview-remote-content → wait for the WebView page to expose its link (#2491 row 1, run 35982745770). A runner restart timed out the landmark wait, so the scenario sent alert get. With no alert up, the runner then read every descendant of every window to find a popover dismiss region. Each element cost one XCTest round trip, and each element the loading page removed cost a 4 s retry. After the 10 s watchdog the runner stayed busy 38 s; every wait poll spent the #2863 resend window (~6 s) on RUNNER_BUSY.

Now one predicate query per window set finds the region. Its query, the alert-title filter, and alert observation share one marker pattern. Three iOS XCTests on a 500-label fixture check it: an absent alert resolves in under half the alert budget; a trimmed, mixed-case marker on a button resolves; a window that is itself the marker resolves. Complements #2897.

Validation

Head ee75e9b9ae: pnpm check:affected --run passed (exit 0).

  • Mutation (main's firstDismissPopupWindow restored): the absent test fails at 282 s against its 5 s bound (500 labels). With the fix: 0.37–0.39 s over 3 runs.
  • Live (iOS 26.2 sim), WebView lab → alert get → page wait:
    • main: MAIN_THREAD_TIMEOUT at 10.2 s; the wait failed with wait_capture_stalled after 20 s; the runner stayed busy 21.9 s.
    • fix: 10/10 ALERT_NOT_FOUND in 0.18–1.2 s; the wait passed in <0.7 s.
  • The scenario passed 10/10.

Residual: the runner restart is a separate signature.

@thymikee

Copy link
Copy Markdown
Member Author

Applied the review notes at ee75e9b. (1) One marker pattern now serves the query, the title filter, and alert observation. (2) The fixture has 500 labels: without the fix the absent-alert test takes 282 s against its 5 s cap; with it, 0.37–0.39 s. A new test covers a window that is itself the marker. That test showed XCTest's containing also matches the window itself, so the separate matching query was redundant and is gone; the test now guards that behavior. check:affected passed (exit 0).

@thymikee
thymikee force-pushed the fix/ios-webview-wait-runner-busy-2491 branch from ee75e9b to 19584de Compare September 24, 2026 13:54
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.80 MB 4.81 MB +2.1 kB
Package (unpacked) 4.80 MB 4.81 MB +2.1 kB
Package (download) 1.44 MB 1.44 MB +205 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.2 ms 28.2 ms +1.0 ms
CLI --help 80.7 ms 85.9 ms +5.2 ms

@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto main at cb62ac2136. Only the CHANGELOG conflicted; this PR's diff adds only its own entry. pnpm check:affected --run passed (exit 0).

@thymikee
thymikee force-pushed the fix/ios-webview-wait-runner-busy-2491 branch from 19584de to cb62ac2 Compare September 24, 2026 14:04
@thymikee
thymikee added this pull request to stack #2914 September 24, 2026 14:44
@thymikee

Copy link
Copy Markdown
Member Author

At cb62ac2, the fix direction looks right, but the regression test meant to prove it likely can't. In RunnerTests+AlertTests.swift, testAlertResolutionFindsAWindowThatIsItselfTheDismissPopupMarker (https://github.com/callstack/agent-device/blob/cb62ac2/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/UnitTests/RunnerTests+AlertTests.swift#L177) launches a fixture where only the window's own accessibilityIdentifier is "Dismiss popup" and the sole on-screen button is identifier "agent-device-close-popover", which doesn't match the marker pattern. Given that fixture, resolveAlert should return nil and the XCTUnwrap should throw, so this test looks like it currently fails against the PR's own implementation. If that's right, the case it's meant to cover — a window that is itself the marker — isn't actually shown to work, and if CI is misconfigured or this test gets skipped, the fix could ship broken.

Does firstDismissPopupWindow gain a query that matches the window itself, or only one that matches a descendant containing the marker? Apple's XCUIElementQuery.h documents containingPredicate: as matching descendants only, not self, so the self-matching case needs its own query next to containing(). I did not build or run the iOS target to check this; the live-sim validation in the PR covered the absent-alert path, not this marker-on-window-itself path.

CI is still pending. The only checks in question sit inside the single Smoke Tests job, which runs both the targeted iOS runner XCTest regressions (this PR's own gates commit adds -only-testing entries for the three new alert-resolution unit tests here) and the fixture-backed E2E smoke that covers the #2491 scenario this PR fixes, so the job is queued rather than failed and no log yet confirms or refutes the test failure above.

There are no known conflicts.

Before merge, someone needs to run testAlertResolutionFindsAWindowThatIsItselfTheDismissPopupMarker, either locally or by reading the completed Smoke Tests log, and confirm it passes; per the containingPredicate: documentation it should not, which would mean firstDismissPopupWindow needs a self-matching query added alongside containing().

…ng every element

alert get/accept/dismiss with no alert walked every descendant of every window,
one XCTest round trip per element plus a retry cycle for each element that
vanished mid-walk. On the WebView lab it outran the 10 s alert budget and kept
the runner main thread busy past 30 s, so the following wait saw RUNNER_BUSY on
every poll until its deadline (smoke:webview-remote-content, #2491).
…ded-screen margin

The query predicate, the alert-title filter, and the post-activation observation
now all read one pattern. The crowded fixture grows to 500 labels so the absent
alert test fails by a wide margin without the query (282 s against a 5 s cap),
and a new test covers a window that is itself the marker, which the single
containing query also returns.
@thymikee
thymikee force-pushed the fix/ios-webview-wait-runner-busy-2491 branch from cb62ac2 to 1416066 Compare September 24, 2026 15:19
@thymikee

Copy link
Copy Markdown
Member Author

Correction to my earlier comment: the Smoke run on cb62ac2 shows testAlertResolutionFindsAWindowThatIsItselfTheDismissPopupMarker passed (17.4 s), so the window-itself case works. That finding does not apply.

The one failing test in that run was testAbandonedTreeCaptureSkipsQuerySweepAndHonorsWarmupExemption. The private-AX lookup could not match the app, so the result was sparse instead of recovered. This PR does not touch that path, the test passed on main at dbc08a4 and 0192348, and #2908 failed it the same way. It looks like a flake.

I rebased this PR onto main at 1416066 (no conflicts, and main did not change the runner or ios.yml since the old base). #2902 is rebased on top of it. CI is running again on both.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 24, 2026

@thymikee thymikee left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 1416066, including the later gate-selection commit. No inline findings. The predicate fixes the unbounded descendant walk, the shared marker pattern keeps the query/title/observation predicates from drifting, and the 500-label mutation plus live 10/10 evidence pin the original pathology. The window-self test is valuable because the containing behavior is otherwise easy to misread as a child-only match.

@thymikee
thymikee merged commit bb5089a into main Sep 24, 2026
18 checks passed
@thymikee
thymikee deleted the fix/ios-webview-wait-runner-busy-2491 branch September 24, 2026 15:24
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-24 15:27 UTC

@thymikee

Copy link
Copy Markdown
Member Author

Reviewed the delta since cb62ac2 at 1416066. The one-query search for the popover dismiss region looks correct, and nothing from the earlier review is still open.

The earlier CI failure at cb62ac2 (testAbandonedTreeCaptureSkipsQuerySweepAndHonorsWarmupExemption) is in a file this PR does not touch, so it looks unrelated. The checks on 1416066 were still queued or running at review time; please let the iOS Smoke Tests run on this head finish green before merging.

@thymikee

Copy link
Copy Markdown
Member Author

Re the window-marker concern: I ran testAlertResolutionFindsAWindowThatIsItselfTheDismissPopupMarker from exact head 1416066ae761 on a fresh iPhone 17 Pro simulator (iOS 26.2, Xcode 26.2). It passed: 1 test, 0 failures. The XCTest trace shows app.windows.containing(...) returned a window; the assertions then verified that window's identifier was Dismiss popup and its button's identifier was the non-marker agent-device-close-popover.

I also changed only the fixture window identifier to Not the marker, rebuilt, and reran the same test. It failed at XCTUnwrap(resolveAlert(...)). I reverted that temporary mutation; there is no PR code change. This proves the test is sensitive to the window marker on the tested iOS runtime. The header describes containingPredicate: in terms of descendants, so I cannot infer from the trace whether XCTest includes self or UIKit projects the window identifier onto a descendant. Either way, this fixture is resolved through the production query on iOS 26.2. Exact-head CI is still queued and will run the targeted XCTest as well.

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.

1 participant