iOS: resolveRunnerWindow fails when an unused trailing window disappears
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 84/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- ios, swift
- 領域
- mobile, testing-qa
調査の方向性
apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift の resolveRunnerWindow(app:) から開始し、続いて ./reproduce.sh でリンクされたネイティブ再現を実行します。完了条件は、resolver が不要な後続ウィンドウを読み取らずに最初の使用可能な空でないウィンドウを返し、app.frame のフォールバックを維持し、stale-element エラーなしで再現が成功することです。
索引モデルが issue の本文から書いたものです。
説明
Bug
resolveRunnerWindow(app:) eagerly reads the frame of every app window before returning the first usable one. If an unused trailing window disappears between its exists check and its frame read, XCTest records a failure even though the first/main window is still available.
Affected implementation: Agent Device 0.21.15; also still present in upstream source at 3660c7fa.
Small native reproduction
Public repo: https://github.com/wcastand/agent-device-window-race-repro
Verified commit: b1baf97
The fixture is a small UIKit app with a persistent main UIWindow. It shows a second window every 5 seconds, then hides/releases it after 600 ms. Two XCUITests repeatedly call the extracted original resolver or the proposed short-circuit version using real XCUIApplication/XCUIElement objects. No Expo/React Native, backend, account, mocked failures, or hooks/delays inside the resolver are involved.
git clone https://github.com/wcastand/agent-device-window-race-repro.git
cd agent-device-window-race-repro
./reproduce.sh <iOS-simulator-UDID>
The Xcode project is included; no package install or signing team is needed. Each loop is bounded to 60 seconds / 6,000 calls. This is a natural timing race, so a run can miss it. The script returns success only if the original produces the specific stale-element failure and the patched test passes; setup errors and missed races are rejected.
Observed vs expected
On Xcode 27.0 (27A266a), macOS 27.0 arm64, iPhone 18 Pro simulator / iOS 27.0, the script exited 0:
- Original: failed on call 332 (zero-based iteration 331).
- Patched: completed 3,843 calls over one minute, no failures.
- The original failure was also observed separately on iPhone 17 / iOS 26.5.
Checking existence of `Window (Element at index 1)`
Find the Window (Element at index 1)
Find the Window (Element at index 1) (retry 1)
Find the Window (Element at index 1) (retry 2)
Failed to get matching snapshot: No matches found for Element at index 1 from input {(
Window (Main)
)}
Expected: return the first usable window without resolving later windows that cannot affect the result. The repro isolates the native resolver; it does not run the full CLI/daemon or reproduce a keyboard-specific lifecycle.
Proposed patch
Downloadable patch, checked against the upstream source path:
--- a/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift
+++ b/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift
@@ -226,12 +226,13 @@
/// display can never name a different window than the one the reference frame was measured on.
func resolveRunnerWindow(app: XCUIApplication) -> (window: XCUIElement?, frame: CGRect) {
let windows = app.windows.allElementsBoundByIndex
- var frames: [CGRect?] = []
- for window in windows {
- frames.append(window.exists ? window.frame : nil)
- }
- if let index = Self.firstUsableWindowIndex(frames: frames) {
- return (windows[index], frames[index] ?? .zero)
+ // Stop at the first usable window. Later keyboard/overlay windows can disappear
+ // between exists and frame, recording an XCTest failure before a valid tap.
+ for window in windows where window.exists {
+ let frame = window.frame
+ if !frame.isEmpty {
+ return (window, frame)
+ }
}
return (nil, app.frame)
}
This preserves first-non-empty-window selection and the app.frame fallback. It avoids unnecessary trailing-window reads; it does not make exists + frame atomic or claim to fix disappearance of the selected window.
- 主要言語
- TypeScript
- スター
- 4.7k
- フォーク
- 304
- 平均マージ
- 11時間 31分
- マージ済み PR(30日)
- 513
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
callstack/agent-device のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
callstack/agent-device#2998 ·
メンテナーはふだん 1 日以内に返信
-
Proxy lease refuses every iOS install/open: connection platform 'ios' compared with internal 'apple'オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
callstack/agent-device#2962 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
callstack/agent-device#1869 ·
メンテナーはふだん 1 日以内に返信
-
Maestro `eraseText` fails on real Android devices: `test` and `replay` cannot opt in to the test IMEオープン
難易度 3/5 1〜2日 初心者へのやさしさ 74/100
callstack/agent-device#2997 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
callstack/agent-device#2996 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
callstack/agent-device の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
rohitg00/agentmemory#1428 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
boxlite-ai/boxlite#1729 ·
メンテナーはふだん 1 日以内に返信
-
detectors enhancement good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
SM260845/readme-gen#1 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
angular/angularfire#3774 ·
メンテナーはふだん 2 日以内に返信