API v4 계약 반영하고 보고서·입출고 화면 실연동 강화
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
@@ -8,6 +9,9 @@ import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
import 'package:superport_v2/core/theme/superport_shad_theme.dart';
|
||||
import 'package:superport_v2/features/inventory/inbound/presentation/pages/inbound_page.dart';
|
||||
import 'package:superport_v2/features/inventory/shared/widgets/product_autocomplete_field.dart';
|
||||
import 'package:superport_v2/widgets/components/form_field.dart';
|
||||
|
||||
import '../../helpers/inventory_test_stubs.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -16,6 +20,14 @@ void main() {
|
||||
await Environment.initialize();
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
registerInventoryTestStubs();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await GetIt.I.reset();
|
||||
});
|
||||
|
||||
testWidgets('입고 필터 적용 및 초기화가 목록을 갱신한다', (tester) async {
|
||||
final view = tester.view;
|
||||
view.physicalSize = const Size(1280, 800);
|
||||
@@ -95,6 +107,27 @@ void main() {
|
||||
await tester.tap(find.widgetWithText(ShadButton, '입고 등록'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final transactionField = find.byWidgetPredicate(
|
||||
(widget) => widget is SuperportFormField && widget.label == '트랜잭션번호',
|
||||
);
|
||||
final approvalField = find.byWidgetPredicate(
|
||||
(widget) => widget is SuperportFormField && widget.label == '결재번호',
|
||||
);
|
||||
expect(transactionField, findsOneWidget);
|
||||
expect(approvalField, findsOneWidget);
|
||||
|
||||
final transactionInput = find.descendant(
|
||||
of: transactionField,
|
||||
matching: find.byType(EditableText),
|
||||
);
|
||||
final approvalInput = find.descendant(
|
||||
of: approvalField,
|
||||
matching: find.byType(EditableText),
|
||||
);
|
||||
await tester.enterText(transactionInput.first, 'IN-TEST-001');
|
||||
await tester.enterText(approvalInput.first, 'APP-TEST-001');
|
||||
await tester.pump();
|
||||
|
||||
final productFields = find.byType(InventoryProductAutocompleteField);
|
||||
expect(productFields, findsWidgets);
|
||||
|
||||
@@ -105,7 +138,9 @@ void main() {
|
||||
await tester.enterText(firstProductInput, 'XR-5000');
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '품목 추가'));
|
||||
final addLineButton = find.widgetWithText(ShadButton, '품목 추가');
|
||||
await tester.ensureVisible(addLineButton);
|
||||
await tester.tap(addLineButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final updatedProductFields = find.byType(InventoryProductAutocompleteField);
|
||||
@@ -118,9 +153,47 @@ void main() {
|
||||
await tester.enterText(secondProductInput, 'XR-5000');
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '저장'));
|
||||
final saveButton = find.widgetWithText(ShadButton, '저장');
|
||||
await tester.ensureVisible(saveButton);
|
||||
await tester.tap(saveButton);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('동일 제품이 중복되었습니다.'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('입고 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
|
||||
final view = tester.view;
|
||||
view.physicalSize = const Size(1280, 900);
|
||||
view.devicePixelRatio = 1.0;
|
||||
addTearDown(() {
|
||||
view.resetPhysicalSize();
|
||||
view.resetDevicePixelRatio();
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ScaffoldMessenger(
|
||||
child: PermissionScope(
|
||||
manager: PermissionManager(),
|
||||
child: ShadTheme(
|
||||
data: SuperportShadTheme.light(),
|
||||
child: Scaffold(
|
||||
body: InboundPage(routeUri: Uri.parse('/inventory/inbound')),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '입고 등록'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '저장'));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
|
||||
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
||||
63
test/features/inventory/outbound_page_test.dart
Normal file
63
test/features/inventory/outbound_page_test.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import 'package:superport_v2/core/config/environment.dart';
|
||||
import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
import 'package:superport_v2/core/theme/superport_shad_theme.dart';
|
||||
import 'package:superport_v2/features/inventory/outbound/presentation/pages/outbound_page.dart';
|
||||
|
||||
import '../../helpers/inventory_test_stubs.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUpAll(() async {
|
||||
await Environment.initialize();
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
registerInventoryTestStubs();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await GetIt.I.reset();
|
||||
});
|
||||
|
||||
testWidgets('출고 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
|
||||
final view = tester.view;
|
||||
view.physicalSize = const Size(1280, 900);
|
||||
view.devicePixelRatio = 1.0;
|
||||
addTearDown(() {
|
||||
view.resetPhysicalSize();
|
||||
view.resetDevicePixelRatio();
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ScaffoldMessenger(
|
||||
child: PermissionScope(
|
||||
manager: PermissionManager(),
|
||||
child: ShadTheme(
|
||||
data: SuperportShadTheme.light(),
|
||||
child: Scaffold(
|
||||
body: OutboundPage(routeUri: Uri.parse('/inventory/outbound')),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '출고 등록'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '저장'));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
|
||||
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
63
test/features/inventory/rental_page_test.dart
Normal file
63
test/features/inventory/rental_page_test.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import 'package:superport_v2/core/config/environment.dart';
|
||||
import 'package:superport_v2/core/permissions/permission_manager.dart';
|
||||
import 'package:superport_v2/core/theme/superport_shad_theme.dart';
|
||||
import 'package:superport_v2/features/inventory/rental/presentation/pages/rental_page.dart';
|
||||
|
||||
import '../../helpers/inventory_test_stubs.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUpAll(() async {
|
||||
await Environment.initialize();
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
registerInventoryTestStubs();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await GetIt.I.reset();
|
||||
});
|
||||
|
||||
testWidgets('대여 등록 모달은 거래번호와 결재번호를 필수로 요구한다', (tester) async {
|
||||
final view = tester.view;
|
||||
view.physicalSize = const Size(1280, 900);
|
||||
view.devicePixelRatio = 1.0;
|
||||
addTearDown(() {
|
||||
view.resetPhysicalSize();
|
||||
view.resetDevicePixelRatio();
|
||||
});
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ScaffoldMessenger(
|
||||
child: PermissionScope(
|
||||
manager: PermissionManager(),
|
||||
child: ShadTheme(
|
||||
data: SuperportShadTheme.light(),
|
||||
child: Scaffold(
|
||||
body: RentalPage(routeUri: Uri.parse('/inventory/rental')),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '대여 등록'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.widgetWithText(ShadButton, '저장'));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('거래번호를 입력하세요.'), findsOneWidget);
|
||||
expect(find.text('결재번호를 입력하세요.'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
@@ -22,38 +22,19 @@ void main() {
|
||||
repository = TransactionCustomerRepositoryRemote(apiClient: apiClient);
|
||||
});
|
||||
|
||||
Map<String, dynamic> customerResponse() {
|
||||
return {
|
||||
'data': {
|
||||
'customers': [
|
||||
{
|
||||
'id': 301,
|
||||
'customer': {
|
||||
'id': 700,
|
||||
'customer_code': 'C-1',
|
||||
'customer_name': '슈퍼포트',
|
||||
},
|
||||
'note': '테스트',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('addCustomers는 거래 ID를 포함해 POST 요청을 보낸다', () async {
|
||||
const path = '/api/v1/stock-transactions/77/customers';
|
||||
when(
|
||||
() => apiClient.post<Map<String, dynamic>>(
|
||||
() => apiClient.post<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => Response<Map<String, dynamic>>(
|
||||
data: customerResponse(),
|
||||
(_) async => Response<void>(
|
||||
requestOptions: RequestOptions(path: path),
|
||||
statusCode: 200,
|
||||
statusCode: 204,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -63,7 +44,7 @@ void main() {
|
||||
|
||||
final payload =
|
||||
verify(
|
||||
() => apiClient.post<Map<String, dynamic>>(
|
||||
() => apiClient.post<void>(
|
||||
captureAny(),
|
||||
data: captureAny(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
@@ -79,17 +60,16 @@ void main() {
|
||||
test('updateCustomers는 PATCH 요청을 보낸다', () async {
|
||||
const path = '/api/v1/stock-transactions/77/customers';
|
||||
when(
|
||||
() => apiClient.patch<Map<String, dynamic>>(
|
||||
() => apiClient.patch<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => Response<Map<String, dynamic>>(
|
||||
data: customerResponse(),
|
||||
(_) async => Response<void>(
|
||||
requestOptions: RequestOptions(path: path),
|
||||
statusCode: 200,
|
||||
statusCode: 204,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -98,7 +78,7 @@ void main() {
|
||||
]);
|
||||
|
||||
verify(
|
||||
() => apiClient.patch<Map<String, dynamic>>(
|
||||
() => apiClient.patch<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
|
||||
@@ -22,36 +22,19 @@ void main() {
|
||||
repository = TransactionLineRepositoryRemote(apiClient: apiClient);
|
||||
});
|
||||
|
||||
Map<String, dynamic> lineResponse() {
|
||||
return {
|
||||
'data': {
|
||||
'lines': [
|
||||
{
|
||||
'id': 101,
|
||||
'line_no': 1,
|
||||
'product': {'id': 11, 'product_code': 'P-1', 'product_name': '품목'},
|
||||
'quantity': 3,
|
||||
'unit_price': 1000,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('addLines는 거래 ID를 포함한 POST 요청을 보낸다', () async {
|
||||
const path = '/api/v1/stock-transactions/50/lines';
|
||||
when(
|
||||
() => apiClient.post<Map<String, dynamic>>(
|
||||
() => apiClient.post<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => Response<Map<String, dynamic>>(
|
||||
data: lineResponse(),
|
||||
(_) async => Response<void>(
|
||||
requestOptions: RequestOptions(path: path),
|
||||
statusCode: 200,
|
||||
statusCode: 204,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -66,7 +49,7 @@ void main() {
|
||||
|
||||
final payload =
|
||||
verify(
|
||||
() => apiClient.post<Map<String, dynamic>>(
|
||||
() => apiClient.post<void>(
|
||||
captureAny(),
|
||||
data: captureAny(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
@@ -82,17 +65,16 @@ void main() {
|
||||
test('updateLines는 PATCH 요청을 사용한다', () async {
|
||||
const path = '/api/v1/stock-transactions/50/lines';
|
||||
when(
|
||||
() => apiClient.patch<Map<String, dynamic>>(
|
||||
() => apiClient.patch<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => Response<Map<String, dynamic>>(
|
||||
data: lineResponse(),
|
||||
(_) async => Response<void>(
|
||||
requestOptions: RequestOptions(path: path),
|
||||
statusCode: 200,
|
||||
statusCode: 204,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -101,7 +83,7 @@ void main() {
|
||||
]);
|
||||
|
||||
verify(
|
||||
() => apiClient.patch<Map<String, dynamic>>(
|
||||
() => apiClient.patch<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
@@ -141,31 +123,28 @@ void main() {
|
||||
test('restoreLine은 복구 엔드포인트를 호출한다', () async {
|
||||
const path = '/api/v1/transaction-lines/101/restore';
|
||||
when(
|
||||
() => apiClient.post<Map<String, dynamic>>(
|
||||
() => apiClient.post<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).thenAnswer(
|
||||
(_) async => Response<Map<String, dynamic>>(
|
||||
data: {
|
||||
'data': {
|
||||
'id': 101,
|
||||
'line_no': 1,
|
||||
'product': {'id': 11, 'product_code': 'P-1', 'product_name': '품목'},
|
||||
'quantity': 3,
|
||||
'unit_price': 1000,
|
||||
},
|
||||
},
|
||||
(_) async => Response<void>(
|
||||
requestOptions: RequestOptions(path: path),
|
||||
statusCode: 200,
|
||||
statusCode: 204,
|
||||
),
|
||||
);
|
||||
|
||||
final line = await repository.restoreLine(101);
|
||||
await repository.restoreLine(101);
|
||||
|
||||
expect(line.id, 101);
|
||||
expect(line.lineNo, 1);
|
||||
verify(
|
||||
() => apiClient.post<void>(
|
||||
path,
|
||||
data: any(named: 'data'),
|
||||
options: any(named: 'options'),
|
||||
cancelToken: any(named: 'cancelToken'),
|
||||
),
|
||||
).called(1);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user