1
0
forked from baron/baron-sso

code check 오류 수정

This commit is contained in:
2026-03-23 15:36:00 +09:00
parent 3c54c46898
commit e98ab39dfe
11 changed files with 155 additions and 104 deletions

File diff suppressed because one or more lines are too long

View File

@@ -277,6 +277,11 @@ privacy_full = "개인정보 수집 및 이용 동의 전문..."
tos_full = "서비스 이용약관 전문..."
[msg.userfront.signup.agreement]
all_hint = "필수 약관 2개를 모두 확인하고 동의하면 다음 단계로 진행할 수 있습니다."
description = "계속 진행하려면 서비스 이용 조건과 개인정보 수집·이용 항목을 확인한 뒤 동의해주세요."
privacy_summary = "개인정보 수집 항목, 이용 목적, 보관 기준을 안내합니다."
progress = "필수 약관 {total}개 중 {count}개 동의 완료"
tos_summary = "서비스 이용 조건과 책임 범위를 확인할 수 있습니다."
title = "서비스 이용을 위해\n약관에 동의해주세요"
[msg.userfront.signup.auth]
@@ -583,6 +588,7 @@ title = "회원가입"
[ui.userfront.signup.agreement]
all = "모두 동의합니다"
privacy_title = "개인정보 수집 및 이용 동의 (필수)"
required = "필수"
tos_title = "바론 소프트웨어 이용약관 (필수)"
[ui.userfront.signup.auth]
@@ -616,4 +622,3 @@ verify = "본인인증"
[ui.userfront.signup.success]
action = "로그인하기"

View File

@@ -277,6 +277,11 @@ privacy_full = ""
tos_full = ""
[msg.userfront.signup.agreement]
all_hint = ""
description = ""
privacy_summary = ""
progress = ""
tos_summary = ""
title = ""
[msg.userfront.signup.auth]
@@ -583,6 +588,7 @@ title = ""
[ui.userfront.signup.agreement]
all = ""
privacy_title = ""
required = ""
tos_title = ""
[ui.userfront.signup.auth]
@@ -616,4 +622,3 @@ verify = ""
[ui.userfront.signup.success]
action = ""

View File

@@ -238,8 +238,8 @@ class _ConsentScreenState extends State<ConsentScreen> {
final clientName = (clientRawName != null && clientRawName.isNotEmpty)
? clientRawName
: (clientId != '-'
? clientId
: tr('msg.userfront.consent.client_unknown'));
? clientId
: tr('msg.userfront.consent.client_unknown'));
final clientLogo = _consentInfo?['client']?['logo_uri'];
final requestedScopes =
(_consentInfo?['requested_scope'] as List<dynamic>?)?.cast<String>() ??

View File

