T22 -- TelemetryUploader on package:http with MockClient standing in for MockWebServer, tested against a real in-memory Drift database rather than a fake DAO. Upload runs on its own timer, injected as a callback so the engine has no opinion about HTTP and tests need no network. Config on shared_preferences with a hand-rolled UUID v4. Still no UI for the endpoint, exactly as in the native app. 7 tests. T24 -- integration_test/app_test.dart, 4 tests passing on the iOS simulator. These cover what widget tests cannot: Drift opening against real platform storage, plugin registration, go_router driving a real Navigator, cold start. T26 -- RELEASE-IOS.md. Usage strings are specific rather than generic, which is the leading Guideline 5.1.1 rejection cause; privacy-label answers decided; a pre-submission list covering the bundle-id switch back to com.rippr, the still default app icon, a release build, and a demo video for review notes. T25 written up as REAL-RIDE-CHECKLIST.md but outstanding by nature. Two items decide real things: force-stopping mid-ride on Android confirms the 111 km crash-gap bug is fixed, and parking 15 minutes mid-recording on iOS decides whether geolocator is sufficient or the paid engine is needed. Two prefer_initializing_formals lints suppressed with a reason: Dart forbids a named parameter beginning with an underscore, so the suggested fix will not compile. 178 tests passing, analyze clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
4.5 KiB
Markdown
101 lines
4.5 KiB
Markdown
# T25 — the real-ride checklist
|
|
|
|
**This is the only task in the plan that cannot be automated, and it is the one that
|
|
matters most.** 171 unit and widget tests plus 4 integration tests are green, and none of
|
|
them prove the app records a ride correctly.
|
|
|
|
Adapted from the native repo's `docs/TESTING.md`, extended for two platforms.
|
|
|
|
---
|
|
|
|
## Why a green suite proves nothing here
|
|
|
|
**Neither simulator produces velocity.** `adb emu geo fix` teleports the device and iOS's
|
|
simulated locations are no better, so every recorded `speedKmh` is `0.0`. That makes the
|
|
following **structurally unverifiable** without riding:
|
|
|
|
- max speed, average moving speed
|
|
- moving time (everything sits under the 1.5 km/h noise floor, so it stays 00:00:00)
|
|
- speed colouring on the map — the whole path renders in one colour
|
|
- elevation gain against real, *correlated* GPS altitude error
|
|
- battery over a multi-hour ride
|
|
- whether iOS suspends a stationary app mid-ride
|
|
|
|
And the subtler trap, which cost v2.0 a release: **when a value cannot change under test,
|
|
the UI around it cannot be judged either.** Max speed as the headline looked perfectly
|
|
fine on an emulator where every number was zero. On a real ride it read as a frozen,
|
|
broken screen.
|
|
|
|
---
|
|
|
|
## Before you ride
|
|
|
|
Install both apps. They have different application ids on purpose
|
|
(`com.rippr` and `com.rippr.port`), so they coexist:
|
|
|
|
```bash
|
|
flutter build apk --debug && flutter install # Flutter port
|
|
adb install -r ~/dojo/samplez/rippr-2.0.1-debug.apk # native reference
|
|
```
|
|
|
|
**Run both simultaneously on the Android ride.** Recording the same ride twice gives a
|
|
direct numeric comparison, which is far stronger evidence than either app alone.
|
|
|
|
---
|
|
|
|
## The ride
|
|
|
|
Do this once on **Android** and once on **iOS**. Pocket the phone — that is the founding
|
|
use case.
|
|
|
|
| # | Check | Why it is here |
|
|
|---|---|---|
|
|
| 1 | Start, pocket, ride ~20 min, stop | The actual usage pattern |
|
|
| 2 | Max speed plausible against the speedometer | Unverifiable on any simulator |
|
|
| 3 | Distance plausible against the odometer | Guards the cross-batch anchor |
|
|
| 4 | Moving time excludes stops | Noise floor behaviour on real data |
|
|
| 5 | **Elevation gain near zero on flat ground** | The most likely silent bug; synthetic noise is uniform, real error is correlated |
|
|
| 6 | Pause at a stop, resume — **no straight line across the gap** | The segment guarantee |
|
|
| 7 | Speed colouring visibly varies along the path | Cannot render in more than one colour on a simulator |
|
|
| 8 | **A short ride (under 100 m) still shows streets** | The v2.0 zoom bug |
|
|
| 9 | GPX opens correctly in Google Earth or Strava | Schema-valid is not the same as accepted |
|
|
| 10 | Battery drain over a multi-hour ride | Never measured, on either app |
|
|
| 11 | Pause/resume survives a screen-off stretch | Android wake lock, iOS background mode |
|
|
|
|
### Android only
|
|
|
|
| # | Check |
|
|
|---|---|
|
|
| A1 | The ongoing notification appears and persists with the screen off |
|
|
| A2 | Force-stop the app mid-ride, relaunch — the ride resumes into a **new segment**, and the dead time is **not** added to distance |
|
|
| A3 | Compare totals against the native app recording the same ride |
|
|
|
|
> **A2 is the fix for a real bug found in the native app.** See T11 in
|
|
> [PROGRESS.md](PROGRESS.md): the native version measures straight through the dead time,
|
|
> which a synthetic test showed adding **111 km**. Confirm the port does not.
|
|
|
|
### iOS only — the genuine unknown
|
|
|
|
| # | Check |
|
|
|---|---|
|
|
| I1 | The blue background-location indicator appears while recording |
|
|
| I2 | Lock the screen for 10 minutes of riding — fixes keep arriving |
|
|
| I3 | **Park for 15 minutes without stopping the recording, then ride again.** Does recording resume? |
|
|
| I4 | Take a phone call mid-ride; recording survives |
|
|
| I5 | Swipe the app away mid-ride — what happens? Document it, whatever it is |
|
|
|
|
**I3 is the decisive test for the whole platform strategy.** If iOS suspends the app when
|
|
stationary and does not reliably resume, `geolocator` is not sufficient and the
|
|
`LocationSource` seam exists precisely so `flutter_background_geolocation` (~$500/yr) can
|
|
be swapped in as one new implementation. Do not make that call without this data.
|
|
|
|
---
|
|
|
|
## Recording the results
|
|
|
|
Append findings to [PROGRESS.md](PROGRESS.md) under a T25 heading, including the numbers
|
|
from both apps where Android was recorded twice. If elevation gain on flat ground is
|
|
implausible, **do not tune it blind** — the native backlog says so explicitly, and the
|
|
port's parity harness (`tool/parity/run.sh`) means any change can be checked against the
|
|
Kotlin implementation first.
|