Integration test full provider graph and disposal
epic-dynamic-terminology-and-labels-service-layer-task-012 — Write integration tests using ProviderContainer to validate the full Riverpod provider graph: organizationLabelsNotifierProvider initializes and exposes loaded state, labelProvider(key) family returns correct per-key value and rebuilds only when that key changes, terminologySyncServiceProvider starts the sync service and disposes it on auth logout, and provider graph has no circular dependencies or memory leaks across org switches.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
This integration test suite serves as the canonical proof that the provider graph design is sound. Structure as: (1) graph topology test — just create the container and read all providers to confirm no circular deps; (2) state lifecycle tests — step through the expected state machine; (3) granular rebuild tests — use listener spy pattern; (4) disposal tests — simulate logout and container.dispose(). Use `ProviderObserver` to log all state changes during the test run for easier debugging. Create a shared `buildTestContainer()` helper that wires all stubs to avoid boilerplate across test cases.
Document the expected provider dependency order in a comment block at the top of the test file.
Testing Requirements
Integration tests using ProviderContainer with dependency overrides for all external services (Supabase, connectivity, auth stream). Use a single container instance per test group (setUp/tearDown) with container.dispose() in tearDown. Test rebuild granularity by attaching multiple listeners to different labelProvider family instances and counting invocations. Use StreamController for auth state simulation.
Verify service lifecycle by injecting a spy/mock TerminologySyncService and asserting start() and dispose() call counts. Run tests with `flutter test` — no device or emulator required.
When a user switches organization context (e.g., a coordinator with multi-org access), a race condition between the outgoing organization's map disposal and the incoming organization's fetch could briefly expose the wrong organization's terminology to the widget tree.
Mitigation & Contingency
Mitigation: Implement an explicit loading state in OrganizationLabelsNotifier that widgets check before rendering any resolved labels. The provider graph should cancel the previous organization's fetch via Riverpod's ref.onDispose before initiating the next.
Contingency: If the race manifests in production, fall back to English defaults during the transition window and emit a Sentry error event for investigation; the UX impact is a brief English flash rather than wrong-org terminology.
Supabase Row Level Security policies on organization_configs may inadvertently restrict the authenticated user from reading their own organization's labels JSONB column, causing silent empty maps that appear as English fallbacks.
Mitigation & Contingency
Mitigation: Write and test explicit RLS policies that grant SELECT on the labels column to any authenticated user whose organization_id matches. Add an integration test that verifies label fetch succeeds for each role (peer mentor, coordinator, admin).
Contingency: If RLS blocks are discovered in production, temporarily escalate label fetch to a service-role edge function while the RLS policy is corrected, ensuring no labels are exposed cross-organization.
A peer mentor who installs the app for the first time with no internet connection will have no cached terminology map and will see only English defaults, which may be confusing for organizations like NHF that use Norwegian-specific role names exclusively.
Mitigation & Contingency
Mitigation: Bundle a default fallback terminology map for each known organization as a compile-time asset (Dart asset file) so that even fresh installs without connectivity render correct organizational terminology immediately.
Contingency: If bundled assets are out of date, display a one-time informational banner noting that terminology will update on next connectivity restore, with no functional blocking of the app.