chore: API 오류 매핑과 Failure 파서 고도화

This commit is contained in:
JiWoong Sul
2025-10-14 18:06:25 +09:00
parent 67fc319c3c
commit 9f61b305d4
7 changed files with 1000 additions and 71 deletions

View File

@@ -1,73 +1,96 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:superport_v2/core/permissions/permission_manager.dart';
import 'package:superport_v2/core/permissions/permission_resources.dart';
void main() {
group('PermissionManager', () {
test('falls back to environment permissions when no override', () {
test('서버 권한을 적용하면 해당 리소스 권한이 설정된다', () {
final manager = PermissionManager();
final allowed = manager.can('/any', PermissionAction.view);
expect(allowed, isTrue);
});
test('respects overrides', () {
final manager = PermissionManager(
overrides: {
'/inventory/inbound': {
PermissionAction.view,
PermissionAction.create,
},
manager.applyServerPermissions({
PermissionResources.stockTransactions: {
PermissionAction.view,
PermissionAction.create,
},
);
expect(manager.can('/inventory/inbound', PermissionAction.view), isTrue);
});
expect(
manager.can('/inventory/inbound', PermissionAction.create),
manager.can(
PermissionResources.stockTransactions,
PermissionAction.view,
),
isTrue,
);
expect(
manager.can('/inventory/inbound', PermissionAction.delete),
manager.can(
PermissionResources.stockTransactions,
PermissionAction.create,
),
isTrue,
);
expect(
manager.can(
PermissionResources.stockTransactions,
PermissionAction.edit,
),
isFalse,
);
});
test('오버라이드가 서버 권한보다 우선한다', () {
final manager = PermissionManager();
manager.applyServerPermissions({
PermissionResources.approvalSteps: {PermissionAction.view},
});
manager.updateOverrides({
PermissionResources.approvalSteps: {PermissionAction.edit},
});
expect(
manager.can(PermissionResources.approvalSteps, PermissionAction.edit),
isTrue,
);
expect(
manager.can(PermissionResources.approvalSteps, PermissionAction.view),
isFalse,
);
});
test('서버 권한을 초기화하면 환경 설정으로 되돌아간다', () {
final manager = PermissionManager();
manager.applyServerPermissions({
PermissionResources.vendors: {PermissionAction.view},
});
expect(
manager.can(PermissionResources.vendors, PermissionAction.edit),
isFalse,
);
manager.clearServerPermissions();
// 환경 설정에 권한이 명시되지 않으면 기본적으로 허용한다.
expect(
manager.can(PermissionResources.vendors, PermissionAction.edit),
isTrue,
);
});
test('별칭 경로도 normalize되어 권한을 확인한다', () {
final manager = PermissionManager();
manager.applyServerPermissions({
PermissionResources.stockTransactions: {PermissionAction.view},
});
expect(
manager.can('/Inventory/Inbound?page=1', PermissionAction.view),
isTrue,
);
expect(
manager.can('/inventory/outbound', PermissionAction.edit),
isFalse,
);
});
});
testWidgets('PermissionGate hides child when unauthorized', (tester) async {
final manager = PermissionManager(overrides: {'/resource': {}});
await tester.pumpWidget(
PermissionScope(
manager: manager,
child: const Directionality(
textDirection: TextDirection.ltr,
child: PermissionGate(
resource: '/resource',
action: PermissionAction.view,
child: Text('secret'),
),
),
),
);
expect(find.text('secret'), findsNothing);
});
testWidgets('PermissionGate shows fallback when provided', (tester) async {
final manager = PermissionManager(overrides: {'/resource': {}});
await tester.pumpWidget(
PermissionScope(
manager: manager,
child: const Directionality(
textDirection: TextDirection.ltr,
child: PermissionGate(
resource: '/resource',
action: PermissionAction.view,
fallback: Text('fallback'),
child: Text('secret'),
),
),
),
);
expect(find.text('fallback'), findsOneWidget);
expect(find.text('secret'), findsNothing);
});
}

View File

@@ -0,0 +1,48 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:superport_v2/core/permissions/permission_resources.dart';
void main() {
group('PermissionResources.normalize', () {
test('경로 별칭을 서버 표준 경로로 변환한다', () {
expect(
PermissionResources.normalize('/inventory/inbound'),
PermissionResources.stockTransactions,
);
expect(
PermissionResources.normalize('/approvals/templates'),
PermissionResources.approvalTemplates,
);
});
test('대소문자/공백/슬래시를 정리한다', () {
expect(
PermissionResources.normalize(' inventory/inbound/ '),
PermissionResources.stockTransactions,
);
expect(
PermissionResources.normalize('stock-transactions'),
PermissionResources.stockTransactions,
);
});
test('쿼리/프래그먼트/URL을 제거한다', () {
expect(
PermissionResources.normalize(
'/Inventory/Inbound?page=2&status=submit',
),
PermissionResources.stockTransactions,
);
expect(
PermissionResources.normalize(
'https://example.com/approvals/templates#section',
),
PermissionResources.approvalTemplates,
);
});
test('비어 있는 입력은 빈 문자열을 반환한다', () {
expect(PermissionResources.normalize(' '), isEmpty);
});
});
}