5.0 KiB
Testing Proximity Without an iPhone
This document explains how to run and test the entire app using only the iOS Simulator — no physical iPhone required for the core interaction loop.
The strategy in one sentence
The interaction logic is fully testable in the simulator. Only the physical sensors (UWB, NFC) need real hardware.
We achieved this by abstracting all hardware behind protocols
(ProximityAdapterProtocols) and injecting a SimulatedAdapter in DEBUG
builds. PresenceEngine talks to the protocols, never to hardware directly,
so it behaves identically whether it's sensing real UWB or receiving simulated
encounters.
What you can test without any device
| Capability | Simulator | Real iPhone |
|---|---|---|
| SwiftUI UI, navigation, chat | ✅ | ✅ |
| Auth (Apple / Google) | ✅ (Apple needs bundle config) | ✅ |
| Backend + WebSocket live loop | ✅ | ✅ |
| Full reveal flow (wave → mutual → chat) | ✅ | ✅ |
| Simulated encounters / crowd | ✅ | ✅ |
| Core Location / iBeacon | ⚠️ simulated location | ✅ |
| BLE broadcast/discovery | ⚠️ limited | ✅ |
| UWB (Nearby Interaction) | ❌ | ✅ |
| NFC tap | ❌ | ✅ |
Quick start (simulator)
1. Run the reference backend
The Swift client in DEBUG mode points at a local server. Start it:
cd server
npm install
npm run dev # runs on http://localhost:8080
2. Run the app in the Simulator
- Open
Proximity.xcodeprojin Xcode. - Select an iPhone simulator (any model).
- Build & run (⌘R).
In DEBUG builds, AppState automatically:
- Points
APIClientathttp://localhost:8080 - Injects
SimulatedAdapterinto thePresenceEngine
3. Exercise the interaction loop
- Sign in (Apple or Google — the reference server accepts any token).
- Tap the big "I'm Here" toggle to go present.
- Open the debug menu (hammer icon, top-left).
- Tap "Simulate someone walking by" — a silhouette appears in the feed.
- Tap Wave on the silhouette.
- To complete the reveal, simulate the other side waving back — in real life the server pushes this over the socket. For a fully local test, you can drive the mutual wave via the debug tools or a second client.
4. Test the reveal moment
When both sides wave, RevealView presents full-screen — two avatars
converging. Tap "Say hello" to open the E2E chat.
Driving the simulation
The debug menu (DebugMenu) provides:
- Simulate someone walking by — one UWB encounter.
- Simulate a crowd (20 people) — a burst of silhouettes.
- Auto-broadcast nearby users — emits encounters on a timer (a "busy street" simulator).
SimulatedAdapter also exposes programmatic methods if you want to write
UITests:
simulatedAdapter.simulateEncounter(remoteToken: "any-token", distance: 1.0)
simulatedAdapter.simulateCrowd(count: 20)
Two-simulator / two-client testing
To test the mutual flow (both sides), run two simulator instances:
- Boot two simulators (e.g. iPhone 15 + iPhone 15 Pro).
- Run the app on both against the same local backend.
- In each, go present and simulate an encounter (the debug menu gives each a distinct token).
- Wave from one — the server derives each sender's own token from its
session, records the directional edge, and when both directions exist it
pushes
mutualto both sockets. The reveal triggers on both devices in real time.
The reference server now implements the full session→token mapping, so the mutual reveal and E2E key exchange work end-to-end across two clients.
Running the UI tests
The ProximityUITests target drives the happy path automatically:
xcodebuild test \
-project Proximity.xcodeproj \
-scheme Proximity \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-only-testing:ProximityUITests/ProximityFlowUITests
Start the reference server first (cd server && npm run dev).
Testing on real hardware (the sensors)
When you're ready to test UWB / BLE / NFC for real:
- Disable the simulated adapter. Either build a non-DEBUG configuration,
or set
AppState.isSimulated = false. - Use two physical iPhones (iPhone 11+ for UWB).
- The real
UWBAdapter,BLEAdapter,BeaconAdaptertake over.
The rest of the app (auth, chat, reveal, backend) works identically — that's the point of the abstraction.
What the simulator can't do (and why it's OK)
- UWB: no support in the simulator. But UWB is only the "this exact person" distance sensor — the interaction logic (handshake → reveal) is fully testable via simulation.
- NFC: no support. NFC is a niche "tap to connect" feature, not core.
- BLE: very limited in simulator. The presence logic is testable; the radio isn't.
Since the make-or-break mechanic — the physical interaction moment — is driven by logic + UI, not by the radio, you can validate the entire product experience in the simulator before ever touching real devices.