End-to-end navigation state restore test
epic-navigation-and-gesture-accessibility-foundation-task-013 — Write an end-to-end widget test that simulates a full session cycle: navigate to tab 3, push two sub-routes, background the app, restore the app, and assert that tab 3 is active and the sub-route stack is restored correctly. Also simulate a logout mid-session and assert that the next session starts at tab 0 with empty stacks. This test exercises the full stack: TabStateManager, NavigationStateRepository, and GoRouter configuration together.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
The trickiest part is simulating backgrounding and restoring without a real device. Use tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused) followed by handleAppLifecycleStateChanged(AppLifecycleState.resumed) — this triggers the WidgetsBindingObserver callbacks that TabStateManager listens to. If GoRouter uses a navigatorKey, capture it after pumpWidget and use it to inspect the current route stack directly. Build a minimal test app scaffold that includes only the navigation shell and two or three stub page widgets — avoid pumping the full production widget tree to keep test speed acceptable.
Use ValueKey or GlobalKey on each stub page widget so finders are unambiguous.
Testing Requirements
This task IS the testing task. The test covers the integration seam between GoRouter, TabStateManager, and NavigationStateRepository. Use ProviderScope with overrides to inject the fake repository. Simulate AppLifecycleState changes by calling tester.binding.handleAppLifecycleStateChanged() directly.
For logout simulation, call the auth provider's logout method (or override the auth state provider to return logged-out). Assert both the Riverpod state (via ProviderContainer reads) AND the rendered widget tree (via widget finders) to ensure the test is not a false positive that only checks in-memory state. Run this test in CI with flutter test --coverage to confirm line coverage of the navigation foundation modules.
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.