import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ignis_app/features/homes/providers/homes_providers.dart'; import 'package:ignis_app/features/provisioning/models/wiz_provisioning_device.dart'; import 'package:ignis_app/features/provisioning/models/wiz_provisioning_environment.dart'; import 'package:ignis_app/features/provisioning/models/wiz_provisioning_failure.dart'; import 'package:ignis_app/features/provisioning/models/wiz_provisioning_state.dart'; import 'package:ignis_app/features/provisioning/models/wiz_provisioning_timing.dart'; import 'package:ignis_app/features/provisioning/providers/wiz_provisioning_providers.dart'; import 'package:ignis_app/features/provisioning/services/wiz_provisioning_platform_service.dart'; import 'package:ignis_app/features/provisioning/services/wiz_smart_pairing_service.dart'; import 'package:ignis_app/features/shared/providers/core_providers.dart'; import 'package:ignis_app/models/home_config.dart'; import 'test_support.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); test('initialize reports missing active home', () async { final container = ProviderContainer( overrides: [ wizProvisioningPlatformServiceProvider.overrideWithValue( FakeWizProvisioningPlatformService(environment: _readyEnvironment()), ), ], ); addTearDown(container.dispose); await container.read(wizProvisioningProvider.notifier).initialize(); final state = container.read(wizProvisioningProvider); expect(state.status, WizProvisioningStatus.failure); expect(state.failure?.kind, WizProvisioningFailureKind.noActiveHome); }); test( 'initialize asks for permissions when Wi-Fi access is not granted', () async { final home = HomeConfig(id: 'home-1', name: 'Дом', url: 'https://ignis'); final container = ProviderContainer( overrides: [ currentHomeProvider.overrideWith(() => FakeCurrentHomeNotifier(home)), wizProvisioningPlatformServiceProvider.overrideWithValue( FakeWizProvisioningPlatformService( environment: _readyEnvironment( permissionStatus: WizProvisioningPermissionStatus.requestable, connectedToWifi: false, ssid: null, bssid: null, frequencyMhz: null, ), ), ), ], ); addTearDown(container.dispose); await container.read(wizProvisioningProvider.notifier).initialize(); final state = container.read(wizProvisioningProvider); expect(state.status, WizProvisioningStatus.attentionRequired); expect( state.failure?.kind, WizProvisioningFailureKind.missingPermissions, ); }, ); test('successful smart pairing ends with rescan success', () async { final home = HomeConfig(id: 'home-1', name: 'Дом', url: 'https://ignis'); final api = FakeIgnisApi() ..rescanNetworkData = { 'status': 'ok', 'found': 1, 'added': 1, 'updated': 0, 'removed_offline': 0, 'pending_removal': 0, 'online': 1, }; final smartPairing = FakeWizSmartPairingService( streamFactory: () { final controller = StreamController(); Future.microtask(() { controller.add( const WizProvisioningDevice( bssid: 'aa:bb:cc:dd:ee:ff', ipAddress: '192.168.1.44', ), ); }); return controller.stream; }, ); final container = ProviderContainer( overrides: [ currentHomeProvider.overrideWith(() => FakeCurrentHomeNotifier(home)), apiProvider.overrideWithValue(api), wizProvisioningPlatformServiceProvider.overrideWithValue( FakeWizProvisioningPlatformService(environment: _readyEnvironment()), ), wizSmartPairingServiceProvider.overrideWithValue(smartPairing), wizProvisioningTimingProvider.overrideWithValue( const WizProvisioningTiming( provisioningTimeout: Duration(milliseconds: 200), settleAfterFirstResponse: Duration.zero, initialRescanDelay: Duration.zero, retryRescanDelay: Duration.zero, maxRescanAttempts: 1, ), ), ], ); addTearDown(container.dispose); await container.read(wizProvisioningProvider.notifier).initialize(); await container .read(wizProvisioningProvider.notifier) .startProvisioning( ssid: 'Home-2G', password: 'secret', bssid: '11:22:33:44:55:66', ); final state = container.read(wizProvisioningProvider); expect(state.status, WizProvisioningStatus.success); expect(state.provisionedDevices, hasLength(1)); expect(state.rescanSummary?.added, 1); expect(api.rescanCalls, 1); }); } class FakeCurrentHomeNotifier extends CurrentHomeNotifier { FakeCurrentHomeNotifier(this._home); final HomeConfig? _home; @override HomeConfig? build() => _home; } class FakeWizProvisioningPlatformService implements WizProvisioningPlatformService { FakeWizProvisioningPlatformService({required this.environment}); final WizProvisioningEnvironment environment; int requestCalls = 0; int openWifiSettingsCalls = 0; int openAppSettingsCalls = 0; @override Future inspectEnvironment() async => environment; @override Future requestPermissions() async { requestCalls += 1; } @override Future openAppSettings() async { openAppSettingsCalls += 1; } @override Future openWifiSettings() async { openWifiSettingsCalls += 1; } } class FakeWizSmartPairingService implements WizSmartPairingService { FakeWizSmartPairingService({required this.streamFactory}); final Stream Function() streamFactory; int startCalls = 0; int stopCalls = 0; @override Stream startProvisioning({ required String ssid, required String password, String? bssid, }) { startCalls += 1; return streamFactory(); } @override Future stopProvisioning() async { stopCalls += 1; } } WizProvisioningEnvironment _readyEnvironment({ WizProvisioningPermissionStatus permissionStatus = WizProvisioningPermissionStatus.granted, bool connectedToWifi = true, bool locationServicesEnabled = true, String? ssid = 'Home-2G', String? bssid = '11:22:33:44:55:66', int? frequencyMhz = 2437, }) { return WizProvisioningEnvironment( platform: 'android', androidApiLevel: 35, smartPairingSupported: true, wifiSettingsSupported: true, appSettingsSupported: true, permissionStatus: permissionStatus, locationServicesEnabled: locationServicesEnabled, connectedToWifi: connectedToWifi, ssid: ssid, bssid: bssid, frequencyMhz: frequencyMhz, ); }