You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Poll simctl bootstatus with migration logging before app install, raise pre-boot and job timeouts, start simulator artifacts after boot, and document iOS simulator reliability in OKF.
Knowledge for GitHub Actions workflows in this repository: how jobs are structured, platform-specific reliability concerns, and how to debug failures from CI artifacts.
4
+
5
+
## Platforms
6
+
7
+
*[iOS](ios.md) — simulator boot reliability, logging, and troubleshooting
This document covers the **Testing E2E iOS** workflow (`.github/workflows/tests_e2e_ios.yml`) and scripts it uses under `.github/workflows/scripts/`.
4
+
5
+
## Simulator reliability
6
+
7
+
### Problem
8
+
9
+
On GitHub Actions macOS runners (currently `macos-26` with `XCODE_VERSION: latest-stable`), booting an iOS Simulator for Detox is not instantaneous. A simulator can report `Booted` in `simctl list` while it is still unusable:
10
+
11
+
1.**First-boot data migration** — `com.apple.datamigrator` can run for several minutes on a fresh simulator (observed ~4+ minutes on iOS 26.5). SpringBoard and app install are not reliable until migration finishes.
12
+
2.**Ambiguous device names** — runners often have multiple simulators with the same marketing name (e.g. several `iPhone 17` entries across iOS runtimes). We intentionally use the **device name** from `tests/.detoxrc.js`, not a pinned UDID, so we do not churn workflow YAML when runner images change.
13
+
3.**`Booted` ≠ ready for testing** — installing or launching the app during migration can block or fail; Detox may time out while the simulator is still migrating.
14
+
15
+
### What we do
16
+
17
+
**Pre-boot step** (`.github/workflows/scripts/boot-simulator.sh`), run via `nick-fields/retry` before Detox:
18
+
19
+
| Phase | What happens |
20
+
|--------|----------------|
21
+
|`resolve_device`| Read simulator name from `tests/.detoxrc.js` (e.g. `iPhone 17`) |
22
+
|`shutdown_existing`| Kill `Simulator.app` and `simctl shutdown` the target |
23
+
|`boot_command`|`xcrun simctl boot <name>`|
24
+
|`wait_for_full_boot`| Poll every 20s (up to 11 min) until `simctl bootstatus` reports ready |
25
+
|`install_app`|`simctl install` the built `testing.app`**only after** bootstatus succeeds |
26
+
27
+
During `wait_for_full_boot`, the script logs to the **GitHub Actions step log** with the `[boot-status]` prefix:
28
+
29
+
- Whether `simctl list` shows the device as `Booted`
30
+
-**Data migration** snippets from `xcrun simctl bootstatus <name> -d` (probed with a short timeout so the step keeps printing progress instead of looking hung)
31
+
- Elapsed time per poll
32
+
33
+
We wait for **`simctl bootstatus`** (full boot completion), not merely the `Booted` line in `simctl list`.
34
+
35
+
**Timeouts** (tuned for first-boot migration on latest iOS):
36
+
37
+
| Setting | Value | Notes |
38
+
|---------|-------|--------|
39
+
| Pre-Boot retry step | 12 min × 3 attempts | was 5 min |
40
+
| Job `timeout-minutes`| 87 | +7 min vs previous 80 |
41
+
| Detox test step | 62 min | +7 min vs previous 55 |
42
+
43
+
Simulator **caching** of device data is intentionally deferred — caching a bad migration state would require cache invalidation policy.
44
+
45
+
### Simulator logging and video (troubleshooting)
46
+
47
+
Artifacts are uploaded on every run (`if: always()`), even when tests fail.
|`simulator-<buildmode>-<iteration>_video`|`xcrun simctl io booted recordVideo` → `simulator.mp4`| Visual confirmation of UI state |
53
+
|`screenrecording-<buildmode>-<iteration>`|`screencapture` of the Mac desktop | Includes Simulator.app window |
54
+
|`screenrecording-setup-<buildmode>-<iteration>.mov`| Guidepup setup recording | Very early environment setup |
55
+
|`emulator-scripts-logs-<buildmode>-<iteration>`|`.github/workflows/scripts/*.log`| Script output if redirected |
56
+
57
+
**When to use which log**
58
+
59
+
-**Boot / migration / “simulator won’t start”** — read the **Pre-Boot Simulator** step log in GitHub Actions first. Look for `[boot-status]` lines and `bootstatus -d` migration output. That captures first-boot migration even though `simulator.log` starts only after pre-boot succeeds.
60
+
-**Detox / app / test failures** — download `simulator-*_log` and search for `com.invertase.testing`, `SpringBoard`, `xctest`, or `Detox`.
61
+
-**UI regressions** — `simulator-*_video` or `screenrecording-*`.
62
+
63
+
**Downloading artifacts**
64
+
65
+
From the workflow run page: **Artifacts** section at the bottom, or:
66
+
67
+
```bash
68
+
gh run download <run-id> -n simulator-debug-0_log
69
+
```
70
+
71
+
**Analyzing `simulator.log`**
72
+
73
+
The file is unified logging from the booted simulator (compact style). Useful patterns:
rg -i "test daemon not ready|xctest" simulator.log
79
+
```
80
+
81
+
A long gap with only `com.apple.datamigrator` activity and no `com.invertase.testing` usually means the simulator was still in first-boot migration or pre-boot had not finished installing the app yet.
82
+
83
+
### Detox configuration
84
+
85
+
Device type is defined in `tests/.detoxrc.js` (`devices.simulator.device.type`). The boot script and Detox both use this name. CI does not hard-code a UDID.
86
+
87
+
### Operational notes
88
+
89
+
-**Release vs debug** — matrix runs both; each has separate artifacts (`debug` / `release` in the artifact name).
90
+
-**Retry** — Pre-Boot retries up to 3 times with 60s between attempts (clean shutdown + boot each time).
91
+
-**Do not boot the simulator only inside Detox** — historical races where the testee never sent “ready” to the Detox proxy; pre-boot remains mandatory.
0 commit comments