Simulator Audio E2E
Verify real native recording and playback on virtual devices without touching a connected physical phone. Treat builds, UI automation, callback state, and log inspection as separate evidence.
Safety Boundary
- Require explicit permission in the current request before recording. State
that
sound.examplerecords a short non-sensitive clip through the host or emulator microphone. A request to run audio E2E is sufficient permission. - Select a concrete iOS Simulator UDID or Android serial beginning with
emulator-. Never allow an implicit destination when physical devices are connected. - Do not upload, transcribe, or retain the recording. Keep only screenshots, JUnit output, and redacted logs needed to diagnose the run.
- Do not claim Bluetooth, interruptions, backgrounding, audio focus, route changes, or audible fidelity from this lane; those require targeted tests and can require a physical device.
Preflight
- Read
AGENTS.md,.claude/commands/e2e-tests.md, the changed source, andreferences/flow-contract.md. - Preserve
git status --short --branch; never clean unrelated work. - Run
scripts/preflight.shand select one available virtual destination. - Run
yarn install --immutable,yarn prepare,yarn typecheck,yarn lint, andyarn test --runInBand. - Confirm
sound.exampledeclares microphone permission and no Metro process conflict exists on port 8081.
Build And Install
For iOS, boot the selected Simulator and build the Debug app for that exact
UDID. Install the produced .app with xcrun simctl install. For Android,
start the selected AVD, wait for boot completion, and build/install Debug with
ANDROID_SERIAL set to the selected emulator serial.
Start Metro from the repository root with yarn start --reset-cache. Keep its
session and save errors separately from native device logs. Grant microphone
permission to sound.example on the selected virtual device before the flow.
Run The Runtime Contract
Run the repository flow through the guarded helper:
.codex/skills/simulator-audio-e2e/scripts/run-maestro.sh ios <simulator-udid>
.codex/skills/simulator-audio-e2e/scripts/run-maestro.sh android <emulator-serial>
The flow must prove both direct and hook APIs can:
- Start recording and emit increasing record time.
- Pause and resume the recorder without a crash or duplicate instance.
- Stop and expose a playable path.
- Start, pause, resume, and stop playback with matching UI state.
- Complete with no visible error alert.
Do not weaken selectors or remove state assertions to make a failed flow pass. Fix the product or explain a platform limitation.
Inspect Native Evidence
After Maestro, inspect simulator logs for the current app process only:
- iOS:
xcrun simctl spawn <udid> log showwith a short time bound and asound.examplepredicate. - Android:
adb -s <serial> logcat --pid=$(adb -s <serial> shell pidof sound.example)captured around the run.
Fail the runtime lane for uncaught exceptions, native crashes, rejected promises, MediaRecorder/AVAudio errors, or leaked-resource warnings attributable to the tested flow. Ignore unrelated host and OS noise with an explanation.
Report And Cleanup
Report BUILD PASS/FAIL and RUNTIME PASS/FAIL/BLOCKED per platform. Include
the exact UDID/serial, OS/API level, RN and Nitro versions, flow path, callback
states observed, JUnit result, and relevant redacted log findings. List every
untested device-only row.
Terminate only Metro/emulators started by this run. Leave user-owned devices
and processes intact. Use the guarded runner's mandatory cleanup and verify
that no recording remains in the selected app container or e2e/artifacts/.
Report RUNTIME BLOCKED if cleanup fails or cannot be confirmed. JUnit,
screenshots, debug output, and redacted logs under e2e/artifacts/ remain
disposable and ignored by Git.