import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:agenda_tasks/core/errors/failures.dart'; import 'package:agenda_tasks/core/errors/result.dart'; import 'package:agenda_tasks/core/logging/app_logger.dart'; import 'package:agenda_tasks/features/tasks/domain/entities/task_entity.dart'; import 'package:agenda_tasks/features/tasks/domain/enums/priority.dart'; import 'package:agenda_tasks/features/tasks/domain/repositories/task_repository.dart'; import 'package:agenda_tasks/features/tasks/presentation/viewmodels/daily_tasks_viewmodel.dart'; // Mock classes class MockTaskRepository extends Mock implements TaskRepository {} class MockAppLogger extends Mock implements AppLogger {} void main() { late DailyTasksViewModel viewModel; late MockTaskRepository mockRepository; late MockAppLogger mockLogger; setUp(() { mockRepository = MockTaskRepository(); mockLogger = MockAppLogger(); viewModel = DailyTasksViewModel( repository: mockRepository, logger: mockLogger, ); }); group('DailyTasksViewModel', () { final testDate = DateTime(2024, 1, 15); // Helper function to create fresh test data for each test List createTestTasks() => [ TaskEntity( id: '1', title: 'Task 1', date: testDate, priority: Priority.high, isDone: false, ), TaskEntity( id: '2', title: 'Task 2', date: testDate, priority: Priority.medium, isDone: true, ), TaskEntity( id: '3', title: 'Task 3', date: testDate, priority: Priority.low, isDone: false, ), ]; group('loadTasks', () { test('should set status to loading then success when tasks loaded', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); // Act final future = viewModel.loadTasks(); // Assert - initial state should be loading expect(viewModel.status, equals(TasksStatus.loading)); await future; // After completion expect(viewModel.status, equals(TasksStatus.success)); expect(viewModel.tasks.length, equals(3)); }); test('should set status to error when loading fails', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Error(const NetworkFailure())); // Act await viewModel.loadTasks(); // Assert expect(viewModel.status, equals(TasksStatus.error)); expect(viewModel.failure, isA()); }); test('should sort tasks by priority (high > medium > low)', () async { // Arrange final unsortedTasks = [ TaskEntity(id: '1', title: 'Low', date: testDate, priority: Priority.low, isDone: false), TaskEntity(id: '2', title: 'High', date: testDate, priority: Priority.high, isDone: false), TaskEntity(id: '3', title: 'Medium', date: testDate, priority: Priority.medium, isDone: false), ]; when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(unsortedTasks)); // Act await viewModel.loadTasks(); // Assert expect(viewModel.tasks[0].priority, equals(Priority.high)); expect(viewModel.tasks[1].priority, equals(Priority.medium)); expect(viewModel.tasks[2].priority, equals(Priority.low)); }); }); group('setFilter', () { setUp(() async { when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); await viewModel.loadTasks(); }); test('should show all tasks when filter is all', () { // Act viewModel.setFilter(TaskFilter.all); // Assert expect(viewModel.filter, equals(TaskFilter.all)); expect(viewModel.tasks.length, equals(3)); }); test('should show only active tasks when filter is active', () { // Act viewModel.setFilter(TaskFilter.active); // Assert expect(viewModel.filter, equals(TaskFilter.active)); expect(viewModel.tasks.length, equals(2)); expect(viewModel.tasks.every((t) => !t.isDone), isTrue); }); test('should show only completed tasks when filter is completed', () { // Act viewModel.setFilter(TaskFilter.completed); // Assert expect(viewModel.filter, equals(TaskFilter.completed)); expect(viewModel.tasks.length, equals(1)); expect(viewModel.tasks.every((t) => t.isDone), isTrue); }); }); group('toggleTask', () { test('should update task in list when toggle succeeds', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); await viewModel.loadTasks(); final toggledTask = createTestTasks()[0].copyWith(isDone: true); when(() => mockRepository.toggleTaskStatus('1')) .thenAnswer((_) async => Success(toggledTask)); // Act await viewModel.toggleTask('1'); // Assert final updatedTask = viewModel.tasks.firstWhere((t) => t.id == '1'); expect(updatedTask.isDone, isTrue); }); test('should set failure when toggle fails', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); await viewModel.loadTasks(); when(() => mockRepository.toggleTaskStatus('1')) .thenAnswer((_) async => Error(const ServerFailure(message: 'Error'))); // Act await viewModel.toggleTask('1'); // Assert expect(viewModel.failure, isA()); }); }); group('deleteTask', () { test('should remove task from list when delete succeeds', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); await viewModel.loadTasks(); when(() => mockRepository.deleteTask('1')) .thenAnswer((_) async => const Success(null)); // Act await viewModel.deleteTask('1'); // Assert expect(viewModel.tasks.any((t) => t.id == '1'), isFalse); expect(viewModel.totalCount, equals(2)); }); }); group('date navigation', () { test('should update selectedDate when setSelectedDate is called', () { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success([])); // Act viewModel.setSelectedDate(testDate); // Assert expect(viewModel.selectedDate.year, equals(2024)); expect(viewModel.selectedDate.month, equals(1)); expect(viewModel.selectedDate.day, equals(15)); }); test('previousDay should subtract one day', () { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success([])); viewModel.setSelectedDate(testDate); // Act viewModel.previousDay(); // Assert expect(viewModel.selectedDate.day, equals(14)); }); test('nextDay should add one day', () { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success([])); viewModel.setSelectedDate(testDate); // Act viewModel.nextDay(); // Assert expect(viewModel.selectedDate.day, equals(16)); }); }); group('counts', () { test('should return correct total and completed counts', () async { // Arrange when(() => mockRepository.getTasksByDate(any())) .thenAnswer((_) async => Success(createTestTasks())); // Act await viewModel.loadTasks(); // Assert expect(viewModel.totalCount, equals(3)); expect(viewModel.completedCount, equals(1)); }); }); }); }