feat(frontend): 승인 템플릿 API 통합 및 디버그 로그인 확장
- docs 폴더 문서를 최신 API 계약으로 갱신하고 가이드를 다듬었다\n- approvals data/presentation 레이어를 API v4 스펙에 맞춰 리팩터링했다\n- approver 자동완성 위젯을 신규 공유 레포지토리에 맞춰 교체하고 UX를 보강했다\n- inventory/rental 페이지 테이블 초기화 시 승인 기준 연동을 정비했다\n- 로그인 페이지 디버그 버튼을 tera/exa 계정으로 분리해 QA 로그인을 단순화했다\n- get_it 등록과 테스트 케이스를 신규 공유 리포지토리에 맞춰 업데이트했다
This commit is contained in:
@@ -1,13 +1,30 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import 'package:superport_v2/features/approvals/domain/entities/approval.dart';
|
||||
import 'package:superport_v2/features/approvals/request/presentation/controllers/approval_request_controller.dart';
|
||||
import 'package:superport_v2/features/approvals/request/presentation/utils/approval_form_initializer.dart';
|
||||
import 'package:superport_v2/features/approvals/shared/domain/entities/approval_approver_candidate.dart';
|
||||
import 'package:superport_v2/features/approvals/shared/domain/repositories/approval_approver_repository.dart';
|
||||
import 'package:superport_v2/features/inventory/transactions/domain/entities/stock_transaction_input.dart';
|
||||
|
||||
void main() {
|
||||
final getIt = GetIt.I;
|
||||
|
||||
setUp(() {
|
||||
if (getIt.isRegistered<ApprovalApproverRepository>()) {
|
||||
getIt.unregister<ApprovalApproverRepository>();
|
||||
}
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (getIt.isRegistered<ApprovalApproverRepository>()) {
|
||||
getIt.unregister<ApprovalApproverRepository>();
|
||||
}
|
||||
});
|
||||
|
||||
group('ApprovalFormInitializer.populate', () {
|
||||
test('초안 저장본이 있으면 상신자와 단계를 복구한다', () {
|
||||
test('초안 저장본이 있으면 상신자와 단계를 복구한다', () async {
|
||||
final controller = ApprovalRequestController();
|
||||
final draft = StockTransactionApprovalInput(
|
||||
requestedById: 101,
|
||||
@@ -17,7 +34,18 @@ void main() {
|
||||
],
|
||||
);
|
||||
|
||||
ApprovalFormInitializer.populate(controller: controller, draft: draft);
|
||||
getIt.registerSingleton<ApprovalApproverRepository>(
|
||||
_FakeApproverRepository({
|
||||
101: _candidate(id: 101, name: '요청자'),
|
||||
104: _candidate(id: 104, name: '1단계 승인자'),
|
||||
201: _candidate(id: 201, name: '최종 승인자'),
|
||||
}),
|
||||
);
|
||||
|
||||
await ApprovalFormInitializer.populate(
|
||||
controller: controller,
|
||||
draft: draft,
|
||||
);
|
||||
|
||||
expect(controller.requester?.id, equals(101));
|
||||
expect(controller.steps.length, equals(2));
|
||||
@@ -25,7 +53,7 @@ void main() {
|
||||
expect(controller.steps.last.approver.id, equals(201));
|
||||
});
|
||||
|
||||
test('카탈로그에 없는 승인자는 복구 대상에서 제외한다', () {
|
||||
test('조회 실패 시 해당 승인자는 복구 대상에서 제외한다', () async {
|
||||
final controller = ApprovalRequestController();
|
||||
final draft = StockTransactionApprovalInput(
|
||||
requestedById: 101,
|
||||
@@ -35,10 +63,53 @@ void main() {
|
||||
],
|
||||
);
|
||||
|
||||
ApprovalFormInitializer.populate(controller: controller, draft: draft);
|
||||
getIt.registerSingleton<ApprovalApproverRepository>(
|
||||
_FakeApproverRepository({
|
||||
101: _candidate(id: 101, name: '요청자'),
|
||||
104: _candidate(id: 104, name: '1단계 승인자'),
|
||||
}),
|
||||
);
|
||||
|
||||
await ApprovalFormInitializer.populate(
|
||||
controller: controller,
|
||||
draft: draft,
|
||||
);
|
||||
|
||||
expect(controller.steps.length, equals(1));
|
||||
expect(controller.steps.first.approver.id, equals(104));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ApprovalApproverCandidate _candidate({required int id, required String name}) {
|
||||
return ApprovalApproverCandidate(
|
||||
id: id,
|
||||
employeeNo: 'EMP$id',
|
||||
name: name,
|
||||
team: '팀',
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeApproverRepository implements ApprovalApproverRepository {
|
||||
_FakeApproverRepository(this._candidates);
|
||||
|
||||
final Map<int, ApprovalApproverCandidate> _candidates;
|
||||
|
||||
@override
|
||||
Future<ApprovalApproverCandidate?> fetchById(int id) async {
|
||||
return _candidates[id];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ApprovalApproverCandidate>> search({
|
||||
required String keyword,
|
||||
int limit = 20,
|
||||
}) async {
|
||||
return _candidates.values.toList(growable: false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ApprovalApproverCandidate>> listInitial({int limit = 20}) async {
|
||||
return _candidates.values.take(limit).toList(growable: false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user