high priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

Test suite contains at least one test per documented behavior: hydration, setActiveTab, updateStackSnapshot, logout lifecycle, role-switch lifecycle, and resume-from-stale
All tests use a FakeNavigationStateRepository — no real Supabase or file I/O occurs in any test
setActiveTab test asserts both the in-memory state emission AND a corresponding persist() call on the fake repository
updateStackSnapshot test verifies that snapshots are stored per-tab index and do not overwrite each other
Logout lifecycle test asserts activeTabIndex resets to 0 and all stack snapshots are cleared
Role-switch lifecycle test asserts the same clearance behavior as logout
Resume test preloads the fake repository with a non-default state and asserts TabStateManager emits that state on initialization
All tests pass with flutter_test; no external process or emulator required
Test file is co-located in the test/ mirror of the source directory following project conventions

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
apis
ProviderContainer (Riverpod testing API)
TabStateManager public API
FakeNavigationStateRepository (test double)
data models
TabStateSnapshot
NavigationStateRepository (interface)
performance requirements
Each test completes in under 200ms — no real async delays permitted
Use fake async (FakeAsync or Riverpod's ProviderContainer with overrides) to control time in tests that involve debounced persistence
security requirements
Test data must not contain real user identifiers or PII even in fixtures

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Create FakeNavigationStateRepository as a simple in-memory implementation of the NavigationStateRepository interface that records all calls for assertion (call counts and arguments). Do not use Mockito or mocktail unless already in the project's pubspec — a handwritten fake is simpler and avoids code-gen setup. Group tests with group() blocks matching the public API surface: 'hydration', 'setActiveTab', 'updateStackSnapshot', 'lifecycle hooks', 'resume'. Use setUp to construct a fresh ProviderContainer and FakeNavigationStateRepository for each group so tests are fully independent.

If TabStateManager is a StateNotifier, use container.read(tabStateManagerProvider.notifier) to call methods and container.read(tabStateManagerProvider) to assert emitted state.

Testing Requirements

This task IS the testing task. Coverage goal: 100% of TabStateManager public methods and all documented state transitions. Use Riverpod's ProviderContainer with overrideWithValue to inject FakeNavigationStateRepository. Each test group should call container.dispose() in tearDown to prevent state leakage between tests.

Include negative cases: setActiveTab with an out-of-range index should throw an AssertionError or be a no-op per the contract. Use stream matchers (emitsInOrder, emits) from dart:async test utilities to assert stream emissions rather than awaiting individual values.

Component
Tab State Manager
service medium
Epic Risks (2)
high impact medium prob technical

StatefulShellRoute branch navigator state can interact unexpectedly with GoRouter's imperative navigation (go, push, replace), causing state snapshots to desync from actual route stacks. This could manifest as a user returning to a tab and seeing a different screen than expected, breaking the core motor-fatigue promise.

Mitigation & Contingency

Mitigation: Write integration tests that simulate cross-tab navigation with nested pushes before any UI layer is built. Pin go_router to a tested minor version and review the StatefulShellRoute changelog before upgrading.

Contingency: If branch navigator state consistently desyncs, fall back to a manual stack snapshot strategy using a custom NavigatorObserver that records and replays navigation events independently of StatefulShellRoute internals.

medium impact medium prob technical

Persisted navigation stacks in shared_preferences can become stale or corrupt if route paths are renamed during development, causing app crashes or infinite redirect loops on cold start for users who have an old snapshot.

Mitigation & Contingency

Mitigation: Version the persisted schema with a format key. On app start, validate that all stored route paths exist in the current route config before restoring; silently discard invalid entries rather than crashing.

Contingency: Implement a safe-mode cold start that skips state restoration after a detected crash (via a dirty-launch flag written at startup and cleared on successful first frame), falling back to the default root tab.