import 'package:eatvio_app/features/payment/models/promo_apply_response.dart'; import 'package:eatvio_app/features/payment/models/promo_code_model.dart'; import 'package:eatvio_app/features/payment/models/promo_validate_response.dart'; import 'package:eatvio_app/features/payment/presentation/payment_flow.dart'; import 'package:eatvio_app/features/payment/presentation/widgets/promo_code_modal.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); Widget createTestApp() { return const MaterialApp( localizationsDelegates: [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: [Locale('ru')], home: Scaffold(body: SizedBox()), ); } group('showConsultationPaymentFlow', () { late bool gateCalled; late bool? gateResult; late bool formCalled; late PromoCodeResult? formResult; late PromoCodeModel? formInitialPromo; late bool sbpCalled; late int sbpPlanId; late int validateCalls; late int applyCalls; late String? lastValidatedCode; late String? lastAppliedCode; late PromoValidateResponse validateResponse; late PromoApplyResponse applyResponse; late bool applyThrows; late PromoCodeModel? listAppliedResult; Future mockGate(BuildContext context) async { gateCalled = true; return gateResult; } Future mockForm( BuildContext context, { Future Function(String)? onValidate, Future Function()? onRemove, PromoCodeModel? initialPromo, }) async { formCalled = true; formInitialPromo = initialPromo; if (formResult?.hasPromoCode == true && !formResult!.alreadyApplied && onValidate != null) { final validation = await onValidate(formResult!.code!); if (!validation.isValid) { return null; } return PromoCodeResult( code: formResult!.code, discountPercent: validation.discountPercent, discountAmountRub: validation.discountAmountRub, originalAmountRub: validation.originalAmountRub, finalAmountRub: validation.finalAmountRub, ); } return formResult; } Future mockSbp(BuildContext context, {required int planId}) async { sbpCalled = true; sbpPlanId = planId; } Future mockValidate({ required int planId, required String promoCode, }) async { validateCalls++; lastValidatedCode = promoCode; return validateResponse; } Future mockApply({ required int planId, required String promoCode, }) async { applyCalls++; lastAppliedCode = promoCode; if (applyThrows) { throw Exception('network'); } return applyResponse; } Future mockListApplied(int planId) async { return listAppliedResult; } Future mockRemove(int planId) async { return true; } setUp(() { gateCalled = false; gateResult = null; formCalled = false; formResult = null; formInitialPromo = null; sbpCalled = false; sbpPlanId = 0; validateCalls = 0; applyCalls = 0; lastValidatedCode = null; lastAppliedCode = null; listAppliedResult = null; validateResponse = const PromoValidateResponse( valid: true, promoCode: 'TEST123', discountPercent: 5, discountAmountRub: 60, originalAmountRub: 1200, finalAmountRub: 1140, ); applyResponse = const PromoApplyResponse(success: true); applyThrows = false; }); Future runFlow(WidgetTester tester) { return showConsultationPaymentFlow( tester.element(find.byType(SizedBox)), planId: 42, showGate: mockGate, showForm: mockForm, showSbp: mockSbp, validatePromo: mockValidate, applyPromo: mockApply, listApplied: mockListApplied, removePromo: mockRemove, ); } testWidgets('Нет → вызывает SbpBanks (не форму)', (tester) async { gateResult = false; await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isTrue); expect(formCalled, isFalse); expect(sbpCalled, isTrue); expect(sbpPlanId, 42); expect(validateCalls, 0); expect(applyCalls, 0); }); testWidgets('Да → форма → Пропустить → вызывает SbpBanks', (tester) async { gateResult = true; formResult = const PromoCodeResult(); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isTrue); expect(formCalled, isTrue); expect(sbpCalled, isTrue); expect(sbpPlanId, 42); expect(applyCalls, 0); }); testWidgets('Да → форма отменена (null) → Sbp не вызывается', (tester) async { gateResult = true; formResult = null; await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isTrue); expect(formCalled, isTrue); expect(sbpCalled, isFalse); }); testWidgets('гейт отменён (null) → ничего не вызывается', (tester) async { gateResult = null; await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isTrue); expect(formCalled, isFalse); expect(sbpCalled, isFalse); }); testWidgets('Да → код → validate + apply → SbpBanks', (tester) async { gateResult = true; formResult = const PromoCodeResult(code: 'TEST123'); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(validateCalls, 1); expect(lastValidatedCode, 'TEST123'); expect(applyCalls, 1); expect(lastAppliedCode, 'TEST123'); expect(sbpCalled, isTrue); expect(sbpPlanId, 42); }); testWidgets('Да → код → apply fail → Sbp не вызывается', (tester) async { gateResult = true; formResult = const PromoCodeResult(code: 'BAD'); applyResponse = const PromoApplyResponse( success: false, error: 'Промокод уже использован', ); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(applyCalls, 1); expect(sbpCalled, isFalse); }); testWidgets('applied rehydrate → Continue → SBP без apply и без гейта', (tester) async { listAppliedResult = const PromoCodeModel( id: 1, chosenPlanId: 42, promoCode: 'SAVE5', discountPercent: 5, discountAmountRub: 60, state: 'applied', ); formResult = const PromoCodeResult( code: 'SAVE5', discountPercent: 5, discountAmountRub: 60, alreadyApplied: true, ); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isFalse); expect(formCalled, isTrue); expect(formInitialPromo?.promoCode, 'SAVE5'); expect(applyCalls, 0); expect(sbpCalled, isTrue); }); testWidgets('list пустой → идёт через гейт', (tester) async { listAppliedResult = null; gateResult = false; await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isTrue); expect(formCalled, isFalse); expect(sbpCalled, isTrue); }); testWidgets('rehydrate → Remove → новый код → apply → SBP', (tester) async { listAppliedResult = const PromoCodeModel( id: 1, chosenPlanId: 42, promoCode: 'OLD', discountPercent: 5, discountAmountRub: 60, state: 'applied', ); formResult = const PromoCodeResult(code: 'NEW123'); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isFalse); expect(formCalled, isTrue); expect(validateCalls, 1); expect(applyCalls, 1); expect(lastAppliedCode, 'NEW123'); expect(sbpCalled, isTrue); }); testWidgets('rehydrate → Remove → Skip → SBP без apply', (tester) async { listAppliedResult = const PromoCodeModel( id: 1, chosenPlanId: 42, promoCode: 'OLD', discountPercent: 5, discountAmountRub: 60, state: 'applied', ); formResult = const PromoCodeResult(); await tester.pumpWidget(createTestApp()); await runFlow(tester); expect(gateCalled, isFalse); expect(formCalled, isTrue); expect(applyCalls, 0); expect(sbpCalled, isTrue); }); }); }