m3mo b7ccbe6a19 Add widget tests for SetupPage
Tests for UI elements display, ViewModel behavior,
and mode card interactions.
2026-02-03 19:46:49 +01:00

226 lines
6.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:agenda_tasks/l10n/app_localizations.dart';
import 'package:agenda_tasks/features/onboarding/presentation/pages/setup_page.dart';
import 'package:agenda_tasks/features/settings/presentation/viewmodels/settings_viewmodel.dart';
import 'package:agenda_tasks/features/settings/domain/enums/app_mode.dart';
import 'package:agenda_tasks/features/settings/data/settings_local_datasource.dart';
import 'package:agenda_tasks/core/logging/app_logger.dart';
// Manual mock for SettingsLocalDataSource
class MockSettingsLocalDataSource implements SettingsLocalDataSource {
AppMode? _appMode;
bool _setupCompleted = false;
bool _onboardingShown = false;
Locale? _locale;
ThemeMode _themeMode = ThemeMode.system;
@override
AppMode? getAppMode() => _appMode;
@override
Future<void> setAppMode(AppMode mode) async {
_appMode = mode;
}
@override
bool isSetupCompleted() => _setupCompleted;
@override
Future<void> setSetupCompleted(bool completed) async {
_setupCompleted = completed;
}
@override
bool isOnboardingShown() => _onboardingShown;
@override
Future<void> setOnboardingShown(bool shown) async {
_onboardingShown = shown;
}
@override
Locale? getLocale() => _locale;
@override
Future<void> setLocale(Locale locale) async {
_locale = locale;
}
@override
ThemeMode getThemeMode() => _themeMode;
@override
Future<void> setThemeMode(ThemeMode mode) async {
_themeMode = mode;
}
}
// Manual mock for AppLogger
class MockAppLogger extends AppLogger {
@override
void debug(String message, [dynamic error, StackTrace? stackTrace]) {}
@override
void info(String message, [dynamic error, StackTrace? stackTrace]) {}
@override
void warning(String message, [dynamic error, StackTrace? stackTrace]) {}
@override
void error(String message, [dynamic error, StackTrace? stackTrace]) {}
@override
void verbose(String message, [dynamic error, StackTrace? stackTrace]) {}
}
void main() {
group('SetupPage', () {
late SettingsViewModel settingsViewModel;
late MockSettingsLocalDataSource mockDataSource;
late MockAppLogger mockLogger;
setUp(() {
mockDataSource = MockSettingsLocalDataSource();
mockLogger = MockAppLogger();
settingsViewModel = SettingsViewModel(
dataSource: mockDataSource,
logger: mockLogger,
);
});
Widget buildSetupPage() {
final router = GoRouter(
initialLocation: '/setup',
routes: [
GoRoute(
path: '/setup',
builder: (context, state) => const SetupPage(),
),
GoRoute(
path: '/onboarding',
builder: (context, state) => const Scaffold(
body: Center(child: Text('Onboarding Page')),
),
),
],
);
return ChangeNotifierProvider<SettingsViewModel>.value(
value: settingsViewModel,
child: MaterialApp.router(
routerConfig: router,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('de'),
],
locale: const Locale('en'),
),
);
}
testWidgets('should display setup title', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.text('Welcome to Agenda Tasks'), findsOneWidget);
});
testWidgets('should display setup subtitle', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.text('Choose how you want to use the app'), findsOneWidget);
});
testWidgets('should display app icon', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.byIcon(Icons.task_alt), findsOneWidget);
});
testWidgets('should display local mode option', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.text('Use Locally'), findsOneWidget);
expect(find.text('Keep tasks on this device only. No account needed.'), findsOneWidget);
expect(find.byIcon(Icons.smartphone), findsOneWidget);
});
testWidgets('should display online mode option', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.text('Sync Online'), findsOneWidget);
expect(find.text('Create an account to sync across devices.'), findsOneWidget);
expect(find.byIcon(Icons.cloud_sync), findsOneWidget);
});
// Test ViewModel behavior directly since widget tests with navigation
// cause timing issues with widget disposal
test('ViewModel should set app mode to local correctly', () async {
await settingsViewModel.setAppMode(AppMode.local);
expect(settingsViewModel.appMode, AppMode.local);
});
test('ViewModel should set setup completed correctly', () async {
await settingsViewModel.setSetupCompleted(true);
expect(settingsViewModel.setupCompleted, true);
});
test('ViewModel should set app mode to online correctly', () async {
await settingsViewModel.setAppMode(AppMode.online);
expect(settingsViewModel.appMode, AppMode.online);
});
testWidgets('should have tappable local mode card', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
// Verify the InkWell is present and tappable
final localCard = find.ancestor(
of: find.text('Use Locally'),
matching: find.byType(InkWell),
);
expect(localCard, findsOneWidget);
});
testWidgets('should have tappable online mode card', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
final onlineCard = find.ancestor(
of: find.text('Sync Online'),
matching: find.byType(InkWell),
);
expect(onlineCard, findsOneWidget);
});
testWidgets('should display two mode cards', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.byType(Card), findsNWidgets(2));
});
testWidgets('should have arrow icons on mode cards', (tester) async {
await tester.pumpWidget(buildSetupPage());
await tester.pumpAndSettle();
expect(find.byIcon(Icons.arrow_forward_ios), findsNWidgets(2));
});
});
}