Long-Run Background E2E
The example app has two background E2E pages:
background-e2eis a short smoke page for API contracts.background-long-runis a device-level page for long-running checks.
The long-run page reads native storage and status. It does not pass from React state alone, so app restarts do not hide missing native delivery.
Android
Run the Android emulator flow:
This flow:
- clears native storage and verifies both last native-record timestamps are absent,
- starts background tracking with
stopOnTerminate: falseandstartOnBoot: true, - registers a geofence,
- establishes an outside foreground baseline, then arms a new proof marker,
- sends the app home and injects inside, then outside locations,
- reopens the page,
- requires the injected inside coordinate followed by the outside coordinate, for both stored locations and location events, after the proof marker,
- verifies
lastLocationAtandlastEventAtare at or after that marker, - verifies the registered Headless task marked an inside event whose native measurement timestamp is after the marker,
- verifies geofence enter and exit events after the marker,
- stops tracking, removes geofences, and polls the native lifecycle briefly before failing cleanup if desired tracking, the actual foreground service, or a geofence remains active.
The prepare and arm registrations omit Android initial triggers, so the required exit cannot be satisfied by the already-outside foreground baseline. Both location payloads are matched to the exact injected coordinates, and the outside row/event must have been stored after the matching inside row/event.
The Headless assertion proves handler delivery without an in-process background listener. It does not terminate the React runtime or claim cold-start delivery.
To include reboot restore on an emulator:
The reboot pass is emulator-only. The wrapper refuses RUN_REBOOT=1 on a
physical Android device before issuing adb reboot, then arms a post-reboot
proof window, waits for sys.boot_completed=1, injects
outside/inside/outside locations after boot, and requires
the same ordered coordinates in both location rows and events using their
native measurement timestamps, plus ordered geofence events. Physical Android
devices need real movement or another trusted location injection setup.
iOS
Run the iOS simulator flow:
This flow:
- clears native storage and verifies both last native-record timestamps are absent,
- starts iOS background/significant-change tracking and records an initial native location timestamp,
- establishes an outside foreground baseline, then arms a new proof marker,
- sends the app home and injects inside, then outside locations,
- reopens the page,
- requires stored geofence enter and exit events after the proof marker,
- proves target-region enter-to-exit callback order with native transition timestamps,
- verifies
lastEventAtis at or after that marker, - stops tracking, removes geofences, and verifies cleanup from native status.
The Simulator does not reliably emit standard or significant-change location rows after the app goes home. The iOS gate therefore uses region transitions, which are native background callbacks, and does not claim that the injected coordinates were retained as location rows. Real-device location delivery remains a manual matrix item.
iOS does not have Android Headless JS or an Android-style boot receiver. The E2E page reports those as platform limits instead of pretending they are supported.
Manual Coordinates
The geofence is centered at:
The deterministic transition path is:
On iOS Simulator, use the Maestro flow for the Home/background step. For a manual run, press Home in Simulator and inject the same path with:
On Android Emulator:
Expected Gaps
Long-run background behavior is platform and device-policy dependent. If the screen reports a failed result, keep it failed and inspect the device state, permissions, battery policy, and native logs. Do not change the E2E page to pass without a stored native event.
The supported guarantees and the full automated/manual matrix are documented in Background Reliability Contract.