@@ -1494,8 +1494,7 @@ class _SignupScreenState extends State<SignupScreen> {
labelText: tr(
'ui.userfront.signup.profile.company',
),
border:
const OutlineInputBorder(),
border: const OutlineInputBorder(),
),
items: [
DropdownMenuItem(
@@ -1557,7 +1556,9 @@ class _SignupScreenState extends State<SignupScreen> {
_buildProfileFieldGroup(
title: _affiliationType == 'AFFILIATE'
? tr('ui.userfront.signup.profile.department')
: tr('ui.userfront.signup.profile.department_optional'),
: tr(
'ui.userfront.signup.profile.department_optional',
),
description: _affiliationType == 'AFFILIATE'
? '가족사 사용자는 부서명을 입력해주세요.'
: '선택 입력 항목입니다.',
@@ -1677,10 +1678,7 @@ class _SignupScreenState extends State<SignupScreen> {
],
),
),
if (trailing != null) ...[
const SizedBox(width: 12),
trailing,
],
if (trailing != null) ...[const SizedBox(width: 12), trailing],
],
),
SizedBox(height: isDesktop ? 18 : 14),
@@ -1793,13 +1791,22 @@ class _SignupScreenState extends State<SignupScreen> {
hasTypeCount,
),
if (requiresUpper)
_cryptoCheck(tr('msg.userfront.signup.password.rule.uppercase'), hasUpper),
_cryptoCheck(
tr('msg.userfront.signup.password.rule.uppercase'),
hasUpper,
),
if (requiresLower)
_cryptoCheck(tr('msg.userfront.signup.password.rule.lowercase'), hasLower),
_cryptoCheck(
tr('msg.userfront.signup.password.rule.lowercase'),
hasLower,
),
if (requiresNumber)
_cryptoCheck(tr('msg.userfront.signup.password.rule.number'), hasDigit),
if (requiresSymbol)
_cryptoCheck(tr('msg.userfront.signup.password.rule.symbol'), hasSpecial),
_cryptoCheck(
tr('msg.userfront.signup.password.rule.symbol'),
hasSpecial,
),
];
return LayoutBuilder(
@@ -1861,14 +1868,15 @@ class _SignupScreenState extends State<SignupScreen> {
obscureText: _isPasswordObscured,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
labelText: tr('ui.userfront.signup.password.label'),
labelText: tr(
'ui.userfront.signup.password.label',
),
border: const OutlineInputBorder(),
errorText: _passwordError,
suffixIcon: IconButton(
onPressed: () {
setState(() {
_isPasswordObscured =
!_isPasswordObscured;
_isPasswordObscured = !_isPasswordObscured;
});
},
icon: Icon(
@@ -1897,8 +1905,8 @@ class _SignupScreenState extends State<SignupScreen> {
obscureText: _isConfirmPasswordObscured,
onChanged: (val) {
setState(() {
_confirmPasswordError = (val !=
_passwordController.text)
_confirmPasswordError =
(val != _passwordController.text)
? tr('msg.userfront.signup.password.mismatch')
: null;
});
@@ -2032,11 +2040,7 @@ class _SignupScreenState extends State<SignupScreen> {
),
child: Padding(
padding: EdgeInsets.all(isDesktop ? 16 : 14),
child: Wrap(
spacing: 12,
runSpacing: 10,
children: checks,
),
child: Wrap(spacing: 12, runSpacing: 10, children: checks),
),
);
}

View File

@@ -10,7 +10,7 @@ class MockProfileNotifier extends ProfileNotifier {
UserProfile? _profile;
bool updateCalled = false;
String? updatedName;
@override
Future<UserProfile?> build() async {
_profile = UserProfile(
@@ -33,7 +33,11 @@ class MockProfileNotifier extends ProfileNotifier {
}
@override
Future<void> updateProfile({String? name, String? phone, String? department}) async {
Future<void> updateProfile({
String? name,
String? phone,
String? department,
}) async {
updateCalled = true;
updatedName = name;
_profile = _profile!.copyWith(
@@ -46,75 +50,82 @@ class MockProfileNotifier extends ProfileNotifier {
}
void main() {
testWidgets('ProfilePage explicit save button UX flow (Edit -> Cancel -> Edit -> Save)', (tester) async {
final recordedErrors = <FlutterErrorDetails>[];
final previousOnError = FlutterError.onError;
FlutterError.onError = (details) {
final text = details.exceptionAsString();
if (text.contains('A RenderFlex overflowed')) {
return;
}
recordedErrors.add(details);
};
addTearDown(() {
FlutterError.onError = previousOnError;
});
testWidgets(
'ProfilePage explicit save button UX flow (Edit -> Cancel -> Edit -> Save)',
(tester) async {
final recordedErrors = <FlutterErrorDetails>[];
final previousOnError = FlutterError.onError;
FlutterError.onError = (details) {
final text = details.exceptionAsString();
if (text.contains('A RenderFlex overflowed')) {
return;
}
recordedErrors.add(details);
};
addTearDown(() {
FlutterError.onError = previousOnError;
});
tester.view.physicalSize = const Size(1920, 1080);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
tester.view.physicalSize = const Size(1920, 1080);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final mockNotifier = MockProfileNotifier();
await tester.pumpWidget(
ProviderScope(
overrides: [
profileProvider.overrideWith(() => mockNotifier),
],
child: const MaterialApp(
home: Scaffold(body: ProfilePage()),
final mockNotifier = MockProfileNotifier();
await tester.pumpWidget(
ProviderScope(
overrides: [profileProvider.overrideWith(() => mockNotifier)],
child: const MaterialApp(home: Scaffold(body: ProfilePage())),
),
),
);
);
await tester.pumpAndSettle();
await tester.pumpAndSettle();
// 1. Entering edit mode
final editButton = find.byKey(const Key('profile-name-edit-button'));
expect(editButton, findsOneWidget);
await tester.tap(editButton);
await tester.pumpAndSettle();
// 1. Entering edit mode
final editButton = find.byKey(const Key('profile-name-edit-button'));
expect(editButton, findsOneWidget);
await tester.tap(editButton);
await tester.pumpAndSettle();
final inputField = find.byKey(const Key('profile-name-input'));
expect(inputField, findsOneWidget);
// 2. Testing cancel flow
await tester.enterText(inputField, 'Changed Name');
await tester.pumpAndSettle();
final cancelButton = find.byKey(const Key('profile-name-cancel-button'));
await tester.tap(cancelButton);
await tester.pumpAndSettle();
// After cancellation, the field should be read-only again.
expect(find.byKey(const Key('profile-name-input')), findsNothing);
// Find text could be part of ListTile
expect(find.text('Original Name'), findsWidgets);
// 3. Re-enter edit mode and explicitly save
await tester.tap(find.byKey(const Key('profile-name-edit-button')));
await tester.pumpAndSettle();
await tester.enterText(find.byKey(const Key('profile-name-input')), 'Saved Name');
await tester.pumpAndSettle();
final saveButton = find.byKey(const Key('profile-name-save-button'));
await tester.tap(saveButton);
await tester.pumpAndSettle();
// Verify the mock received the update
expect(mockNotifier.updateCalled, isTrue);
expect(mockNotifier.updatedName, 'Saved Name');
});
final inputField = find.byKey(const Key('profile-name-input'));
expect(inputField, findsOneWidget);
// 2. Testing cancel flow
await tester.enterText(inputField, 'Changed Name');
await tester.pumpAndSettle();
final cancelButton = find.byKey(const Key('profile-name-cancel-button'));
await tester.tap(cancelButton);
await tester.pumpAndSettle();
// After cancellation, the field should be read-only again.
expect(find.byKey(const Key('profile-name-input')), findsNothing);
// Find text could be part of ListTile
expect(find.text('Original Name'), findsWidgets);
// 3. Re-enter edit mode and explicitly save
await tester.tap(find.byKey(const Key('profile-name-edit-button')));
await tester.pumpAndSettle();
await tester.enterText(
find.byKey(const Key('profile-name-input')),
'Saved Name',
);
await tester.pumpAndSettle();
final saveButton = find.byKey(const Key('profile-name-save-button'));
await tester.tap(saveButton);
await tester.pumpAndSettle();
await tester.pump(const Duration(seconds: 4));
await tester.pumpAndSettle();
FlutterError.onError = previousOnError;
// Verify the mock received the update
expect(mockNotifier.updateCalled, isTrue);
expect(mockNotifier.updatedName, 'Saved Name');
expect(recordedErrors, isEmpty);
},
);
}