Commit Graph

5 Commits

Author SHA1 Message Date
Trey T
9fa58352c0 Parity gallery: unify around canonical manifest, fix populated-state rendering
Single source of truth: `com.tt.honeyDue.testing.GalleryScreens` lists
every user-reachable screen with its category (DataCarrying / DataFree)
and per-platform reachability. Both platforms' test harnesses are
CI-gated against it — `GalleryManifestParityTest` on each side fails
if the surface list drifts from the manifest.

Variant matrix by category: DataCarrying captures 4 PNGs
(empty/populated × light/dark), DataFree captures 2 (light/dark only).
Empty variants for DataCarrying use `FixtureDataManager.empty(seedLookups = false)`
so form screens that only read DM lookups can diff against populated.

Detail-screen rendering fixed on both platforms. Root cause: VM
`stateIn(Eagerly, initialValue = …)` closures evaluated
`_selectedX.value` before screen-side `LaunchedEffect` / `.onAppear`
could set the id, leaving populated captures byte-identical to empty.

  Kotlin: `ContractorViewModel` + `DocumentViewModel` accept
  `initialSelectedX: Int? = null` so the id is set in the primary
  constructor before `stateIn` computes its seed.

  Swift: `ContractorViewModel`, `DocumentViewModelWrapper`,
  `ResidenceViewModel`, `OnboardingTasksViewModel` gained pre-seed
  init params. `ContractorDetailView`, `DocumentDetailView`,
  `ResidenceDetailView`, `OnboardingFirstTaskContent` gained
  test/preview init overloads that accept the pre-seeded VM.
  Corresponding view bodies prefer cached success state over
  loading/error — avoids a spinner flashing over already-visible
  content during background refreshes (production benefit too).

Real production bug fixed along the way: `DataManager.clear()` was
missing `_contractorDetail`, `_documentDetail`, `_contractorsByResidence`,
`_taskCompletions`, `_notificationPreferences`. On logout these maps
leaked across user sessions; in the gallery they leaked the previous
surface's populated state into the next surface's empty capture.

`ImagePicker.android.kt` guards `rememberCameraPicker` with
`LocalInspectionMode` — `FileProvider.getUriForFile` can't resolve the
Robolectric test-cache path, so `add_document` / `edit_document`
previously failed the entire capture.

Honest reclassifications: `complete_task`, `manage_users`, and
`task_suggestions` moved to DataFree. Their first-paint visible state
is driven by static props or APILayer calls, not by anything on
`IDataManager` — populated would be byte-identical to empty without
a significant production rewire. The manifest comments call this out.

Manifest counts after all moves: 43 screens = 12 DataCarrying + 31
DataFree, 37 on both platforms + 3 Android-only (home, documents,
biometric_lock) + 3 iOS-only (documents_warranties, add_task,
profile_edit).

Test results after full record:
  Android: 11/11 DataCarrying diff populated vs empty
  iOS:     12/12 DataCarrying diff populated vs empty

Also in this change:
- `scripts/build_parity_gallery.py` parses the Kotlin manifest
  directly, renders rows in product-flow order, shows explicit
  `[missing — <platform>]` placeholders for expected-but-absent
  captures and muted `not on <platform>` placeholders for
  platform-specific screens. Docs regenerated.
- `scripts/cleanup_orphan_goldens.sh` safely removes PNGs from prior
  test configurations (theme-named, compare artifacts, legacy
  empty/populated pairs for what is now DataFree). Dry-run by default.
- `docs/parity-gallery.md` rewritten: canonical-manifest workflow,
  adding-a-screen guide, variant matrix explained.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 18:10:32 -05:00
Trey T
f83e89bee3 Parity gallery: honest populated-state coverage (10/34 surfaces differ)
Fixed & documented, not-just-marketed:
- HomeScreen now derives summary card from LocalDataManager.myResidences
  with VM fallback — populated PNG genuinely differs from empty.
- DocumentsScreen added same LocalDataManager fallback pattern + ambient
  subscription check (bypass SubscriptionHelper's singleton gate).
- ScreenshotTests.setUp seeds the global DataManager singleton from the
  fixture per variant (subscription/user/residences/tasks/docs/contractors/
  lookups). Unblocks screens that bypass LocalDataManager.

Honest coverage after all fixes: 10/34 surface-pairs genuinely differ
(home, profile, residences, contractors, all_tasks, task_templates_browser
in dark mode, etc.). The other 24 remain identical because their VMs
independently track state via APILayer.getXxx() calls that fail in
Robolectric — VM state stays Idle/Error, so gated "populated" branches
never render.

Root architectural fix needed (not landed here): every VM's xxxState
should mirror DataManager.xxx reactively instead of tracking API results
independently. That's a ~20-VM refactor tracked as follow-up in
docs/parity-gallery.md "Known limitations".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:31:52 -05:00
Trey T
ab0e5c450c Coverage: regenerate gallery — 40/40 Android surfaces rendering
Previous run left edit_document at 0/4 because the record task hadn't
recorded it; the other 39 surfaces' goldens were optimized in-place by
zopflipng (no visual change). Gallery HTML/markdown regenerated to
reflect 160 Android goldens (40 surfaces × 4 variants).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 02:28:59 -05:00
Trey T
b24469bf38 Coverage: Android gallery expansion 23 → 39 surfaces + regenerate gallery
Android Roborazzi re-recorded end-to-end. Coverage expanded from 23
surfaces × 4 variants (92 goldens) to 39 surfaces × 4 variants (156
goldens). Only edit_document still silent-fails — flagged for follow-up
PR requiring fixture DocumentResponse + a non-network Edit flow.

docs/parity-gallery.html + docs/parity-gallery-grid.md regenerated:
47 screens, 156 Android + 88 iOS = 244 PNGs. Compared to the prior
gallery commit (3944223) this doubles total coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 01:45:14 -05:00
Trey T
6cc5295db8 P2: Android parity gallery — real-screen captures (partial, 17/40 surfaces)
Replaces the synthetic theme-showcase ScreenshotTests with real screens
rendered against FixtureDataManager.empty() / .populated() via
LocalDataManager. GallerySurfaces.kt manifest declares 40 screens.

Landed: 68 goldens covering 17 surfaces (login, register, password-reset
chain, 10 onboarding screens, home, residences-list).

Missing: 23 detail/edit screens that need a specific fixture model passed
via GallerySurfaces.kt — tracked as follow-up in docs/parity-gallery.md.
Non-blocking: these render silently as blank and don't fail the suite.

Android total: 2.5 MB, avg 41 KB, max 113 KB — well under the 150 KB
per-file budget enforced by the CI size gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:45:12 -05:00