번호 자동 부여 대응 및 API 공통 처리 보강

This commit is contained in:
JiWoong Sul
2025-10-23 14:02:31 +09:00
parent 09c31b2503
commit 7e933a2dda
55 changed files with 948 additions and 586 deletions

View File

@@ -15,11 +15,28 @@ void main() {
setUpAll(() {
registerFallbackValue(Options());
registerFallbackValue(CancelToken());
registerFallbackValue(
Response<dynamic>(requestOptions: RequestOptions(path: '/')),
);
});
setUp(() {
apiClient = _MockApiClient();
repository = ApprovalRepositoryRemote(apiClient: apiClient);
when(() => apiClient.unwrapAsMap(any())).thenAnswer((invocation) {
final response = invocation.positionalArguments.first;
if (response is Response) {
final data = response.data;
if (data is Map<String, dynamic>) {
final nested = data['data'];
if (nested is Map<String, dynamic>) {
return nested;
}
return data;
}
}
return <String, dynamic>{};
});
});
test('list는 신규 필터 파라미터를 전달한다', () async {
@@ -93,7 +110,6 @@ void main() {
final input = ApprovalCreateInput(
transactionId: 9001,
approvalNo: 'APP-2025-0001',
approvalStatusId: 1,
requestedById: 7,
note: ' 신규 결재 ',
@@ -113,7 +129,7 @@ void main() {
expect(captured.first, equals(path));
final payload = captured[1] as Map<String, dynamic>;
expect(payload['transaction_id'], 9001);
expect(payload['approval_no'], 'APP-2025-0001');
expect(payload.containsKey('approval_no'), isFalse);
expect(payload['approval_status_id'], 1);
expect(payload['requested_by_id'], 7);
expect(payload['note'], '신규 결재');

View File

@@ -116,17 +116,18 @@ void main() {
expect(transactionField, findsOneWidget);
expect(approvalField, findsOneWidget);
final transactionInput = find.descendant(
of: transactionField,
matching: find.byType(EditableText),
expect(
find.descendant(
of: transactionField,
matching: find.byType(EditableText),
),
findsNothing,
);
final approvalInput = find.descendant(
of: approvalField,
matching: find.byType(EditableText),
expect(
find.descendant(of: approvalField, matching: find.byType(EditableText)),
findsNothing,
);
await tester.enterText(transactionInput.first, 'IN-TEST-001');
await tester.enterText(approvalInput.first, 'APP-TEST-001');
await tester.pump();
expect(find.text('저장 시 자동 생성'), findsAtLeastNWidgets(2));
final productFields = find.byType(InventoryProductAutocompleteField);
expect(productFields, findsWidgets);
@@ -161,7 +162,7 @@ void main() {
expect(find.text('동일 제품이 중복되었습니다.'), findsOneWidget);
});
testWidgets('입고 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
testWidgets('입고 등록 모달은 번호 입력 없이 저장 안내만 제공한다', (tester) async {
final view = tester.view;
view.physicalSize = const Size(1280, 900);
view.devicePixelRatio = 1.0;
@@ -190,10 +191,14 @@ void main() {
await tester.tap(find.widgetWithText(ShadButton, '입고 등록'));
await tester.pumpAndSettle();
expect(find.text('저장 시 자동 생성'), findsAtLeastNWidgets(2));
await tester.tap(find.widgetWithText(ShadButton, '저장'));
await tester.pump();
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
expect(find.text('거래번호를 입력하세요.'), findsNothing);
expect(find.text('결재번호를 입력하세요.'), findsNothing);
expect(find.textContaining('자동완성에서 선택'), findsOneWidget);
expect(find.textContaining('창고를 선택'), findsOneWidget);
});
}

View File

@@ -25,7 +25,7 @@ void main() {
await GetIt.I.reset();
});
testWidgets('출고 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
testWidgets('출고 등록 모달은 번호 입력 없이 자동 생성 안내를 제공한다', (tester) async {
final view = tester.view;
view.physicalSize = const Size(1280, 900);
view.devicePixelRatio = 1.0;
@@ -54,10 +54,14 @@ void main() {
await tester.tap(find.widgetWithText(ShadButton, '출고 등록'));
await tester.pumpAndSettle();
expect(find.text('저장 시 자동 생성'), findsAtLeastNWidgets(2));
await tester.tap(find.widgetWithText(ShadButton, '저장'));
await tester.pump();
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
expect(find.text('거래번호를 입력하세요.'), findsNothing);
expect(find.text('결재번호를 입력하세요.'), findsNothing);
expect(find.textContaining('자동완성에서 선택'), findsOneWidget);
expect(find.text('창고를 선택하세요.'), findsOneWidget);
});
}

View File

@@ -25,7 +25,7 @@ void main() {
await GetIt.I.reset();
});
testWidgets('대여 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
testWidgets('대여 등록 모달은 번호 입력 없이 자동 생성 안내를 제공한다', (tester) async {
final view = tester.view;
view.physicalSize = const Size(1280, 900);
view.devicePixelRatio = 1.0;
@@ -54,10 +54,14 @@ void main() {
await tester.tap(find.widgetWithText(ShadButton, '대여 등록'));
await tester.pumpAndSettle();
expect(find.text('저장 시 자동 생성'), findsAtLeastNWidgets(2));
await tester.tap(find.widgetWithText(ShadButton, '저장'));
await tester.pump();
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
expect(find.text('거래번호를 입력하세요.'), findsNothing);
expect(find.text('결재번호를 입력하세요.'), findsNothing);
expect(find.textContaining('자동완성에서 선택'), findsOneWidget);
expect(find.text('최소 1개의 고객사를 선택하세요.'), findsOneWidget);
});
}

View File

@@ -164,6 +164,11 @@ void main() {
),
],
customers: [TransactionCustomerCreateInput(customerId: 7)],
approval: StockTransactionApprovalInput(
requestedById: 9,
approvalStatusId: 5,
note: '승인 요청',
),
);
await repository.create(input);
@@ -185,6 +190,12 @@ void main() {
expect(payload['created_by_id'], 9);
expect(payload['lines'], isA<List>());
expect(payload['customers'], isA<List>());
expect(payload.containsKey('transaction_no'), isFalse);
final approvalPayload = payload['approval'] as Map<String, dynamic>;
expect(approvalPayload.containsKey('approval_no'), isFalse);
expect(approvalPayload['requested_by_id'], 9);
expect(approvalPayload['approval_status_id'], 5);
expect(approvalPayload['note'], '승인 요청');
});
test('submit은 /submit 엔드포인트를 호출한다', () async {

View File

@@ -14,11 +14,28 @@ void main() {
setUpAll(() {
registerFallbackValue(Options());
registerFallbackValue(CancelToken());
registerFallbackValue(
Response<dynamic>(requestOptions: RequestOptions(path: '/')),
);
});
setUp(() {
apiClient = _MockApiClient();
repository = CustomerRepositoryRemote(apiClient: apiClient);
when(() => apiClient.unwrapAsMap(any())).thenAnswer((invocation) {
final response = invocation.positionalArguments.first;
if (response is Response) {
final data = response.data;
if (data is Map<String, dynamic>) {
final nested = data['data'];
if (nested is Map<String, dynamic>) {
return nested;
}
return data;
}
}
return <String, dynamic>{};
});
});
test('list 호출 시 필터를 쿼리에 포함한다', () async {