import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:sxchnge_auth/sxchnge_auth.dart'; import 'package:sxchnge_app/main.dart'; import 'package:sxchnge_app/providers/locale.dart'; import 'package:sxchnge_app/routing/routes.dart'; import 'package:sxchnge_app/verification/page.dart'; class PendingConfirmation implements VerificationService { final results = >{}; @override Future confirm({required String token}) => (results[token] = Completer()).future; @override Future send({ required String email, required String locale, }) async => const VerificationResult(isSimulated: true); } Future openRoute( WidgetTester tester, String route, { VerificationService service = const DummyVerificationService( delay: Duration.zero, ), }) async { tester.platformDispatcher.defaultRouteNameTestValue = route; addTearDown(tester.platformDispatcher.clearDefaultRouteNameTestValue); await tester.pumpWidget(SxchngeApp(verificationService: service)); await tester.pump(); return GoRouter.of(tester.element(find.byType(Scaffold).last)); } void main() { testWidgets('unknown deep link redirects to canonical login URL', ( tester, ) async { final router = await openRoute(tester, '/unknown?token=private'); await tester.pumpAndSettle(); expect(router.routeInformationProvider.value.uri.toString(), '/'); expect(find.byKey(const ValueKey('email')), findsOneWidget); }); testWidgets( 'changing confirmation token ignores the previous pending result', (tester) async { final service = PendingConfirmation(); final router = await openRoute( tester, '/verify-email?token=first', service: service, ); await tester.pump(); expect(service.results.containsKey('first'), isTrue); router.goNamed( AppRoutes.verifyEmail, queryParameters: {'token': 'second'}, ); await tester.pump(); await tester.pump(); service.results['second']!.completeError( const VerificationException(VerificationError.expired), ); await tester.pumpAndSettle(); expect( find.byKey(const ValueKey('verification-expired')), findsOneWidget, ); service.results['first']!.complete( const VerificationResult(isSimulated: true), ); await tester.pumpAndSettle(); expect( find.byKey(const ValueKey('verification-expired')), findsOneWidget, ); expect(find.byKey(const ValueKey('verification-verified')), findsNothing); }, ); testWidgets( 'platform back and forward route updates recheck confirmation tokens', (tester) async { final router = await openRoute(tester, '/verify-email?token=demo-valid'); await tester.pumpAndSettle(); await router.routeInformationProvider.didPushRouteInformation( RouteInformation(uri: Uri.parse('/verify-email?token=demo-expired')), ); await tester.pumpAndSettle(); expect( find.byKey(const ValueKey('verification-expired')), findsOneWidget, ); await router.routeInformationProvider.didPushRouteInformation( RouteInformation(uri: Uri.parse('/verify-email?token=demo-valid')), ); await tester.pumpAndSettle(); expect( find.byKey(const ValueKey('verification-verified')), findsOneWidget, ); expect( router.routeInformationProvider.value.uri.queryParameters['token'], 'demo-valid', ); }, ); testWidgets('locale rebuild preserves router, URL and confirmation state', ( tester, ) async { final router = await openRoute(tester, '/verify-email?token=demo-valid'); await tester.pumpAndSettle(); final context = tester.element(find.byType(VerificationPage)); await context.read().setLocale(const Locale('ru')); await tester.pumpAndSettle(); expect( GoRouter.of(tester.element(find.byType(VerificationPage))), same(router), ); expect(find.byKey(const ValueKey('verification-verified')), findsOneWidget); expect(find.text('Ваша почта\nподтверждена.'), findsOneWidget); }); testWidgets( 'signup email stays in memory and is excluded from serialized history', (tester) async { final router = await openRoute(tester, '/'); await tester.pumpAndSettle(); router.goNamed(AppRoutes.verificationSent, extra: 'alex@example.com'); await tester.pumpAndSettle(); expect(find.text('alex@example.com'), findsOneWidget); expect(find.byKey(const ValueKey('verification-sent')), findsOneWidget); final restored = router.routeInformationParser.restoreRouteInformation( router.routerDelegate.currentConfiguration, )!; expect(restored.state.toString(), isNot(contains('alex@example.com'))); expect(restored.uri.toString(), '/verification-sent'); router.goNamed(AppRoutes.login); await tester.pumpAndSettle(); router.goNamed(AppRoutes.verificationSent); await tester.pumpAndSettle(); expect(find.text('alex@example.com'), findsNothing); expect(find.byKey(const ValueKey('verification-idle')), findsOneWidget); }, ); }