high priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Test: initial state is AsyncLoading when notifier is first created
Test: successful fetch emits AsyncData with the exact label map returned by the stub repository
Test: Supabase error (e.g., PostgrestException) causes state to transition to AsyncError with the original exception
Test: org-switch (changing organizationId input) causes state to transition back to AsyncLoading, then to AsyncData with the new org's label map
Test: label('known_key') returns the resolved string from the loaded map
Test: label('missing_key') returns 'missing_key' as the raw fallback string
Test: label('any_key') returns the raw key when state is AsyncLoading
Test: label('any_key') returns the raw key when state is AsyncError
All stubs are set up with mockito or mocktail — no real Supabase calls in unit tests
Tests run in under 2 seconds total (no real async delays — use fake async or immediate futures)
All tests are independent — no shared mutable state between test cases

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
apis
Supabase (stubbed via mockito/mocktail)
data models
OrganizationLabelsNotifier
TerminologyRepository
TerminologyCacheAdapter
OrganizationLabelsState
performance requirements
Full test suite completes in under 5 seconds
No real network calls — all Supabase interactions stubbed
security requirements
Test fixtures must not contain real organization IDs or label data from production

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Structure tests in one test file per class: `organization_labels_notifier_test.dart`. Group tests by scenario using `group()`. For org-switch tests, update the provider's family argument (if org-id is a family parameter) or simulate the org-switch by calling the appropriate notifier method. Use `container.listen()` to collect all emitted states for sequence assertions rather than relying on a single final state check.

Prefer mocktail over mockito for null-safe Dart codebases as it requires less boilerplate. Ensure mock setup uses `when(() => repo.fetchLabels(any())).thenAnswer(...)` style for correct null-safe stub syntax.

Testing Requirements

Pure unit tests using flutter_test. Use ProviderContainer with overrides to inject mock TerminologyRepository and TerminologyCacheAdapter. Use fake async (FakeAsync from the fake_async package or flutter_test's pump) to control async timing. Each state transition should be tested in isolation.

Use `expectLater(container.read(provider.stream), emitsInOrder([...]))` pattern to assert emission sequences for multi-step transitions like org-switch. Aim for 100% branch coverage of the notifier's state transition logic and the label() helper method.

Component
Organization Labels Notifier
service medium
Epic Risks (3)
high impact medium prob technical

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.

high impact low prob security

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.

medium impact medium prob scope

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.