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 setAppMode(AppMode mode) async { _appMode = mode; } @override bool isSetupCompleted() => _setupCompleted; @override Future setSetupCompleted(bool completed) async { _setupCompleted = completed; } @override bool isOnboardingShown() => _onboardingShown; @override Future setOnboardingShown(bool shown) async { _onboardingShown = shown; } @override Locale? getLocale() => _locale; @override Future setLocale(Locale locale) async { _locale = locale; } @override ThemeMode getThemeMode() => _themeMode; @override Future 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.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)); }); }); }