import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:appsok/src/features/settings/settings_page.dart'; import 'package:appsok/src/theme/app_theme.dart'; Widget _wrap(Widget child) => MaterialApp( theme: AppTheme.light(), home: Scaffold(body: child), ); void main() { group('SettingsPage web login', () { testWidgets('disables web login for invalid Jenkins URL', (tester) async { await tester.pumpWidget(_wrap(const SettingsPage())); final button = tester.widget( find.byKey(const ValueKey('jenkins-web-login-button')), ); expect(button.onPressed, isNull); // Empty URL — still disabled await tester.enterText(find.byType(TextField).first, ''); await tester.pump(); final buttonAfterEmpty = tester.widget( find.byKey(const ValueKey('jenkins-web-login-button')), ); expect(buttonAfterEmpty.onPressed, isNull); // Non-URL text — still disabled await tester.enterText(find.byType(TextField).first, 'not-a-url'); await tester.pump(); final buttonAfterInvalid = tester.widget( find.byKey(const ValueKey('jenkins-web-login-button')), ); expect(buttonAfterInvalid.onPressed, isNull); }); testWidgets('calls web login launcher with normalized base URL', ( tester, ) async { String? capturedUrl; await tester.pumpWidget( _wrap( SettingsPage( webLoginLauncher: (url) async { capturedUrl = url; return null; }, ), ), ); await tester.enterText( find.byType(TextField).first, 'https://jenkins.example.com', ); await tester.pump(); final button = tester.widget( find.byKey(const ValueKey('jenkins-web-login-button')), ); expect(button.onPressed, isNotNull); await tester.tap(find.byKey(const ValueKey('jenkins-web-login-button'))); await tester.pumpAndSettle(); expect(capturedUrl, 'https://jenkins.example.com'); }); testWidgets('shows completed login user without token text', ( tester, ) async { await tester.pumpWidget( _wrap( SettingsPage( webLoginLauncher: (_) async => const JenkinsWebLoginResult( username: 'toki', displayName: 'Toki Lab', apiToken: 'issued-token', ), ), ), ); await tester.enterText( find.byType(TextField).first, 'https://jenkins.example.com', ); await tester.pump(); await tester.tap(find.byKey(const ValueKey('jenkins-web-login-button'))); await tester.pumpAndSettle(); // Result label must show displayName expect(find.byKey(const ValueKey('web-login-result')), findsOneWidget); expect(find.textContaining('Toki Lab'), findsOneWidget); // No token-like text should appear expect(find.textContaining('token'), findsNothing); expect(find.textContaining('apiToken'), findsNothing); }); testWidgets('shows token issue error when web login returns no apiToken', ( tester, ) async { await tester.pumpWidget( _wrap( SettingsPage( webLoginLauncher: (_) async => const JenkinsWebLoginResult( username: 'toki', displayName: 'Toki Lab', ), ), ), ); await tester.enterText( find.byType(TextField).first, 'https://jenkins.example.com', ); await tester.pump(); await tester.tap(find.byKey(const ValueKey('jenkins-web-login-button'))); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('web-login-result')), findsNothing); expect(find.textContaining('API token 발급에 실패했습니다'), findsOneWidget); }); testWidgets('clears stored credential through sessionClearer', ( tester, ) async { var clearCalled = false; await tester.pumpWidget( _wrap( SettingsPage( sessionClearer: () async { clearCalled = true; }, ), ), ); await tester.tap( find.byKey(const ValueKey('jenkins-clear-session-button')), ); await tester.pumpAndSettle(); expect(clearCalled, isTrue); expect( find.byKey(const ValueKey('session-cleared-label')), findsOneWidget, ); expect(find.byKey(const ValueKey('session-clear-error')), findsNothing); }); }); group('SettingsPage base URL change clears transient state', () { testWidgets( 'SettingsPage clears transient login/save/clear state when base url changes', (tester) async { await tester.pumpWidget( _wrap( SettingsPage( webLoginLauncher: (url) async => const JenkinsWebLoginResult( username: 'toki', displayName: 'Toki Lab', apiToken: 'issued-token', ), tokenSaver: (baseUrl, username, apiToken) async => true, onSessionSaved: () {}, ), ), ); // Enter a valid URL and trigger web login so token-saved-label appears. await tester.enterText( find.byType(TextField).first, 'https://jenkins.example.com', ); await tester.pump(); await tester.tap( find.byKey(const ValueKey('jenkins-web-login-button')), ); await tester.pumpAndSettle(); expect(find.byKey(const ValueKey('token-saved-label')), findsOneWidget); // Change URL — all transient labels must be cleared. await tester.enterText( find.byType(TextField).first, 'https://jenkins2.example.com', ); await tester.pump(); expect(find.byKey(const ValueKey('token-saved-label')), findsNothing); expect(find.byKey(const ValueKey('web-login-result')), findsNothing); expect(find.byKey(const ValueKey('token-save-error')), findsNothing); expect( find.byKey(const ValueKey('session-cleared-label')), findsNothing, ); }, ); }); }