- Completed authentication system with signup, login, password reset, and logout - Enhanced error handling and accessibility across all auth flows - Added comprehensive loading states and user feedback - Implemented confirmation dialogs for destructive actions - Setup complete Flutter project structure with proper configuration - Added planning documentation for Phase 2 household creation - All Phase 1 success criteria verified and complete
144 lines
5.1 KiB
Dart
144 lines
5.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:integration_test/integration_test.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:sage/main.dart' as app;
|
|
import 'package:sage/core/router/app_router.dart';
|
|
|
|
/// Integration test for password reset flow
|
|
///
|
|
/// Tests the complete password reset journey:
|
|
/// 1. Navigate to password reset from login
|
|
/// 2. Request password reset
|
|
/// 3. Handle deep link with token
|
|
/// 4. Update password
|
|
/// 5. Navigate back to login
|
|
void main() {
|
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
group('Password Reset Flow', () {
|
|
testWidgets('complete password reset flow works correctly', (WidgetTester tester) async {
|
|
// Launch app
|
|
app.main();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Start from login screen (if not already there)
|
|
// Navigate to password reset
|
|
final forgotPasswordButton = find.text('Forgot Password?');
|
|
expect(forgotPasswordButton, findsOneWidget);
|
|
|
|
await tester.tap(forgotPasswordButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should be on reset password page
|
|
expect(find.text('Reset Password'), findsOneWidget);
|
|
expect(find.text('Forgot Password?'), findsOneWidget);
|
|
|
|
// Test deep linking by simulating URL with token
|
|
// This would normally be triggered by email link
|
|
final context = tester.element(find.byType(Scaffold));
|
|
|
|
// Navigate to reset password confirm with token
|
|
GoRouter.of(context).go('/reset-password-confirm?token=test123&email=test@example.com');
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should be on reset password confirm page
|
|
expect(find.text('Reset Password'), findsOneWidget);
|
|
|
|
// Navigate to update password with token
|
|
GoRouter.of(context).go('/update-password?token=test123&email=test@example.com');
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should be on update password page
|
|
expect(find.text('Update Password'), findsOneWidget);
|
|
expect(find.text('Set New Password'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('password reset navigation from signup works', (WidgetTester tester) async {
|
|
// Launch app
|
|
app.main();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Navigate to signup first
|
|
final signupButton = find.text('Sign Up');
|
|
if (signupButton.evaluate().isNotEmpty) {
|
|
await tester.tap(signupButton);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
// Look for forgot password link on signup page
|
|
final signupForgotPassword = find.text('Forgot Password?');
|
|
expect(signupForgotPassword, findsOneWidget);
|
|
|
|
await tester.tap(signupForgotPassword);
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should navigate to reset password page
|
|
expect(find.text('Reset Password'), findsOneWidget);
|
|
expect(find.text('Forgot Password?'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('deep linking handles malformed URLs gracefully', (WidgetTester tester) async {
|
|
// Launch app
|
|
app.main();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Test malformed reset URL
|
|
final context = tester.element(find.byType(Scaffold));
|
|
GoRouter.of(context).go('/reset-password-invalid');
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should show error page with option to request new reset
|
|
expect(find.text('Page not found'), findsOneWidget);
|
|
expect(find.text('Request New Reset Link'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('router extracts URL parameters correctly', (WidgetTester tester) async {
|
|
// Launch app
|
|
app.main();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Navigate with URL parameters
|
|
final context = tester.element(find.byType(Scaffold));
|
|
GoRouter.of(context).go('/reset-password-confirm?token=abc123&email=user@example.com');
|
|
await tester.pumpAndSettle();
|
|
|
|
// Extract parameters using router helper
|
|
final params = AppRouter.extractQueryParameters(context);
|
|
expect(params['token'], 'abc123');
|
|
expect(params['email'], 'user@example.com');
|
|
|
|
// Test deep link handler
|
|
final resetData = AppRouter.handlePasswordResetDeepLink(context);
|
|
expect(resetData['token'], 'abc123');
|
|
expect(resetData['email'], 'user@example.com');
|
|
});
|
|
});
|
|
|
|
group('Navigation Guards', () {
|
|
testWidgets('password reset routes are accessible without auth', (WidgetTester tester) async {
|
|
// Launch app
|
|
app.main();
|
|
await tester.pumpAndSettle();
|
|
|
|
// Test all password reset routes are accessible
|
|
final context = tester.element(find.byType(Scaffold));
|
|
|
|
// Test /reset-password
|
|
GoRouter.of(context).go('/reset-password');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Reset Password'), findsOneWidget);
|
|
|
|
// Test /reset-password-confirm
|
|
GoRouter.of(context).go('/reset-password-confirm');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Reset Password'), findsOneWidget);
|
|
|
|
// Test /update-password
|
|
GoRouter.of(context).go('/update-password');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Update Password'), findsOneWidget);
|
|
});
|
|
});
|
|
} |