AgendaTasks/test/features/tasks/presentation/viewmodels/daily_tasks_viewmodel_test.dart
m3mo 8c02dae118 Add unit tests for DailyTasksViewModel
- Test loading tasks with success and error states
- Test priority sorting (high > medium > low)
- Test filter functionality (all, active, completed)
- Test task toggle and delete operations
- Test date navigation (previousDay, nextDay)
- Use mocktail for repository mocking
2026-02-04 14:40:19 +01:00

261 lines
8.2 KiB
Dart

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<TaskEntity> 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<NetworkFailure>());
});
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<ServerFailure>());
});
});
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));
});
});
});
}