import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:sxchnge_analytics/sxchnge_analytics.dart'; import 'package:sxchnge_auth/sxchnge_auth.dart'; import 'package:sxchnge_app/main.dart'; import 'package:sxchnge_app/providers/locale.dart'; class DeliveryBackend extends BackendAuthServices { DeliveryBackend(List requests) : super( baseUri: Uri.parse('https://api.example/api/v1'), clientId: 'web', client: MockClient((request) async { requests.add(request.url.path); return http.Response( jsonEncode({ 'data': request.url.path.endsWith('/signup') ? {'userId': 'customer'} : {'accepted': true}, }), 202, ); }), ); int sends = 0; bool failResend = true; @override Future send({ required String email, required String locale, }) async { sends++; if (failResend) { throw const VerificationException(VerificationError.internal); } return super.send(email: email, locale: locale); } } void main() { for (final language in ['en', 'ru']) { testWidgets( 'accepted signup survives an unavailable resend service ($language)', (tester) async { tester.view.physicalSize = const Size(390, 844); tester.view.devicePixelRatio = 1; tester.platformDispatcher.textScaleFactorTestValue = 1.5; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue); final requests = []; final backend = DeliveryBackend(requests); final analytics = DummyAnalyticsService(); await tester.pumpWidget( SxchngeApp( backend: backend, analyticsService: analytics, localeProvider: LocaleProvider(initialLocale: Locale(language)), ), ); await tester.pumpAndSettle(); final signup = find.text(language == 'ru' ? 'Регистрация' : 'Sign up'); await tester.ensureVisible(signup); await tester.tap(signup); await tester.pumpAndSettle(); for (final entry in { 'name': 'Ada Lovelace', 'email': 'ada@example.com', 'password': 'password preserved', 'confirmation': 'password preserved', }.entries) { await tester.enterText(find.byKey(ValueKey(entry.key)), entry.value); } final submit = find.byKey(const ValueKey('submit')); await tester.ensureVisible(submit); await tester.tap(submit); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('verification-sent')), findsOneWidget); expect(find.text('ada@example.com'), findsOneWidget); expect(backend.sends, 0); expect(requests, ['/api/v1/accounts/signup']); final router = GoRouter.of(tester.element(find.byType(Scaffold))); final restored = router.routeInformationParser.restoreRouteInformation( router.routerDelegate.currentConfiguration, )!; expect(restored.uri.toString(), '/verification-sent'); expect(restored.state.toString(), isNot(contains('ada@example.com'))); expect( analytics.events.where( (event) => event.name == 'auth_signup_succeeded', ), hasLength(1), ); expect( analytics.events.where( (event) => event.name == 'auth_email_delivery_succeeded', ), hasLength(1), ); final resend = find.byKey(const ValueKey('verification-resend')); await tester.ensureVisible(resend); await tester.tap(resend); await tester.pumpAndSettle(); expect( find.byKey(const ValueKey('verification-error')), findsOneWidget, ); expect(backend.sends, 1); expect( tester .widget( find.byKey(const ValueKey('verification-email')), ) .controller! .text, 'ada@example.com', ); backend.failResend = false; await tester.ensureVisible(resend); await tester.tap(resend); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('verification-sent')), findsOneWidget); expect(backend.sends, 2); expect(requests.last, '/api/v1/accounts/verification/send'); expect(requests, hasLength(2)); expect( analytics.events.map((event) => event.journeyId).toSet(), hasLength(1), ); expect( analytics.events.map((event) => event.properties).toString(), isNot(contains('ada@example.com')), ); expect(tester.takeException(), isNull); }, ); } }