high priority medium complexity testing pending testing specialist Tier 7

Acceptance Criteria

All ActiveChapterState BLoC state transitions have corresponding unit tests with 100% branch coverage
Initial state test verifies BLoC emits NoChapterSelected on first creation when no persisted chapter exists
SelectChapter event test verifies BLoC emits ChapterSelected with correct chapter data and persists chapter ID to secure storage
Logout event test verifies BLoC clears secure storage entry and emits NoChapterSelected state
App restart test verifies BLoC reads persisted chapter ID from secure storage, fetches chapter from repository, and emits ChapterSelected on success
App restart test verifies BLoC emits NoChapterSelected when secure storage is empty on restart
App restart test verifies BLoC emits NoChapterSelected and clears stale storage entry when repository lookup returns null for persisted ID
Mock secure storage adapter verifies read/write/delete calls are made with correct keys and values
Riverpod provider test verifies widget consumers receive correct state via ProviderScope and ref.watch
All tests pass in CI with flutter test --coverage and no flaky behavior
Error path: repository throws exception during restore → BLoC emits NoChapterSelected and does not crash

Technical Requirements

frameworks
Flutter
flutter_test
BLoC (bloc_test)
Riverpod
data models
Chapter
ActiveChapterState
NoChapterSelected
ChapterSelected
performance requirements
All tests complete in under 5 seconds total
No real async timers or network calls in unit tests
security requirements
Mock adapter must not write to real secure storage during tests
Verify secure storage key naming is consistent and not guessable

Execution Context

Execution Tier
Tier 7

Tier 7 - 84 tasks

Can start after Tier 6 completes

Implementation Notes

Use bloc_test's blocTest() with act/expect/verify parameters — avoid manual StreamQueue assertions. For Riverpod provider tests, wrap in ProviderContainer and use container.read() / container.listen(). The mock secure storage should be a hand-written Fake or generated with mocktail — prefer mocktail for verify() call counts. Ensure the BLoC constructor accepts the repository and storage adapter via dependency injection so mocks can be injected cleanly.

Group tests by event type using group() blocks for readability. Test the error/null path for the repository lookup to ensure the BLoC degrades gracefully — this is a common oversight that causes production crashes on first-install or after data wipes.

Testing Requirements

Unit tests only using flutter_test and bloc_test packages. Use MockSecureStorage adapter implementing the same abstract interface as the real adapter — do not instantiate flutter_secure_storage directly. Use bloc_test's blocTest() helper for all BLoC event/state assertions. Use ProviderContainer from Riverpod for provider-level tests.

Cover: (1) initial state, (2) SelectChapter happy path, (3) logout clears storage + state, (4) restart with valid persisted ID, (5) restart with empty storage, (6) restart with stale/invalid ID, (7) repository exception during restore. Achieve 100% line and branch coverage on the BLoC class.

Component
Active Chapter State (BLoC)
service low
Epic Risks (3)
high impact medium prob technical

Recursive CTE queries for large hierarchies (1,400+ nodes) may exceed Supabase query timeouts or produce unacceptably slow responses, degrading tree load time beyond the 1-second target.

Mitigation & Contingency

Mitigation: Implement Supabase RPC functions for subtree fetches rather than client-side recursive calls. Use materialized path or closure table as a supplemental index for depth-first traversal. Benchmark with realistic NHF data volumes during development.

Contingency: Fall back to a pre-computed flat unit list stored in the hierarchy cache with client-side tree reconstruction, trading freshness for speed. Add a background refresh job to keep the cache warm.

medium impact low prob technical

Concurrent writes from multiple admin sessions could cause cache staleness, leading to stale tree views and incorrect ancestor path computations that corrupt aggregation results.

Mitigation & Contingency

Mitigation: Use optimistic versioning on cache entries with a short TTL (5 minutes) as a safety net. Subscribe to Supabase Realtime on the organization_units table to push invalidation events to all connected clients.

Contingency: Provide a manual 'Refresh Hierarchy' action in the admin portal that forces a full cache bust, and display a staleness warning banner when the cache age exceeds the TTL.

high impact low prob security

Persisting the flat unit list to local storage may expose organization structure data if the device is compromised or the storage is not properly encrypted, violating data protection requirements.

Mitigation & Contingency

Mitigation: Use flutter_secure_storage (AES-256 backed by Keychain/Keystore) for the local unit list cache rather than SharedPreferences. Include only unit IDs, names, and types — no member PII.

Contingency: Disable local-storage persistence entirely and rely on in-memory cache only. Accept the trade-off of no offline hierarchy access for the security guarantee.