high priority medium complexity testing pending testing specialist Tier 6

Acceptance Criteria

Test suite contains at minimum 40 individual test cases across both AggregationQueryBuilder and BufdirMetricsRepository
Every public method on both classes has at least one happy-path test and one failure-path test
Org-isolation test: a test proves that calling any read method without org_id throws ArgumentError before any Supabase interaction
RPC parameter mapping test: verifies that fetchRawActivities passes the correct period, org_id, and any filter parameters to the mock Supabase RPC call
View query correctness test: verifies that geographic distribution query uses the PostGIS view name and not a raw table
Snapshot round-trip test: save → getMetricSnapshot returns saved data with correct field values
Cache-hit test: after save, a second fetch does not call the AggregationQueryBuilder mock (verified via verify(mock.fetchRawActivities(...)).called(0))
Cache-miss test: getMetricSnapshot with no prior save returns Right(None) and calls the query builder
Domain error mapping: PostgrestException with code '42501' (RLS violation) maps to UnauthorizedFailure
Domain error mapping: generic SocketException maps to NetworkFailure
MockBufdirMetricsRepository generated via @GenerateMocks can be injected into a sample service class and returns stubbed Either values
All tests run in under 10 seconds total (no real network calls)
Test file follows the project's existing test file naming and directory conventions

Technical Requirements

frameworks
Flutter
Dart
flutter_test
mockito
build_runner
apis
Supabase PostgreSQL 15 (mocked via mockito)
data models
activity
annual_summary
bufdir_export_audit_log
performance requirements
Full test suite execution under 10 seconds
No real network calls — all Supabase interactions mocked
security requirements
Test fixtures must not contain real org_id UUIDs, personnel numbers, or PII
Mock setup must not hardcode real Supabase credentials or URLs

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Use mockito's @GenerateMocks annotation on a @GenerateMocks([AggregationQueryBuilder, SupabaseClient]) class and run build_runner to generate mocks. Organize tests in nested group() blocks mirroring the class structure. For the MockBufdirMetricsRepository usability test, create a minimal BufdirSomeService class in the test file itself that accepts IBufdirMetricsRepository and verify the mock can be passed to it — this validates the interface is correctly abstract. Use setUp() to reset mock state between tests.

For error mapping tests, throw PostgrestException with specific statusCode values and assert the resulting Left() contains the correct DomainFailure subtype. Avoid testing private implementation details — only test through public method signatures.

Testing Requirements

This task IS the testing work. Deliverable is a test file (test/data/repositories/bufdir_metrics_repository_test.dart) using flutter_test groups: 'AggregationQueryBuilder', 'BufdirMetricsRepository - read operations', 'BufdirMetricsRepository - snapshot persistence', 'BufdirMetricsRepository - error mapping', and 'MockBufdirMetricsRepository usability'. Run flutter test --coverage and confirm line coverage >= 90% for both classes. All tests must pass on CI without environment variables pointing to a real Supabase instance.

Component
Bufdir Metrics Repository
data medium
Epic Risks (2)
high impact medium prob technical

Supabase RPC functions return JSON with PostgreSQL numeric types (bigint, numeric) that do not map cleanly to Dart int/double. Silent truncation or JSON parsing errors could corrupt participant counts in the final Bufdir submission without any runtime exception.

Mitigation & Contingency

Mitigation: Define explicit Dart fromJson factories for all RPC result models with type-safe parsing and assertion checks. Add a contract test that compares raw RPC JSON output against expected Dart model values using a known seed dataset.

Contingency: If type mismatches are found in production metrics, expose a validation endpoint in BufdirMetricsRepository that re-fetches and compares raw RPC output against the persisted snapshot, flagging any discrepancies before export proceeds.

medium impact high prob scope

Persisted metric snapshots can become stale if additional activities are registered after the snapshot is saved but before the export is finalized. Coordinators might unknowingly export data that does not reflect the latest activity registrations.

Mitigation & Contingency

Mitigation: Store a snapshot_generated_at timestamp and a record_count_at_generation field in the snapshot. When the coordinator views cached results, compare the current activity count for the period against the snapshot value and display a 'Data updated since last aggregation — re-run?' warning if counts differ.

Contingency: Add a mandatory staleness check before the export confirmation dialog can proceed: if the snapshot is more than 24 hours old or the record count has changed, require the coordinator to re-run aggregation before the export button is enabled.