diff --git a/docs/progress.md b/docs/progress.md index b130e14..89977a9 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -2,6 +2,25 @@ Updated: 2026-02-15 +## Latest Milestone (2026-02-15): App Session Flow Test Coverage + +Added higher-level widget coverage for a core authenticated user journey: + +- New test: + - `test/features/app/app_auth_flow_test.dart` + - validates end-to-end path: + - sign-in screen shown by default + - sign-in transitions into app shell + - navigate to settings and sign out + - sign-out returns to sign-in screen +- Uses deterministic in-memory overrides for token, local data store, sync state + store, and backend gateway fake. + +Validation for this milestone: + +- `flutter analyze` -> pass +- `flutter test` -> pass + ## Latest Milestone (2026-02-15): Rejected-Mutation Requeue Flow Extended sync conflict handling so rejected mutations can be retried after local diff --git a/test/features/app/app_auth_flow_test.dart b/test/features/app/app_auth_flow_test.dart new file mode 100644 index 0000000..af25f90 --- /dev/null +++ b/test/features/app/app_auth_flow_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:relationship_saver/core/auth/in_memory_token_store.dart'; +import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart'; +import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart'; +import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart'; +import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart'; +import 'package:relationship_saver/integrations/backend/backend_gateway_fake.dart'; +import 'package:relationship_saver/integrations/backend/backend_gateway_provider.dart'; +import 'package:relationship_saver/main.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +void main() { + setUp(() { + SharedPreferences.setMockInitialValues({}); + }); + + testWidgets('sign-in and sign-out session flow works end-to-end', ( + WidgetTester tester, + ) async { + await tester.binding.setSurfaceSize(const Size(1280, 800)); + addTearDown(() => tester.binding.setSurfaceSize(null)); + + await tester.pumpWidget( + ProviderScope( + overrides: [ + tokenStoreProvider.overrideWithValue(InMemoryTokenStore()), + backendGatewayProvider.overrideWithValue(BackendGatewayFake()), + localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()), + syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()), + ], + child: const RelationshipSaverApp(), + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('Sign in to continue'), findsOneWidget); + + await tester.tap(find.widgetWithText(FilledButton, 'Sign In')); + await tester.pumpAndSettle(const Duration(milliseconds: 450)); + + expect(find.text('Dashboard'), findsWidgets); + + await tester.tap(find.text('Settings').first); + await tester.pumpAndSettle(const Duration(milliseconds: 450)); + + expect( + find.text('Environment and integration configuration for this build.'), + findsOneWidget, + ); + + await tester.tap(find.widgetWithText(FilledButton, 'Sign Out')); + await tester.pumpAndSettle(const Duration(milliseconds: 450)); + + expect(find.text('Sign in to continue'), findsOneWidget); + }); +}