import 'package:eatvio_app/features/payment/services/sbp_service.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:sbp/models/c2bmembers_model.dart'; /// Тесты реализации [SbpServiceImpl] — обёртки над статичным классом [Sbp]. /// /// Поскольку unit-тесты исполняются на хост-машине (не iOS), срабатывает /// Android-ветка плагина: `getInstalledBanks` возвращает список банков через /// `package_name`, а `openBank` подставляет схему банка в начало checkout_url. void main() { TestWidgetsFlutterBinding.ensureInitialized(); const channel = MethodChannel('sbp'); /// Банк-фикстура: Сбербанк (присутствует в справочнике c2bmembersData пакета). final sberbank = C2bmemberModel.fromJson(const { 'bankName': 'Сбербанк', 'logoURL': 'https://qr.nspk.ru/proxyapp/logo/bank100000000111.png', 'schema': 'bank100000000111', 'package_name': 'ru.sberbankmobile', 'icon': 'packages/sbp/assets/icons/sber.png', }); late SbpService sbpService; setUp(() { sbpService = const SbpServiceImpl(); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, null); }); group('SbpServiceImpl.getInstalledBanks', () { test('возвращает список банков, установленных на устройстве (Android)', () async { // Плагин (Android) возвращает список установленных банков в формате // {name, bitmap, package_name}; обёртка сопоставляет со справочником. TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall call) async { return [ {'name': 'Сбербанк', 'bitmap': null, 'package_name': 'ru.sberbankmobile'}, ]; }); final result = await sbpService.getInstalledBanks(); expect(result, isNotEmpty); expect( result.any( (bank) => bank.bankName == 'Сбербанк' && bank.packageName == 'ru.sberbankmobile', ), isTrue, ); }); test('возвращает пустой список, если нет установленных банков', () async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall call) async { return >[]; }); final result = await sbpService.getInstalledBanks(); expect(result, isEmpty); }); test('пробрасывает ошибку плагина при отсутствии нативного обработчика', () async { // Обработчик не зарегистрирован → invokeMethod выбрасывает // MissingPluginException. Сервис должен пробросить её наверх. expect( sbpService.getInstalledBanks(), throwsA(isA()), ); }); }); group('SbpServiceImpl.openBank', () { test('вызывает нативный openBank с подстановкой схемы банка в url и возвращает true', () async { const checkoutUrl = 'https://qr.nspk.ru/ASDFASDFASDFASDF'; String? receivedUrl; String? receivedPackageName; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall call) async { if (call.method == 'openBank') { final args = call.arguments as Map; receivedUrl = args['url'] as String?; receivedPackageName = args['package_name'] as String?; return true; } return null; }); final result = await sbpService.openBank(url: checkoutUrl, bank: sberbank); expect(result, isTrue); // Android-ветка заменяет схему "https" на schema банка в начале url. expect(receivedUrl, 'bank100000000111://qr.nspk.ru/ASDFASDFASDFASDF'); expect(receivedPackageName, 'ru.sberbankmobile'); }); test('возвращает false при неудачном запуске банковского приложения', () async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(channel, (MethodCall call) async { return false; }); final result = await sbpService.openBank( url: 'https://qr.nspk.ru/ASDFASDFASDFASDF', bank: sberbank, ); expect(result, isFalse); }); }); }