Write unit and integration tests for OrganizationRepository
epic-organization-selection-and-onboarding-data-layer-task-009 — Write comprehensive tests for OrganizationRepository covering: unit tests for domain model mapping from raw Supabase JSON, cache hit/miss behavior, cache invalidation on sign-out, and error handling. Write integration tests against a Supabase test project verifying the Realtime stream emits on table changes and that RLS correctly scopes results to the authenticated user. Use flutter_test with mocktail for unit tests and a dedicated test Supabase instance for integration tests.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Use mocktail's `when(() => mockSupabase.from('organizations')...)` pattern to stub Supabase client calls — avoid real HTTP in unit tests. The cache layer is most reliably tested by injecting a controllable clock (DateTime provider) so TTL expiry can be simulated without sleeping. For integration tests, use a dedicated Supabase project with RLS policies mirroring production; seed it in a `setUpAll` block and clean up in `tearDownAll`. To test Realtime, subscribe before inserting and use a `Completer` with a timeout to await the event.
Verify RLS by authenticating two separate JWT tokens (user A and user B) and asserting the stream for user A never emits user B's rows. Parameterize the Supabase URL and anon/service-role keys via `const String.fromEnvironment` so the same test binary works in all environments.
Testing Requirements
Unit tests (flutter_test + mocktail): mock the Supabase client and verify (1) JSON-to-domain mapping covers all fields including nullable ones, (2) cache returns stale data on hit, (3) cache is bypassed and refreshed on miss, (4) sign-out clears cache, (5) each error type produces the correct typed exception. Integration tests (dedicated test Supabase instance): spin up a seeded test schema, authenticate as a test user, assert Realtime stream events fire on INSERT/UPDATE/DELETE, assert a second test user cannot observe the first user's data. Integration tests are gated behind a CI environment variable (RUN_INTEGRATION_TESTS=true) so they do not block local unit test runs. Aim for 100% branch coverage on repository logic; integration coverage report generated in CI.
TenantSessionStore must write to both SecureStorageAdapter and Supabase session synchronously. If the Supabase write succeeds but the local secure storage write fails (or vice versa), the system ends up in an inconsistent state: local app thinks org A is selected but Supabase queries are scoped to org B (or unscoped), causing silent data leakage or empty result sets.
Mitigation & Contingency
Mitigation: Implement the dual-write with compensating rollback: if the second write fails, undo the first write and surface a typed DualWriteFailureError to callers. Add a startup integrity check in restoreSession() that validates local storage and Supabase session agree on the current org_id.
Contingency: If integrity check fails on startup, clear both stores and redirect the user to the org selection screen rather than proceeding with potentially mismatched state.
An organization could be deactivated in Supabase between the time the org list is cached and the time the user taps to select it. If the repository serves stale cached data the org-selection-service will attempt to seed a context for an inactive org, potentially causing RLS scope issues or confusing error states.
Mitigation & Contingency
Mitigation: The OrganizationRepository.getOrganizationById() path used during selection validation always performs a fresh network fetch (bypassing cache) to confirm the org is still active before the TenantSessionStore writes anything.
Contingency: If a freshness check finds the org is inactive, surface a localized error message on the selection screen ('This organization is no longer available') and refresh the org list to show only currently active partners.