Write unit tests for NavigationStateRepository
epic-navigation-and-gesture-accessibility-foundation-task-003 — Write unit tests for NavigationStateRepository covering: saving and loading tab index, saving and loading stack snapshots for each of five tabs, clearAll on logout/role-switch, and graceful handling of missing/corrupted stored data. Use a fake SharedPreferences instance to keep tests hermetic.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
The test file should be placed at test/navigation/navigation_state_repository_test.dart. Since SharedPreferences is injected into the repository constructor, no mockito mocks are needed — just use the fake instance from setMockInitialValues. For the 5-tab loop test, use a for loop with test('tab $i round-trip', ...) inside a group to avoid code duplication. For the corrupted data graceful-handling tests, pre-seed the raw SharedPreferences key directly (bypassing the repository's write path) to simulate real-world corruption scenarios.
Ensure tearDown calls SharedPreferences.setMockInitialValues({}) even if test throws, or rely on setUp being called before every test. Keep fixtures (sample route stacks) in a local const or a test fixture file shared with task-001 model tests.
Testing Requirements
Use SharedPreferences.setMockInitialValues({}) in a setUp() block to guarantee a clean store before each test. Instantiate NavigationStateRepository by passing the fake SharedPreferences.getInstance() result obtained after setMockInitialValues. Write one test group per method: 'saveTabIndex / loadTabIndex', 'saveStackSnapshot / loadStackSnapshot', 'clearAll', 'corrupted data handling'. For corrupted data tests, use SharedPreferences.setMockInitialValues({'nav_state.tab_index': 'not-a-number'}) to pre-seed invalid data.
Use expect(result, isNull) assertions — never expect an exception for graceful degradation paths. Run flutter test --coverage and confirm branch coverage with a coverage report.
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.