forked from baron/baron-sso
계정 생성, 비밀번호변경, 삭제 테스트케이스 추가
This commit is contained in:
@@ -40,11 +40,26 @@
|
||||
- `template.toml` 제외
|
||||
- 유효 locale 파일(`en.toml`, `ko.toml`)만 지원 목록에 반영
|
||||
|
||||
### S8. 실계정 비밀번호 변경 스모크(E2E)
|
||||
- 목적: 로그인 상태 플로우가 기존 동작을 깨지 않았는지 확인
|
||||
- 절차:
|
||||
- Kratos Admin API로 임시 계정 생성(초기 비밀번호 포함)
|
||||
- 구 비밀번호 로그인 성공 확인
|
||||
- Settings API로 비밀번호 변경
|
||||
- 구 비밀번호 로그인 실패 확인
|
||||
- 신 비밀번호 로그인 성공 확인
|
||||
- 테스트 계정 삭제(정리)
|
||||
- 기대:
|
||||
- 비밀번호 변경 전/후 인증 결과가 정확히 반전
|
||||
- 테스트 종료 후 identity 삭제 완료(잔존 계정 없음)
|
||||
|
||||
## 실행 방법
|
||||
```bash
|
||||
cd userfront
|
||||
flutter test test/locale_utils_test.dart
|
||||
flutter test test/locale_registry_test.dart
|
||||
flutter test test/router_redirect_widget_test.dart
|
||||
flutter test --platform chrome test/locale_utils_test.dart test/locale_registry_test.dart test/router_redirect_widget_test.dart
|
||||
```
|
||||
|
||||
## 자동화 매핑
|
||||
@@ -52,3 +67,17 @@ flutter test test/locale_registry_test.dart
|
||||
- S1~S6 전부 커버
|
||||
- `userfront/test/locale_registry_test.dart`
|
||||
- S7 커버
|
||||
- `userfront/test/router_redirect_widget_test.dart`
|
||||
- 로그인/비로그인 redirect 동작 검증(`redirect_uri`, `redirect_url`)
|
||||
|
||||
## 최근 실행 결과
|
||||
- 실행일: 2026-02-19
|
||||
- 결과:
|
||||
- Flutter 테스트(VM): 통과
|
||||
- Flutter 테스트(Chrome): 통과
|
||||
- S8 실계정 E2E: 통과
|
||||
- `login_old_password=200`
|
||||
- `change_password=200`
|
||||
- `login_old_after_change=400`
|
||||
- `login_new_after_change=200`
|
||||
- `cleanup(delete identity)=204`
|
||||
|
||||
@@ -63,6 +63,14 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('buildLocalizedPath preserves redirect_url parameter', () {
|
||||
final uri = Uri.parse('/signin?redirect_url=https://example.com/after');
|
||||
expect(
|
||||
buildLocalizedPath('ko', uri),
|
||||
'/ko/signin?redirect_url=https://example.com/after',
|
||||
);
|
||||
});
|
||||
|
||||
test('buildLocalizedPath preserves raw query order and duplicates', () {
|
||||
final uri = Uri.parse(
|
||||
'/signin?a=1&a=2&redirect_uri=https%3A%2F%2Fexample.com%2Fcb%3Fx%3D1%26y%3D2',
|
||||
@@ -109,5 +117,15 @@ void main() {
|
||||
'/ko/signin?a=1&a=2&redirect_uri=https%3A%2F%2Fexample.com%2Fcb%3Fx%3D1%26y%3D2¬ice=qr_login_required',
|
||||
);
|
||||
});
|
||||
|
||||
test('buildSigninRedirectPath preserves redirect_url and redirect_uri', () {
|
||||
final uri = Uri.parse(
|
||||
'/ko/profile?redirect_url=https%3A%2F%2Fa.example.com%2Fcb&redirect_uri=https%3A%2F%2Fb.example.com%2Fcb',
|
||||
);
|
||||
expect(
|
||||
buildSigninRedirectPath('ko', uri),
|
||||
'/ko/signin?redirect_url=https%3A%2F%2Fa.example.com%2Fcb&redirect_uri=https%3A%2F%2Fb.example.com%2Fcb',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
121
userfront/test/router_redirect_widget_test.dart
Normal file
121
userfront/test/router_redirect_widget_test.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:userfront/core/i18n/locale_registry.dart';
|
||||
import 'package:userfront/core/i18n/locale_utils.dart';
|
||||
import 'package:userfront/core/services/auth_token_store.dart';
|
||||
|
||||
Widget _buildTestApp(String initialLocation) {
|
||||
final router = GoRouter(
|
||||
initialLocation: initialLocation,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/:locale',
|
||||
builder: (context, state) => const Scaffold(body: Text('root')),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'signin',
|
||||
builder: (context, state) {
|
||||
final challenge = state.uri.queryParameters['login_challenge'];
|
||||
final redirect =
|
||||
state.uri.queryParameters['redirect_uri'] ??
|
||||
state.uri.queryParameters['redirect_url'] ??
|
||||
'';
|
||||
return Scaffold(
|
||||
body: Text(
|
||||
'signin|challenge=${challenge ?? ''}|redirect=$redirect',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: 'profile',
|
||||
builder: (context, state) =>
|
||||
const Scaffold(body: Text('profile-page')),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
redirect: (context, state) {
|
||||
final requestedLocale = extractLocaleFromPath(state.uri);
|
||||
if (requestedLocale == null) {
|
||||
return buildLocalizedPath(resolvePreferredLocaleCode(), state.uri);
|
||||
}
|
||||
|
||||
final isLoggedIn =
|
||||
AuthTokenStore.getToken() != null || AuthTokenStore.usesCookie();
|
||||
final path = stripLocalePath(state.uri);
|
||||
final isPublicPath = path == '/signin';
|
||||
if (isPublicPath) {
|
||||
return null;
|
||||
}
|
||||
if (!isLoggedIn) {
|
||||
return buildSigninRedirectPath(requestedLocale, state.uri);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
return MaterialApp.router(routerConfig: router);
|
||||
}
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
LocaleRegistry.setSupportedLocaleCodesForTest(['en', 'ko']);
|
||||
AuthTokenStore.clear();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
AuthTokenStore.clear();
|
||||
LocaleRegistry.resetForTest();
|
||||
});
|
||||
|
||||
testWidgets('비로그인: redirect_uri/login_challenge가 signin으로 전달', (
|
||||
tester,
|
||||
) async {
|
||||
final encodedRedirectUri = Uri.encodeComponent(
|
||||
'https://rp.example.com/cb?x=1',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
_buildTestApp(
|
||||
'/en/profile?login_challenge=lc_123&redirect_uri=$encodedRedirectUri',
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.text(
|
||||
'signin|challenge=lc_123|redirect=https://rp.example.com/cb?x=1',
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('비로그인: redirect_uri가 없으면 redirect_url을 전달', (tester) async {
|
||||
final encodedRedirectUrl = Uri.encodeComponent(
|
||||
'https://legacy.example.com/cb',
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
_buildTestApp('/en/profile?redirect_url=$encodedRedirectUrl'),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.text('signin|challenge=|redirect=https://legacy.example.com/cb'),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('로그인 상태: profile 접근 시 signin으로 리다이렉트하지 않음', (tester) async {
|
||||
AuthTokenStore.setToken('test-token', provider: 'ory');
|
||||
await tester.pumpWidget(
|
||||
_buildTestApp(
|
||||
'/en/profile?redirect_uri=https%3A%2F%2Frp.example.com%2Fcb',
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('profile-page'), findsOneWidget);
|
||||
expect(find.textContaining('signin|'), findsNothing);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user