- Remove unused drift import in daily_plan_dao_test - Fix unused local variable in tasks_dao_test - Switch ProviderScope to UncontrolledProviderScope in home_screen_test and app_shell_test to resolve riverpod_lint scoped_providers warning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
254 lines
7.7 KiB
Dart
254 lines
7.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:household_keeper/core/database/database.dart';
|
|
import 'package:household_keeper/core/router/router.dart';
|
|
import 'package:household_keeper/features/home/domain/daily_plan_models.dart';
|
|
import 'package:household_keeper/features/home/presentation/daily_plan_providers.dart';
|
|
import 'package:household_keeper/features/rooms/presentation/room_providers.dart';
|
|
import 'package:household_keeper/features/tasks/domain/effort_level.dart';
|
|
import 'package:household_keeper/features/tasks/domain/frequency.dart';
|
|
import 'package:household_keeper/l10n/app_localizations.dart';
|
|
|
|
/// Helper to create a test [Task] with sensible defaults.
|
|
Task _makeTask({
|
|
int id = 1,
|
|
int roomId = 1,
|
|
String name = 'Test Task',
|
|
required DateTime nextDueDate,
|
|
}) {
|
|
return Task(
|
|
id: id,
|
|
roomId: roomId,
|
|
name: name,
|
|
intervalType: IntervalType.weekly,
|
|
intervalDays: 7,
|
|
effortLevel: EffortLevel.medium,
|
|
nextDueDate: nextDueDate,
|
|
createdAt: DateTime(2026, 1, 1),
|
|
);
|
|
}
|
|
|
|
/// Helper to create a [TaskWithRoom].
|
|
TaskWithRoom _makeTaskWithRoom({
|
|
int id = 1,
|
|
int roomId = 1,
|
|
String taskName = 'Test Task',
|
|
String roomName = 'Kueche',
|
|
required DateTime nextDueDate,
|
|
}) {
|
|
return TaskWithRoom(
|
|
task: _makeTask(
|
|
id: id,
|
|
roomId: roomId,
|
|
name: taskName,
|
|
nextDueDate: nextDueDate,
|
|
),
|
|
roomName: roomName,
|
|
roomId: roomId,
|
|
);
|
|
}
|
|
|
|
/// Build the app with dailyPlanProvider overridden to the given state.
|
|
///
|
|
/// Uses [UncontrolledProviderScope] with a [ProviderContainer] to avoid
|
|
/// the riverpod_lint scoped_providers_should_specify_dependencies warning.
|
|
Widget _buildApp(DailyPlanState planState) {
|
|
final container = ProviderContainer(overrides: [
|
|
dailyPlanProvider.overrideWith(
|
|
(ref) => Stream.value(planState),
|
|
),
|
|
roomWithStatsListProvider.overrideWith(
|
|
(ref) => Stream.value([]),
|
|
),
|
|
]);
|
|
|
|
return UncontrolledProviderScope(
|
|
container: container,
|
|
child: MaterialApp.router(
|
|
routerConfig: router,
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: const [Locale('de')],
|
|
locale: const Locale('de'),
|
|
),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
setUp(() {
|
|
SharedPreferences.setMockInitialValues({});
|
|
});
|
|
|
|
group('HomeScreen empty states', () {
|
|
testWidgets('shows no-tasks empty state when no tasks exist at all',
|
|
(tester) async {
|
|
await tester.pumpWidget(_buildApp(const DailyPlanState(
|
|
overdueTasks: [],
|
|
todayTasks: [],
|
|
tomorrowTasks: [],
|
|
completedTodayCount: 0,
|
|
totalTodayCount: 0,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should show "Noch keine Aufgaben angelegt" (dailyPlanNoTasks)
|
|
expect(find.text('Noch keine Aufgaben angelegt'), findsOneWidget);
|
|
// Should show action button to create a room
|
|
expect(find.text('Raum erstellen'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('shows all-clear state when all tasks are done',
|
|
(tester) async {
|
|
await tester.pumpWidget(_buildApp(const DailyPlanState(
|
|
overdueTasks: [],
|
|
todayTasks: [],
|
|
tomorrowTasks: [],
|
|
completedTodayCount: 3,
|
|
totalTodayCount: 3,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should show celebration empty state
|
|
expect(find.text('Alles erledigt! \u{1F31F}'), findsOneWidget);
|
|
expect(find.byIcon(Icons.celebration_outlined), findsOneWidget);
|
|
// Progress card should show 3/3
|
|
expect(find.text('3 von 3 erledigt'), findsOneWidget);
|
|
});
|
|
});
|
|
|
|
group('HomeScreen normal state', () {
|
|
testWidgets('shows progress card with correct counts', (tester) async {
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
|
|
await tester.pumpWidget(_buildApp(DailyPlanState(
|
|
overdueTasks: [],
|
|
todayTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 1,
|
|
taskName: 'Staubsaugen',
|
|
roomName: 'Wohnzimmer',
|
|
nextDueDate: today,
|
|
),
|
|
],
|
|
tomorrowTasks: [],
|
|
completedTodayCount: 2,
|
|
totalTodayCount: 3,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Progress card should show 2/3
|
|
expect(find.text('2 von 3 erledigt'), findsOneWidget);
|
|
expect(find.byType(LinearProgressIndicator), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('shows overdue section when overdue tasks exist',
|
|
(tester) async {
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
final yesterday = today.subtract(const Duration(days: 1));
|
|
|
|
await tester.pumpWidget(_buildApp(DailyPlanState(
|
|
overdueTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 1,
|
|
taskName: 'Boden wischen',
|
|
roomName: 'Kueche',
|
|
nextDueDate: yesterday,
|
|
),
|
|
],
|
|
todayTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 2,
|
|
taskName: 'Staubsaugen',
|
|
roomName: 'Wohnzimmer',
|
|
nextDueDate: today,
|
|
),
|
|
],
|
|
tomorrowTasks: [],
|
|
completedTodayCount: 0,
|
|
totalTodayCount: 2,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should show overdue section header
|
|
expect(find.text('\u00dcberf\u00e4llig'), findsOneWidget);
|
|
// Should show today section header (may also appear as relative date)
|
|
expect(find.text('Heute'), findsAtLeast(1));
|
|
// Should show both tasks
|
|
expect(find.text('Boden wischen'), findsOneWidget);
|
|
expect(find.text('Staubsaugen'), findsOneWidget);
|
|
// Should show room name tags
|
|
expect(find.text('Kueche'), findsOneWidget);
|
|
expect(find.text('Wohnzimmer'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('shows collapsed tomorrow section with count',
|
|
(tester) async {
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
final tomorrow = today.add(const Duration(days: 1));
|
|
|
|
await tester.pumpWidget(_buildApp(DailyPlanState(
|
|
overdueTasks: [],
|
|
todayTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 1,
|
|
taskName: 'Staubsaugen',
|
|
roomName: 'Wohnzimmer',
|
|
nextDueDate: today,
|
|
),
|
|
],
|
|
tomorrowTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 2,
|
|
taskName: 'Fenster putzen',
|
|
roomName: 'Schlafzimmer',
|
|
nextDueDate: tomorrow,
|
|
),
|
|
_makeTaskWithRoom(
|
|
id: 3,
|
|
taskName: 'Bett beziehen',
|
|
roomName: 'Schlafzimmer',
|
|
nextDueDate: tomorrow,
|
|
),
|
|
],
|
|
completedTodayCount: 0,
|
|
totalTodayCount: 1,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Should show collapsed tomorrow section with count
|
|
expect(find.text('Demn\u00e4chst (2)'), findsOneWidget);
|
|
// Tomorrow tasks should NOT be visible (collapsed by default)
|
|
expect(find.text('Fenster putzen'), findsNothing);
|
|
});
|
|
|
|
testWidgets('today tasks have checkboxes', (tester) async {
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
|
|
await tester.pumpWidget(_buildApp(DailyPlanState(
|
|
overdueTasks: [],
|
|
todayTasks: [
|
|
_makeTaskWithRoom(
|
|
id: 1,
|
|
taskName: 'Staubsaugen',
|
|
roomName: 'Wohnzimmer',
|
|
nextDueDate: today,
|
|
),
|
|
],
|
|
tomorrowTasks: [],
|
|
completedTodayCount: 0,
|
|
totalTodayCount: 1,
|
|
)));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Today task should have a checkbox
|
|
expect(find.byType(Checkbox), findsOneWidget);
|
|
});
|
|
});
|
|
}
|