Write unit tests for TabStateManager
epic-navigation-and-gesture-accessibility-foundation-task-011 — Write unit tests for TabStateManager covering: initial hydration from a pre-populated repository, setActiveTab updates activeTabIndex and persists, updateStackSnapshot stores and retrieves correct snapshot per tab, lifecycle hooks clear state on logout and role-switch, and resume reloads stale state from repository. Mock NavigationStateRepository with a fake implementation.
Acceptance Criteria
Technical Requirements
Execution Context
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.
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.
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.