Integration tests for BLoC, service, and repository flow
epic-expense-type-selection-core-services-task-016 — Write integration tests for the full reactive data flow: user toggles expense type → BLoC invokes rule engine → valid selection triggers calculation service → result emitted in state → repository draft written → final submit persists to Supabase. Also test invalid toggle (mutually exclusive type) rejected by BLoC, and draft recovery restoring selection on re-initialisation. Run tests with real in-memory Hive and mock Supabase.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 6 - 158 tasks
Can start after Tier 5 completes
Implementation Notes
This test file is the highest-confidence verification for the epic. Wire all real components except Supabase (mocked). The key test setup is: (1) Hive.init with a temporary directory per test (use Directory.systemTemp.createTempSync()), (2) register all Hive type adapters for ExpenseType and related models, (3) inject the mock Supabase client into the repository, (4) inject the repository and calculation service into the BLoC. For state sequence tests with bloc_test, use act to send multiple events in sequence and expect to assert intermediate states.
The mutual exclusion rejection test is critical: assert that the BLoC state after the invalid toggle is identical to the state before (selection unchanged), not just that an error flag is set. Clean up temp directories in tearDownAll. Consider extracting a TestDependencies helper class that wires the full graph to avoid repetition across test cases.
Testing Requirements
Integration tests using flutter_test and bloc_test. Wire together the real BLoC, real ExpenseCalculationService, real ExpenseTypeRepository, real in-memory Hive adapter, and mock Supabase client. Use setUp() to initialise Hive with Hive.init(tempDir) and registerAdapter, tearDown() to clear the Hive box. Use blocTest
For the draft recovery test, create the BLoC, add events, close it, then create a new BLoC instance over the same Hive box and verify initial state. Run with: flutter test test/integration/expense_selection_flow_test.dart.
The per-km reimbursement rate and transit zone amounts must be read from org-specific configuration stored in Supabase. If the rate configuration table or RLS policies are not yet deployed when this epic runs, the calculation service cannot be completed and integration tests will fail.
Mitigation & Contingency
Mitigation: Define a RateConfigRepository interface and inject a stub implementation with default HLF rates from day one; write the real Supabase adapter in parallel and swap via dependency injection before merge.
Contingency: If org rate config is delayed beyond this epic's window, ship with the default-rate stub and log a prominent warning; calculate with defaults and surface a 'rates not confirmed' notice in the UI preview.
If the peer mentor opens an expense claim on two devices simultaneously, the local draft and the Supabase record may diverge. The repository's last-write-wins strategy could silently overwrite a valid selection with a stale one.
Mitigation & Contingency
Mitigation: Add an updated_at timestamp to the draft record and reject saves where the server timestamp is newer than the local copy; surface a conflict resolution prompt rather than silently overwriting.
Contingency: If conflict resolution UI is out of scope, fall back to server-authoritative reads on app foreground resume and discard local draft, notifying the user that their draft was refreshed from the server.