medium priority medium complexity testing pending testing specialist Tier 3

Acceptance Criteria

Test suite contains at least one test per branch: threshold met, threshold not met, badge already awarded, badge award service error, repository read error
ReferralAttributionService event stream is fully mocked — no real Supabase calls in any test
BadgeDefinitionRepository mock returns criteria keyed by type matching the recruitment event type
Threshold comparison tests cover boundary values: count exactly at threshold (award triggered), count one below threshold (not triggered), count above threshold (award triggered once, not multiple times)
Duplicate-award guard test: BadgeRepository mock returns existing badge → BadgeAwardService.award is never called
Success event emission verified via stream listener assertion after award completes
Failure event emission verified when BadgeAwardService throws — no unhandled exception propagates
All tests pass with flutter_test and produce a coverage report showing 100% branch coverage on BadgeCriteriaIntegration evaluation methods
Tests run in under 2 seconds total (no I/O, all mocked)

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
Riverpod
apis
BadgeAwardService mock
BadgeRepository mock
BadgeDefinitionRepository mock
ReferralAttributionService event stream mock
data models
badge_definition
performance requirements
Full test suite completes in under 2 seconds — all dependencies are synchronous mocks
security requirements
No real credentials or Supabase URLs in test files
Test fixtures must not contain real personnummer or PII

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Structure tests in a single file: badge_criteria_integration_test.dart. Group by scenario using group() blocks: 'threshold evaluation', 'duplicate guard', 'event emission', 'error handling'. Use setUp() to initialise fresh mocks and a new StreamController before each test — avoids state leakage between tests. For the stream subscription test, add the integration's StreamSubscription to an addTearDown() cleanup.

Avoid testing Riverpod provider wiring in these unit tests — that belongs in widget/integration tests. Focus exclusively on the evaluation logic class itself.

Testing Requirements

Pure unit tests using flutter_test. Use mockito or mocktail for mock generation. Create a StreamController in test setup to simulate the ReferralAttributionService event stream. Use fake_async or pump-based patterns if any debounce/delay logic exists.

Assert on both the mock call counts (verify(mockBadgeAwardService.award(any, any)).called(1)) and on the emitted stream events. Generate coverage with flutter test --coverage and verify 100% branch coverage on the integration class before marking done.

Component
Badge Criteria Integration
service medium
Epic Risks (3)
medium impact high prob dependency

BadgeCriteriaIntegration must reference specific badge definition IDs from the badge-definition-repository for recruitment badges. If those badge definitions have not been created in the database when this epic is implemented, the integration will silently fail to award badges.

Mitigation & Contingency

Mitigation: As the first task of this epic, create the four recruitment badge definitions (seed data migration) with known, stable IDs. BadgeCriteriaIntegration hardcodes these IDs as constants. Include an assertion in the integration tests that verifies the badge definition records exist in the test database.

Contingency: If the badge definitions system does not support seeding at migration time, store the badge definition IDs in a feature-flag-style config table and look them up at runtime, falling back to a no-op with a warning log if they are absent.

medium impact medium prob technical

The coordinator dashboard aggregates referral stats across all peer mentors in an organisation. For large organisations (HLF has many peer mentors nationally), the aggregation query may be slow, causing the dashboard to feel unresponsive.

Mitigation & Contingency

Mitigation: Implement the aggregation as a Supabase database view or RPC that runs server-side with appropriate indexes on (mentor_id, org_id, created_at, event_type). Add a composite index on referral_events during the foundation epic's migration. Cache the result in the Riverpod provider with a 5-minute TTL.

Contingency: If query performance remains unacceptable at scale, materialise the aggregation in a nightly pg_cron job into a stats_cache table, and serve the dashboard from the cache with a 'last updated' timestamp shown to the coordinator.

medium impact low prob integration

The existing badge award service is implemented by the achievement-badges feature. If that feature's public API (BadgeAwardService interface) changes while this epic is in progress, the BadgeCriteriaIntegration will break at compile time or behave incorrectly at runtime.

Mitigation & Contingency

Mitigation: Confirm the BadgeAwardService interface is stable and document the exact method signatures this integration depends on. Write a narrow integration test that constructs the real BadgeAwardService against a test database to detect breaking changes immediately.

Contingency: If the badge service interface changes, adapt the BadgeCriteriaIntegration adapter class to match the new contract. The adapter pattern used here isolates the change to a single class.