Files
Nearfield_Friends/docs/TESTING.md

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

  1. Open Proximity.xcodeproj in Xcode.
  2. Select an iPhone simulator (any model).
  3. Build & run (⌘R).

In DEBUG builds, AppState automatically:

  • Points APIClient at http://localhost:8080
  • Injects SimulatedAdapter into the PresenceEngine

3. Exercise the interaction loop

  1. Sign in (Apple or Google — the reference server accepts any token).
  2. Tap the big "I'm Here" toggle to go present.
  3. Open the debug menu (hammer icon, top-left).
  4. Tap "Simulate someone walking by" — a silhouette appears in the feed.
  5. Tap Wave on the silhouette.
  6. 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:

  1. Boot two simulators (e.g. iPhone 15 + iPhone 15 Pro).
  2. Run the app on both against the same local backend.
  3. In each, go present and simulate an encounter (the debug menu gives each a distinct token).
  4. 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 mutual to 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:

  1. Disable the simulated adapter. Either build a non-DEBUG configuration, or set AppState.isSimulated = false.
  2. Use two physical iPhones (iPhone 11+ for UWB).
  3. The real UWBAdapter, BLEAdapter, BeaconAdapter take 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.