high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

StatsCacheManager: test that a cached value is returned on second call within TTL window without calling the repository
StatsCacheManager: test that a stale entry (past TTL) triggers a repository fetch and updates the cache
StatsCacheManager: test that explicit invalidate(key) causes the next call to fetch fresh data
StatsCacheManager: test concurrent access does not produce duplicate repository calls (use FakeAsync to control time)
RoleAccessValidator: test that coordinator role with matching chapterId passes scope check
RoleAccessValidator: test that coordinator role with mismatched chapterId throws typed AccessDeniedException
RoleAccessValidator: test that org-admin role with matching orgId passes scope check for all chapters in org
RoleAccessValidator: test that org-admin role with mismatched orgId throws AccessDeniedException
CoordinatorStatsService: test that getStatsViewModel() calls repository with correct parameters and maps response to expected CoordinatorStatsViewModel fields
CoordinatorStatsService: test that repository error is wrapped in a typed StatsServiceException
PersonalStatsService: test that buildContributionData() correctly aggregates activity rows into ContributionData monthly map
PersonalStatsService: test streak calculation for consecutive days, gap in streak, and zero-activity state
All tests use @GenerateMocks or @GenerateNiceMocks and run without network calls
flutter test --coverage reports 90%+ branch coverage on all four classes under test
Test file naming follows existing project convention (e.g. stats_cache_manager_test.dart)

Technical Requirements

frameworks
Flutter
Dart
flutter_test
mockito
build_runner
data models
ContributionData
CoordinatorStatsViewModel
StatsRow
PeriodStats
ActivityTypeStats
performance requirements
All unit tests must complete in under 5 seconds total
Use FakeAsync for time-dependent TTL tests to avoid real delays
security requirements
Tests must not embed real Supabase credentials — use mocked repository exclusively
AccessDeniedException tests verify that exception message does not leak internal org/chapter IDs in production mode

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Annotate mock generation at the top of each test file with @GenerateMocks([RepositoryClass]) and run flutter pub run build_runner build to generate .mocks.dart files before writing tests. Use FakeAsync.withZone to advance time for TTL tests — do not use real sleeps. For CoordinatorStatsService view model tests, construct minimal StatsRow fixtures rather than reading from JSON files, to keep tests self-contained. Verify that RoleAccessValidator tests cover both the positive (pass) and negative (throw) branches for each role — this is where branch coverage gaps are most likely.

Group related tests with group() for clarity in CI output.

Testing Requirements

Pure unit tests with flutter_test and mockito. Generate mocks with build_runner (@GenerateMocks annotation). Use FakeAsync (from fake_async package) for TTL and time-sensitive tests. Structure tests in describe/group blocks matching class names.

Each class under test gets its own test file. Run coverage with flutter test --coverage and verify lcov.info shows 90%+ branch coverage for service and cache source files. Include at least one test per public method and one test per distinct error path.

Component
Coordinator Statistics Service
service high
Epic Risks (3)
medium impact medium prob technical

fl_chart's default colour palette may not meet WCAG 2.2 AA contrast requirements when rendered on the app's dark or light backgrounds. If segment colours are insufficient, the donut chart will fail accessibility audits, which is a compliance blocker for all three organisations.

Mitigation & Contingency

Mitigation: Define all chart colours in the design token system with pre-validated contrast ratios. Run the contrast-ratio-validator against every chart colour during the adapter's unit tests. Use the contrast-safe-color-palette as the source palette.

Contingency: If a colour fails validation, replace with the nearest compliant token. If activity types exceed the available token set, implement a deterministic hashing algorithm that maps activity type IDs to compliant colours.

medium impact medium prob technical

StatsBloc subscribing to the activity registration stream creates a long-lived subscription. If the subscription is not disposed correctly when the dashboard is closed, it will cause a stream leak and potentially trigger re-fetches on a disposed BLoC, resulting in uncaught errors in production.

Mitigation & Contingency

Mitigation: Implement subscription disposal in the BLoC's close() override. Write a widget test that navigates away from the dashboard and asserts no BLoC events are emitted after disposal.

Contingency: If leaks are detected in QA, add a mounted check guard before emitting states from async callbacks, and audit all other BLoC stream subscriptions in the codebase for the same pattern.

low impact low prob scope

PersonalStatsService's Phase 4 gamification data structure is designed against an assumed future schema. If the Phase 4 Spotify Wrapped feature defines a different data contract when it is developed, the structure built now will require a breaking change and migration.

Mitigation & Contingency

Mitigation: Document the contribution data structure with explicit field semantics and versioning comments. Keep the Phase 4 fields as optional/nullable so they do not break existing consumers if the schema evolves.

Contingency: If the Phase 4 schema diverges significantly, the personal stats data can be re-mapped in a thin adapter layer without changing PersonalStatsService's core implementation.