import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:userfront/core/constants/error_whitelist.dart'; import 'package:userfront/features/auth/presentation/error_screen.dart'; import 'package:userfront/i18n.dart'; Future _pumpErrorScreen( WidgetTester tester, { String? errorCode, String? description, bool? isProdOverride, Future> Function()? sessionProfileLoader, Map? tenantAccessDetails, }) async { await tester.pumpWidget( MaterialApp( home: ErrorScreen( errorCode: errorCode, description: description, isProdOverride: isProdOverride, sessionProfileLoader: sessionProfileLoader, tenantAccessDetails: tenantAccessDetails, ), ), ); await tester.pump(); } void main() { setUpAll(() { TestWidgetsFlutterBinding.ensureInitialized(); final dispatcher = TestWidgetsFlutterBinding.instance.platformDispatcher; dispatcher.localeTestValue = const Locale('ko'); dispatcher.localesTestValue = const [Locale('ko')]; }); tearDownAll(() { final dispatcher = TestWidgetsFlutterBinding.instance.platformDispatcher; dispatcher.clearLocaleTestValue(); dispatcher.clearLocalesTestValue(); }); testWidgets('개발환경은 원문 메시지를 노출한다', (WidgetTester tester) async { await _pumpErrorScreen( tester, errorCode: 'custom_error', description: '원문 메시지', isProdOverride: false, ); final title = tr( 'msg.userfront.error.title_with_code', fallback: '오류: {{code}}', params: {'code': 'custom_error'}, ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'custom_error'}, ); expect(find.text(title), findsOneWidget); expect(find.text('원문 메시지'), findsOneWidget); expect(find.text(type), findsOneWidget); }); testWidgets('프로덕션은 whitelist 메시지를 노출한다', (WidgetTester tester) async { await _pumpErrorScreen( tester, errorCode: 'settings_disabled', description: '원문 메시지', isProdOverride: true, ); final title = tr( 'msg.userfront.error.title', fallback: '인증 과정에서 오류가 발생했습니다', ); final detail = tr( 'msg.userfront.error.whitelist.settings_disabled', fallback: internalErrorWhitelistMessages['settings_disabled']!, ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'settings_disabled'}, ); expect(find.text(title), findsOneWidget); expect(find.text(detail), findsOneWidget); expect(find.text('원문 메시지'), findsNothing); expect(find.text(type), findsOneWidget); }); testWidgets('프로덕션은 ORY 코드를 bypass 처리한다', (WidgetTester tester) async { await _pumpErrorScreen( tester, errorCode: 'access_denied', description: '원문 메시지', isProdOverride: true, ); final title = tr( 'msg.userfront.error.title', fallback: '인증 과정에서 오류가 발생했습니다', ); final detail = tr( 'msg.userfront.error.ory.access_denied', fallback: '사용자가 동의를 거부했습니다.', ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'access_denied'}, ); expect(find.text(title), findsOneWidget); expect(find.text(detail), findsOneWidget); expect(find.text('원문 메시지'), findsNothing); expect(find.text(type), findsOneWidget); }); testWidgets('프로덕션은 비허용 에러를 unknown_error로 처리한다', (WidgetTester tester) async { await _pumpErrorScreen( tester, errorCode: 'weird_error', description: '원문 메시지', isProdOverride: true, ); final title = tr( 'msg.userfront.error.title', fallback: '인증 과정에서 오류가 발생했습니다', ); final detail = tr( 'msg.userfront.error.detail_contact', fallback: '에러가 계속되면 관리자에게 문의해주세요', ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'unknown_error'}, ); expect(find.text(title), findsOneWidget); expect(find.text(detail), findsOneWidget); expect(find.text('원문 메시지'), findsNothing); expect(find.text(type), findsOneWidget); }); testWidgets('프로덕션은 not_found 코드를 whitelist 메시지로 노출한다 (404 매핑)', ( WidgetTester tester, ) async { await _pumpErrorScreen( tester, errorCode: 'not_found', description: '원문 메시지', isProdOverride: true, ); final detail = tr( 'msg.userfront.error.whitelist.not_found', fallback: internalErrorWhitelistMessages['not_found']!, ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'not_found'}, ); expect(find.text(detail), findsOneWidget); expect(find.text(type), findsOneWidget); expect(find.text('원문 메시지'), findsNothing); }); testWidgets('프로덕션은 rate_limited 코드를 whitelist 메시지로 노출한다 (429 매핑)', ( WidgetTester tester, ) async { await _pumpErrorScreen( tester, errorCode: 'rate_limited', description: '원문 메시지', isProdOverride: true, ); final detail = tr( 'msg.userfront.error.whitelist.rate_limited', fallback: internalErrorWhitelistMessages['rate_limited']!, ); final type = tr( 'msg.userfront.error.type', fallback: '오류 종류: {{type}}', params: {'type': 'rate_limited'}, ); expect(find.text(detail), findsOneWidget); expect(find.text(type), findsOneWidget); expect(find.text('원문 메시지'), findsNothing); }); testWidgets('tenant_not_allowed는 전용 차단 정보를 노출한다', ( WidgetTester tester, ) async { await _pumpErrorScreen( tester, errorCode: 'tenant_not_allowed', description: '원문 메시지', isProdOverride: true, sessionProfileLoader: () async { return { 'email': 'employee@example.com', 'tenant': {'name': 'Baron HQ', 'slug': 'baron-hq'}, }; }, ); final title = tr( 'msg.userfront.error.tenant.page_title', fallback: '애플리케이션 접근이 제한되었습니다', ); final detail = tr( 'msg.userfront.error.tenant.detail', fallback: '현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다.', ); final account = tr('msg.userfront.error.tenant.account', fallback: '계정'); final primaryTenant = tr( 'msg.userfront.error.tenant.primary_tenant', fallback: '대표 소속 테넌트', ); final affiliatedTenants = tr( 'msg.userfront.error.tenant.affiliated_tenants', fallback: '전체 소속 테넌트', ); final switchAccount = tr( 'ui.userfront.error.switch_account', fallback: '다른 계정으로 로그인', ); expect(find.text(title), findsOneWidget); expect(find.text(detail), findsOneWidget); expect(find.text(account), findsOneWidget); expect(find.text('employee@example.com'), findsOneWidget); expect(find.text(primaryTenant), findsOneWidget); expect(find.text(affiliatedTenants), findsOneWidget); expect(find.text('Baron HQ'), findsNWidgets(2)); expect(find.text(switchAccount), findsOneWidget); }); testWidgets('tenant_not_allowed는 details를 우선 사용해 계정과 테넌트 정보를 노출한다', ( WidgetTester tester, ) async { await _pumpErrorScreen( tester, errorCode: 'tenant_not_allowed', isProdOverride: true, tenantAccessDetails: { 'account': {'email': 'dyddus1210@gmail.com'}, 'current_tenant': {'name': 'test1 company', 'slug': 'test1-company'}, 'affiliated_tenants': [ {'name': 'test1 company', 'slug': 'test1-company'}, {'name': 'test2 company', 'slug': 'test-company'}, ], 'allowed_tenants': [ {'name': 'test4', 'slug': 'test4'}, ], }, ); expect(find.text('dyddus1210@gmail.com'), findsOneWidget); expect(find.text('test1 company'), findsOneWidget); expect(find.text('test1 company, test2 company'), findsOneWidget); expect(find.text('test4'), findsOneWidget); expect(find.text('알 수 없음'), findsNothing); }); }