import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fotodocumentation/controller/login_controller.dart'; import 'package:fotodocumentation/dto/jwt_token_pair_dto.dart'; import 'package:fotodocumentation/pages/login/login_widget.dart'; import 'package:fotodocumentation/utils/di_container.dart'; import 'package:fotodocumentation/utils/global_router.dart'; import 'package:fotodocumentation/utils/login_credentials.dart'; import 'package:mockito/mockito.dart'; import '../testing/test_utils.dart'; import '../testing/test_utils.mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); DiContainer.instance.initState(); late MockLoginController mockLoginController; late MockLoginCredentials mockLoginCredentials; setUp(() { mockLoginController = MockLoginController(); mockLoginCredentials = MockLoginCredentials(); when(mockLoginCredentials.isLoggedIn).thenReturn(false); DiContainer.instance.put(LoginController, mockLoginController); DiContainer.instance.put(LoginCredentials, mockLoginCredentials); }); group('LoginWidget', () { testWidgets('displays login title', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Verify the login title is displayed (German localization) expect(find.byKey(const Key('login_title')), findsOneWidget); }); testWidgets('displays username and password fields', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Verify username field exists expect(find.byKey(const Key("username")), findsOneWidget); // Verify password field exists expect(find.byKey(const Key("password")), findsOneWidget); }); testWidgets('displays login button', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Verify login button exists expect(find.byKey(const Key("SubmitWidgetButton")), findsOneWidget); }); testWidgets('can enter username and password', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Enter username await tester.enterText(find.byKey(const Key("username")), 'testuser'); await tester.pumpAndSettle(); // Enter password await tester.enterText(find.byKey(const Key("password")), 'testpassword'); await tester.pumpAndSettle(); // Verify text was entered expect(find.text('testuser'), findsOneWidget); }); testWidgets('calls authenticate on login button tap', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); final jwtTokenPairDto = JwtTokenPairDto( accessToken: 'test_access_token', refreshToken: 'test_refresh_token', ); when(mockLoginController.authenticate('testuser', 'testpassword')) .thenAnswer((_) async => (jwtTokenPairDto: jwtTokenPairDto)); await pumpAppConfig(tester, GlobalRouter.pathLogin); await tester.pumpAndSettle(); // Enter credentials await tester.enterText(find.byKey(const Key("username")), 'testuser'); await tester.enterText(find.byKey(const Key("password")), 'testpassword'); await tester.pumpAndSettle(); // Tap login button await tester.tap(find.byKey(const Key("SubmitWidgetButton"))); await tester.pumpAndSettle(); // Verify authenticate was called with correct credentials verify(mockLoginController.authenticate('testuser', 'testpassword')).called(1); }); testWidgets('sets logged in on successful authentication', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); final jwtTokenPairDto = JwtTokenPairDto( accessToken: 'test_access_token', refreshToken: 'test_refresh_token', ); when(mockLoginController.authenticate('testuser', 'testpassword')) .thenAnswer((_) async => (jwtTokenPairDto: jwtTokenPairDto)); await pumpAppConfig(tester, GlobalRouter.pathLogin); await tester.pumpAndSettle(); // Enter credentials await tester.enterText(find.byKey(const Key("username")), 'testuser'); await tester.enterText(find.byKey(const Key("password")), 'testpassword'); await tester.pumpAndSettle(); // Tap login button await tester.tap(find.byKey(const Key("SubmitWidgetButton"))); await tester.pumpAndSettle(); // Verify setLoggedIn was called verify(mockLoginCredentials.setLoggedIn(true)).called(1); }); testWidgets('displays error message on failed authentication', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); when(mockLoginController.authenticate('testuser', 'wrongpassword')) .thenAnswer((_) async => (jwtTokenPairDto: null)); await pumpAppConfig(tester, GlobalRouter.pathLogin); await tester.pumpAndSettle(); // Enter credentials await tester.enterText(find.byKey(const Key("username")), 'testuser'); await tester.enterText(find.byKey(const Key("password")), 'wrongpassword'); await tester.pumpAndSettle(); // Tap login button await tester.tap(find.byKey(const Key("SubmitWidgetButton"))); await tester.pumpAndSettle(); // Verify error message is displayed (German localization) expect(find.text('Falscher Benutzername oder Passwort'), findsOneWidget); }); testWidgets('does not call setLoggedIn on failed authentication', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); when(mockLoginController.authenticate('testuser', 'wrongpassword')) .thenAnswer((_) async => (jwtTokenPairDto: null)); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Enter credentials await tester.enterText(find.byKey(const Key("username")), 'testuser'); await tester.enterText(find.byKey(const Key("password")), 'wrongpassword'); await tester.pumpAndSettle(); // Tap login button await tester.tap(find.byKey(const Key("SubmitWidgetButton"))); await tester.pumpAndSettle(); // Verify setLoggedIn was NOT called verifyNever(mockLoginCredentials.setLoggedIn(any)); }); testWidgets('password field obscures text', (WidgetTester tester) async { setScreenSize(tester, 1024, 1024); await pumpApp(tester, const LoginWidget()); await tester.pumpAndSettle(); // Find the EditableText descendant of the password field // TextFormField wraps TextField which contains EditableText final passwordFieldFinder = find.byKey(const Key("password")); final editableTextFinder = find.descendant( of: passwordFieldFinder, matching: find.byType(EditableText), ); final editableText = tester.widget(editableTextFinder); // Verify obscureText is true expect(editableText.obscureText, isTrue); }); }); }