appsok/test/settings_page_test.dart
toki 8429af52f3 feat: reauth UI wiring — restore result kinds propagate to BuildsPage status states
- AppSokApp uses restoreDetailed() and maps JenkinsSessionRestoreKind to
  JenkinsConnectionStatus; network/server failures expose a retry callback
- AppSokShell passes connectionStatus + onRetryConnection through to BuildsPage
- BuildsPage shows four distinct no-loader states: missing, reauthRequired,
  networkFailure (with retry), serverFailure (with retry)
- SettingsPage clears all transient login/save/clear state on base URL change
- pubspec.lock restored to meta 1.18.0 / test_api 0.7.11 (reverts container downgrade)
- Regression tests added in app_auth_test, builds_page_test, settings_page_test;
  widget_test updated to expect 재로그인 필요 on 401

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 21:26:33 +09:00

183 lines
5.4 KiB
Dart

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<ElevatedButton>(
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<ElevatedButton>(
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<ElevatedButton>(
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<ElevatedButton>(
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',
),
),
),
);
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('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,
);
},
);
});
}