Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

iOS: resolveRunnerWindow fails when an unused trailing window disappears

Aberta Para iniciantes
#2,995 0 comentários 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
2/5
Tempo estimado
1-3 horas
Facilidade para iniciantes
84/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
ios, swift
Domínio
mobile, testing-qa

Direção de pesquisa

Comece em apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift, em resolveRunnerWindow(app:), e depois execute a reprodução nativa vinculada com ./reproduce.sh . Considera-se concluído quando o resolver retorna a primeira janela utilizável e não vazia sem ler janelas finais desnecessárias, preserva o fallback de app.frame e a reprodução passa sem a falha stale-element.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

ready-for-agent

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.

Sanitized native test output:

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.

Linguagem predominante
TypeScript
Estrelas
4.8k
Forks
315
Merge médio
11h 25min
PRs com merge (30d)
545

Preparar o ambiente

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de callstack/agent-device

Todas as issues de callstack/agent-device

Issues semelhantes

Mais issues de TypeScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.