import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:ignis_app/app/load_state.dart'; import 'package:ignis_app/providers/providers.dart'; import 'package:ignis_app/services/api_client.dart'; class FakeIgnisApi extends IgnisApi { Object? statsData; Object? eventLogData; Object? statsError; Object? eventLogError; int? requestedDays; int? requestedLimit; FakeIgnisApi({this.statsData, this.eventLogData}); @override Future getStatsSummary({int days = 7}) async { requestedDays = days; final error = statsError; if (error != null) throw error; return Response( requestOptions: RequestOptions(path: '/stats/summary'), data: statsData, ); } @override Future getStatsLog({int limit = 100}) async { requestedLimit = limit; final error = eventLogError; if (error != null) throw error; return Response( requestOptions: RequestOptions(path: '/stats/log'), data: eventLogData, ); } } void main() { ProviderContainer containerWith(FakeIgnisApi api) { final container = ProviderContainer( overrides: [apiProvider.overrideWithValue(api)], ); addTearDown(container.dispose); return container; } test('stats load exposes data state', () async { final api = FakeIgnisApi( statsData: { 'groups': [ {'id': 'kitchen', 'total_commands': 3}, ], }, ); final container = containerWith(api); await container.read(statsProvider.notifier).load(days: 14); final state = container.read(statsProvider); expect(state.status, LoadStatus.data); expect(state.data['groups'], hasLength(1)); expect(api.requestedDays, 14); }); test('stats load exposes empty state for empty groups', () async { final api = FakeIgnisApi(statsData: {'groups': []}); final container = containerWith(api); await container.read(statsProvider.notifier).load(); final state = container.read(statsProvider); expect(state.status, LoadStatus.empty); expect(state.data['groups'], isEmpty); }); test('event log load accepts map response and exposes data state', () async { final api = FakeIgnisApi( eventLogData: { 'events': [ {'action': 'toggle', 'target_id': 'kitchen'}, ], }, ); final container = containerWith(api); await container.read(eventLogProvider.notifier).load(limit: 50); final state = container.read(eventLogProvider); expect(state.status, LoadStatus.data); expect(state.data, hasLength(1)); expect(api.requestedLimit, 50); }); test('load error keeps previous stats data and exposes message', () async { final api = FakeIgnisApi( statsData: { 'groups': [ {'id': 'kitchen'}, ], }, ); final container = containerWith(api); await container.read(statsProvider.notifier).load(); api.statsError = DioException( requestOptions: RequestOptions(path: '/stats/summary'), type: DioExceptionType.connectionError, message: 'No route to host', ); await container.read(statsProvider.notifier).load(); final state = container.read(statsProvider); expect(state.status, LoadStatus.error); expect(state.data['groups'], hasLength(1)); expect(state.errorMessage, contains('Backend недоступен')); }); }