Skip to content

iOS CI simulator: XCUIApplication.state reports runningForeground for the runner target while a foreign app is foreground #2696

Description

@thymikee

Finding

On the GitHub-hosted iOS Smoke job's simulator (ios.yml → "Run fixture-backed iOS simulator E2E smoke", iPhone 17 Pro, iOS 26.2), the XCUITest runner's XCUIApplication(bundleIdentifier:).state reports .runningForeground for the runner's own target app while a foreign app is demonstrably holding the screen.

Consequence inside the runner (RunnerTests+Lifecycle.swift targetNeedsActivation → RunnerTests+CommandExecution.swift prepareActiveCommandContext): the activation preflight is skipped, the capture is served from the backgrounded app, and no targetActivation fact is stamped (#2682) — correctly so, given the state it read. The divergence is between that state read and the device's actual foreground app, not in the disclosure path.

Evidence

  • Failed lane run: https://github.com/callstack/agent-device/actions/runs/35460535722/job/105943468492 — smoke-ios-target-activation.test.ts, "no foreground disclosure within 90000ms of the handoff to com.apple.Preferences".
  • Uploaded artifact for that run proves both sides of the contradiction: the pre-handoff screenshot shows the session app rendered (wait label="Gesture lab" had already passed), the post-handoff screenshot shows Settings on screen, and the 31 snapshot -i responses in between each returned a healthy tree for com.callstack.agentdevicelab in ~450 ms with targetActivation absent.
  • The same runner build on a local simulator (iPhone 17 Pro, iOS 26.2) discloses on the first capture after the identical handoff: {"reason":"bundle_changed","priorState":"runningBackground","otherActiveApplicationPid":<pid>}, pid resolvable to com.apple.Preferences/MobileSafari by host ps, and the following capture discloses nothing.
  • Same-shape symptom on the Android lane of the same job family is unrelated (wait timed out for text: Automation lab, a fixture launch issue).

Required behavior

Decide which of these the repo believes, and encode it where the claim lives:

  1. The runner must not trust XCUIApplication.state alone as the foreground oracle when the session's app can be observed to be backgrounded by another signal (e.g. the runner's own activeApplications probe, which already yields soleOtherActiveApplicationPid). Then a CI-simulator capture of a backgrounded app activates and discloses like every other host.
  2. Or the runner documents that target-foreground equality is not observable on CI-hosted simulators, and the live activation lane is declared manual/env-gated with the reason stated at the lane (its current state) so no automatic gate ever waits on that assertion.

Completion conditions

  • A named owner decides 1 or 2 and records it (ADR or runner doc comment beside targetNeedsActivation).
  • If 1: a lane on the CI simulator asserts the capture activates and carries targetActivation, and it passes.
  • If 2: test/integration/smoke-ios-target-activation.test.ts states the divergence at the lane, and no CI job depends on that assertion.

Non-goals

Not a claim that physical devices misreport foreground; the physical lane for #2682 is tracked in .device-evidence/CHECKLIST.md.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions