From 45b2842e5a7acfa0b76cc94f33504c26f04cccb7 Mon Sep 17 00:00:00 2001 From: JulianAlcala Date: Sun, 26 Apr 2026 08:29:17 +0200 Subject: [PATCH] test(app-usage-schedules): add controller and editor unit tests (6 cases) --- .../app_usage_schedules_controller_test.dart | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 modules/legacy/modules/device_management/test/features/app_usage_schedules/app_usage_schedules_controller_test.dart diff --git a/modules/legacy/modules/device_management/test/features/app_usage_schedules/app_usage_schedules_controller_test.dart b/modules/legacy/modules/device_management/test/features/app_usage_schedules/app_usage_schedules_controller_test.dart new file mode 100644 index 00000000..f883370d --- /dev/null +++ b/modules/legacy/modules/device_management/test/features/app_usage_schedules/app_usage_schedules_controller_test.dart @@ -0,0 +1,162 @@ +import 'package:device_management/src/core/domain/entities/app_usage_schedule_entity.dart'; +import 'package:device_management/src/core/domain/repositories/app_usage_schedules_repository.dart'; +import 'package:device_management/src/core/providers/app_usage_schedules_repository_provider.dart'; +import 'package:device_management/src/features/app_usage_schedules/presentation/providers/app_usage_schedules_controller.dart'; +import 'package:device_management/src/features/app_usage_schedules/presentation/providers/app_usage_schedules_editor_provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:sf_shared/testing.dart'; + +class MockAppUsageSchedulesRepository extends Mock + implements AppUsageSchedulesRepository {} + +const _period = AppUsageSchedulePeriodEntity( + periodStart: '08:00', + periodEnd: '12:00', + isPeriodEnabled: true, +); + +const _period2 = AppUsageSchedulePeriodEntity( + periodStart: '14:00', + periodEnd: '18:00', + isPeriodEnabled: false, +); + +void main() { + setUpAll(() { + registerFallbackValue(const []); + }); + + ProviderContainer buildContainer(AppUsageSchedulesRepository repo) { + return makeContainer( + overrides: [ + appUsageSchedulesRepositoryProvider.overrideWithValue(repo), + ], + ); + } + + group('AppUsageSchedulesController.save', () { + test('persists periods and transitions to AsyncData', () async { + final repo = MockAppUsageSchedulesRepository(); + when( + () => repo.upsertSchedules( + identificator: any(named: 'identificator'), + periods: any(named: 'periods'), + ), + ).thenAnswer((_) async => const [_period]); + + final container = buildContainer(repo); + addTearDown(container.dispose); + + await container + .read(appUsageSchedulesControllerProvider.notifier) + .save(identificator: 'imei-1', periods: const [_period]); + + expect( + container.read(appUsageSchedulesControllerProvider), + isA>(), + ); + verify( + () => repo.upsertSchedules( + identificator: 'imei-1', + periods: const [_period], + ), + ).called(1); + }); + + test('exposes AsyncError when repository fails', () async { + final repo = MockAppUsageSchedulesRepository(); + when( + () => repo.upsertSchedules( + identificator: any(named: 'identificator'), + periods: any(named: 'periods'), + ), + ).thenThrow(Exception('boom')); + + final container = buildContainer(repo); + addTearDown(container.dispose); + + await container + .read(appUsageSchedulesControllerProvider.notifier) + .save(identificator: 'imei-1', periods: const [_period]); + + expect( + container.read(appUsageSchedulesControllerProvider), + isA>(), + ); + }); + }); + + group('AppUsageSchedulesEditor', () { + test('init sets periods', () { + final container = makeContainer(); + addTearDown(container.dispose); + + expect(container.read(appUsageSchedulesEditorProvider), isNull); + + container + .read(appUsageSchedulesEditorProvider.notifier) + .init(const [_period]); + + expect( + container.read(appUsageSchedulesEditorProvider), + equals(const [_period]), + ); + }); + + test('add appends period', () { + final container = makeContainer(); + addTearDown(container.dispose); + + container + .read(appUsageSchedulesEditorProvider.notifier) + .init(const [_period]); + + container + .read(appUsageSchedulesEditorProvider.notifier) + .add(_period2); + + expect( + container.read(appUsageSchedulesEditorProvider), + equals(const [_period, _period2]), + ); + }); + + test('replace updates period at index', () { + final container = makeContainer(); + addTearDown(container.dispose); + + container + .read(appUsageSchedulesEditorProvider.notifier) + .init(const [_period, _period2]); + + const replacement = AppUsageSchedulePeriodEntity( + periodStart: '10:00', + periodEnd: '16:00', + isPeriodEnabled: true, + ); + container + .read(appUsageSchedulesEditorProvider.notifier) + .replace(0, replacement); + + expect( + container.read(appUsageSchedulesEditorProvider), + equals(const [replacement, _period2]), + ); + }); + + test('clear resets to null', () { + final container = makeContainer(); + addTearDown(container.dispose); + + container + .read(appUsageSchedulesEditorProvider.notifier) + .init(const [_period]); + + container.read(appUsageSchedulesEditorProvider.notifier).clear(); + + expect(container.read(appUsageSchedulesEditorProvider), isNull); + }); + }); +}