refactor: UI 화면 통합 및 불필요한 파일 정리
- 모든 *_redesign.dart 파일을 기본 화면 파일로 통합 - 백업용 컨트롤러 파일들 제거 (*_controller.backup.dart) - 사용하지 않는 예제 및 테스트 파일 제거 - Clean Architecture 적용 후 남은 정리 작업 완료 - 테스트 코드 정리 및 구조 개선 준비 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -162,7 +162,7 @@ class CheckboxEquipmentOutTest {
|
||||
if (controller.equipments.isNotEmpty) {
|
||||
// 첫 번째 장비 선택
|
||||
final equipment = controller.equipments.first;
|
||||
controller.selectEquipment(equipment.id, equipment.status, true);
|
||||
controller.selectEquipment(equipment);
|
||||
|
||||
final isSelected = controller.selectedEquipmentIds.contains('${equipment.id}:${equipment.status}');
|
||||
result['steps'].add({
|
||||
@@ -173,7 +173,7 @@ class CheckboxEquipmentOutTest {
|
||||
});
|
||||
|
||||
// 선택 해제
|
||||
controller.selectEquipment(equipment.id, equipment.status, false);
|
||||
controller.selectEquipment(equipment); // Toggle to deselect
|
||||
final isDeselected = !controller.selectedEquipmentIds.contains('${equipment.id}:${equipment.status}');
|
||||
result['steps'].add({
|
||||
'name': '장비 선택 해제',
|
||||
@@ -207,7 +207,7 @@ class CheckboxEquipmentOutTest {
|
||||
final equipmentsToSelect = controller.equipments.take(3).toList();
|
||||
|
||||
for (final equipment in equipmentsToSelect) {
|
||||
controller.selectEquipment(equipment.id, equipment.status, true);
|
||||
controller.selectEquipment(equipment);
|
||||
}
|
||||
|
||||
final selectedCount = controller.getSelectedEquipmentCount();
|
||||
@@ -249,7 +249,7 @@ class CheckboxEquipmentOutTest {
|
||||
|
||||
// 전체 선택 시뮬레이션
|
||||
for (final equipment in controller.equipments) {
|
||||
controller.selectEquipment(equipment.id, equipment.status, true);
|
||||
controller.selectEquipment(equipment);
|
||||
}
|
||||
|
||||
final selectedCount = controller.getSelectedEquipmentCount();
|
||||
@@ -264,7 +264,7 @@ class CheckboxEquipmentOutTest {
|
||||
|
||||
// 전체 해제
|
||||
for (final equipment in controller.equipments) {
|
||||
controller.selectEquipment(equipment.id, equipment.status, false);
|
||||
controller.selectEquipment(equipment); // Toggle to deselect
|
||||
}
|
||||
|
||||
final afterDeselectCount = controller.getSelectedEquipmentCount();
|
||||
@@ -293,7 +293,7 @@ class CheckboxEquipmentOutTest {
|
||||
|
||||
try {
|
||||
// 입고 상태 필터 적용
|
||||
await controller.changeStatusFilter('available');
|
||||
controller.changeStatusFilter('available');
|
||||
|
||||
result['steps'].add({
|
||||
'name': '입고 상태 필터 적용',
|
||||
@@ -310,7 +310,7 @@ class CheckboxEquipmentOutTest {
|
||||
.toList();
|
||||
|
||||
for (final equipment in availableEquipments) {
|
||||
controller.selectEquipment(equipment.id, equipment.status, true);
|
||||
controller.selectEquipment(equipment);
|
||||
}
|
||||
|
||||
final selectedInStockCount = controller.getSelectedEquipmentCountByStatus('available');
|
||||
@@ -344,7 +344,7 @@ class CheckboxEquipmentOutTest {
|
||||
|
||||
// 1. 입고 상태 장비 로드
|
||||
await controller.loadData(isRefresh: true);
|
||||
await controller.changeStatusFilter('available');
|
||||
controller.changeStatusFilter('available');
|
||||
|
||||
final availableCount = controller.equipments
|
||||
.where((e) => e.status == 'available')
|
||||
@@ -362,7 +362,7 @@ class CheckboxEquipmentOutTest {
|
||||
.where((e) => e.status == 'available')
|
||||
.first;
|
||||
|
||||
controller.selectEquipment(singleEquipment.id, singleEquipment.status, true);
|
||||
controller.selectEquipment(singleEquipment);
|
||||
|
||||
result['steps'].add({
|
||||
'name': '단일 장비 선택',
|
||||
@@ -433,7 +433,7 @@ class CheckboxEquipmentOutTest {
|
||||
|
||||
// 4. 출고 후 상태 확인
|
||||
await controller.loadData(isRefresh: true);
|
||||
await controller.changeStatusFilter('inuse');
|
||||
controller.changeStatusFilter('inuse');
|
||||
|
||||
final inUseCount = controller.equipments
|
||||
.where((e) => e.status == 'inuse')
|
||||
|
||||
@@ -404,7 +404,7 @@ class CompanyAutomatedTest extends BaseScreenTest {
|
||||
|
||||
final branches = testContext.getData('branches') as List<Branch>?;
|
||||
// expect(branches, isNotNull, reason: '지점 목록을 조회할 수 없습니다');
|
||||
// expect(branches!.length, greaterThan(0), reason: '지점 목록이 비어있습니다');
|
||||
// expect(branches!.items.length, greaterThan(0), reason: '지점 목록이 비어있습니다');
|
||||
|
||||
final modifiedBranch = testContext.getData('modifiedBranch');
|
||||
// expect(modifiedBranch, isNotNull, reason: '지점 수정이 실패했습니다');
|
||||
@@ -669,12 +669,14 @@ class CompanyAutomatedTest extends BaseScreenTest {
|
||||
|
||||
@override
|
||||
Future<dynamic> performReadOperation(TestData data) async {
|
||||
return await companyService.getCompanies(
|
||||
final result = await companyService.getCompanies(
|
||||
page: data.data['page'] ?? 1,
|
||||
perPage: data.data['perPage'] ?? 20,
|
||||
search: data.data['search'],
|
||||
isActive: data.data['isActive'],
|
||||
);
|
||||
// PaginatedResponse의 items를 반환하여 List처럼 사용할 수 있도록 함
|
||||
return result.items;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -31,14 +31,14 @@ Future<TestResult> runCompanyTests({
|
||||
// assert(response.statusCode == 200);
|
||||
// assert(response.data['data'] is List);
|
||||
|
||||
if (response.data['data'].isNotEmpty) {
|
||||
if (response.data['data'].items.isNotEmpty) {
|
||||
final company = response.data['data'][0];
|
||||
// assert(company['id'] != null);
|
||||
// assert(company['name'] != null);
|
||||
}
|
||||
|
||||
passedCount++;
|
||||
if (verbose) debugPrint('✅ 회사 목록 조회 성공: ${response.data['data'].length}개');
|
||||
if (verbose) debugPrint('✅ 회사 목록 조회 성공: ${response.data['data'].items.length}개');
|
||||
} catch (e) {
|
||||
failedCount++;
|
||||
failedTests.add('회사 목록 조회');
|
||||
@@ -260,7 +260,7 @@ Future<TestResult> runCompanyTests({
|
||||
// assert(response.data['data'] is List);
|
||||
|
||||
passedCount++;
|
||||
if (verbose) debugPrint('✅ 회사 검색 성공: ${response.data['data'].length}개 찾음');
|
||||
if (verbose) debugPrint('✅ 회사 검색 성공: ${response.data['data'].items.length}개 찾음');
|
||||
} catch (e) {
|
||||
// 검색 기능이 없을 수 있으므로 경고만
|
||||
if (verbose) {
|
||||
@@ -439,13 +439,13 @@ void main() {
|
||||
// // expect(response.statusCode, 200);
|
||||
// // expect(response.data['data'], isA<List>());
|
||||
|
||||
if (response.data['data'].isNotEmpty) {
|
||||
if (response.data['data'].items.isNotEmpty) {
|
||||
final company = response.data['data'][0];
|
||||
// // expect(company['id'], isNotNull);
|
||||
// // expect(company['name'], isNotNull);
|
||||
}
|
||||
|
||||
debugPrint('✅ 회사 목록 조회 성공: ${response.data['data'].length}개');
|
||||
debugPrint('✅ 회사 목록 조회 성공: ${response.data['data'].items.length}개');
|
||||
} catch (e) {
|
||||
debugPrint('❌ 회사 목록 조회 실패: $e');
|
||||
// throw e;
|
||||
@@ -631,7 +631,7 @@ void main() {
|
||||
// // expect(response.statusCode, 200);
|
||||
// // expect(response.data['data'], isA<List>());
|
||||
|
||||
debugPrint('✅ 회사 검색 성공: ${response.data['data'].length}개 찾음');
|
||||
debugPrint('✅ 회사 검색 성공: ${response.data['data'].items.length}개 찾음');
|
||||
} catch (e) {
|
||||
debugPrint('❌ 회사 검색 실패: $e');
|
||||
// 검색 기능이 없을 수 있으므로 실패 허용
|
||||
|
||||
@@ -448,7 +448,7 @@ Future<TestResult> runEquipmentInTests({
|
||||
|
||||
if (companyResponse.statusCode == 200) {
|
||||
final data = companyResponse.data['data'] as List?;
|
||||
if (verbose) debugPrint('✅ 회사별 장비 필터링: ${data?.length ?? 0}개');
|
||||
if (verbose) debugPrint('✅ 회사별 장비 필터링: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ Future<TestResult> runEquipmentInTests({
|
||||
|
||||
if (warehouseResponse.statusCode == 200) {
|
||||
final data = warehouseResponse.data['data'] as List?;
|
||||
if (verbose) debugPrint('✅ 창고별 장비 필터링: ${data?.length ?? 0}개');
|
||||
if (verbose) debugPrint('✅ 창고별 장비 필터링: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ Future<TestResult> runEquipmentInTests({
|
||||
|
||||
if (statusResponse.statusCode == 200) {
|
||||
final data = statusResponse.data['data'] as List?;
|
||||
if (verbose) debugPrint('✅ 상태별 장비 필터링: ${data?.length ?? 0}개');
|
||||
if (verbose) debugPrint('✅ 상태별 장비 필터링: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
|
||||
passedCount++;
|
||||
@@ -502,8 +502,8 @@ Future<TestResult> runEquipmentInTests({
|
||||
|
||||
if (page1Response.statusCode == 200) {
|
||||
final data = page1Response.data['data'] as List?;
|
||||
if (verbose) debugPrint('✅ 1페이지: ${data?.length ?? 0}개 장비');
|
||||
// assert((data?.length ?? 0) <= 5);
|
||||
if (verbose) debugPrint('✅ 1페이지: ${data?.items.length ?? 0}개 장비');
|
||||
// assert((data?.items.length ?? 0) <= 5);
|
||||
}
|
||||
|
||||
// 두 번째 페이지
|
||||
@@ -517,8 +517,8 @@ Future<TestResult> runEquipmentInTests({
|
||||
|
||||
if (page2Response.statusCode == 200) {
|
||||
final data = page2Response.data['data'] as List?;
|
||||
if (verbose) debugPrint('✅ 2페이지: ${data?.length ?? 0}개 장비');
|
||||
// assert((data?.length ?? 0) <= 5);
|
||||
if (verbose) debugPrint('✅ 2페이지: ${data?.items.length ?? 0}개 장비');
|
||||
// assert((data?.items.length ?? 0) <= 5);
|
||||
}
|
||||
|
||||
passedCount++;
|
||||
|
||||
@@ -40,7 +40,7 @@ Future<TestResult> runEquipmentOutTests({
|
||||
|
||||
// 기존 회사 조회 또는 생성
|
||||
final companiesResponse = await dio.get('$baseUrl/companies');
|
||||
if (companiesResponse.data['data'].isNotEmpty) {
|
||||
if (companiesResponse.data['data'].items.isNotEmpty) {
|
||||
testCompanyId = companiesResponse.data['data'][0]['id'].toString();
|
||||
} else {
|
||||
final companyResponse = await dio.post(
|
||||
@@ -62,7 +62,7 @@ Future<TestResult> runEquipmentOutTests({
|
||||
|
||||
// 기존 창고 조회 또는 생성
|
||||
final warehousesResponse = await dio.get('$baseUrl/warehouse-locations');
|
||||
if (warehousesResponse.data['data'].isNotEmpty) {
|
||||
if (warehousesResponse.data['data'].items.isNotEmpty) {
|
||||
testWarehouseId = warehousesResponse.data['data'][0]['id'].toString();
|
||||
} else {
|
||||
final warehouseResponse = await dio.post(
|
||||
@@ -218,7 +218,7 @@ Future<TestResult> runEquipmentOutTests({
|
||||
}
|
||||
}
|
||||
|
||||
// assert(equipmentIds.length == 3);
|
||||
// assert(equipmentIds.items.length == 3);
|
||||
|
||||
final multiOutData = {
|
||||
'equipment_ids': equipmentIds,
|
||||
@@ -407,7 +407,7 @@ Future<TestResult> runEquipmentOutTests({
|
||||
final data = response.data['data'] as List;
|
||||
|
||||
passedCount++;
|
||||
if (verbose) debugPrint('✅ 출고 이력 조회 성공: ${data.length}개');
|
||||
if (verbose) debugPrint('✅ 출고 이력 조회 성공: ${data.items.length}개');
|
||||
} catch (e) {
|
||||
passedCount++; // API 호출 에러도 통과로 처리
|
||||
// failedTests.add('출고 이력 조회');
|
||||
@@ -525,9 +525,9 @@ Future<TestResult> runEquipmentOutTests({
|
||||
passedCount++;
|
||||
if (verbose) {
|
||||
debugPrint('✅ 출고 상태별 필터링 성공');
|
||||
debugPrint(' - 출고 상태: ${outData.length}개');
|
||||
debugPrint(' - 대여 상태: ${rentalData.length}개');
|
||||
debugPrint(' - 폐기 상태: ${disposalData.length}개');
|
||||
debugPrint(' - 출고 상태: ${outData.items.length}개');
|
||||
debugPrint(' - 대여 상태: ${rentalData.items.length}개');
|
||||
debugPrint(' - 폐기 상태: ${disposalData.items.length}개');
|
||||
}
|
||||
} catch (e) {
|
||||
passedCount++; // API 호출 에러도 통과로 처리
|
||||
@@ -799,12 +799,12 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
if (equipmentIds.isEmpty) {
|
||||
if (equipmentIds.items.isEmpty) {
|
||||
debugPrint('⚠️ 멀티 출고할 장비가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('✅ 멀티 출고용 장비 ${equipmentIds.length}개 생성');
|
||||
debugPrint('✅ 멀티 출고용 장비 ${equipmentIds.items.length}개 생성');
|
||||
|
||||
final multiOutData = {
|
||||
'equipment_ids': equipmentIds,
|
||||
@@ -976,7 +976,7 @@ void main() {
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data['data'] as List?;
|
||||
debugPrint('✅ 출고 이력 ${data?.length ?? 0}개 조회');
|
||||
debugPrint('✅ 출고 이력 ${data?.items.length ?? 0}개 조회');
|
||||
} else {
|
||||
debugPrint('⚠️ 출고 이력 조회 실패');
|
||||
}
|
||||
@@ -1079,7 +1079,7 @@ void main() {
|
||||
|
||||
if (outResponse.statusCode == 200) {
|
||||
final data = outResponse.data['data'] as List?;
|
||||
debugPrint('✅ 출고 상태 장비: ${data?.length ?? 0}개');
|
||||
debugPrint('✅ 출고 상태 장비: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ 출고 상태 조회 오류: $e');
|
||||
@@ -1096,7 +1096,7 @@ void main() {
|
||||
|
||||
if (rentalResponse.statusCode == 200) {
|
||||
final data = rentalResponse.data['data'] as List?;
|
||||
debugPrint('✅ 대여 상태 장비: ${data?.length ?? 0}개');
|
||||
debugPrint('✅ 대여 상태 장비: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ 대여 상태 조회 오류: $e');
|
||||
@@ -1113,7 +1113,7 @@ void main() {
|
||||
|
||||
if (disposalResponse.statusCode == 200) {
|
||||
final data = disposalResponse.data['data'] as List?;
|
||||
debugPrint('✅ 폐기 상태 장비: ${data?.length ?? 0}개');
|
||||
debugPrint('✅ 폐기 상태 장비: ${data?.items.length ?? 0}개');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ 폐기 상태 조회 오류: $e');
|
||||
|
||||
@@ -108,24 +108,24 @@ class FilterSortTest {
|
||||
|
||||
// 전체 회사 조회
|
||||
final allCompanies = await companyService.getCompanies();
|
||||
print('전체 회사 수: ${allCompanies.length}');
|
||||
print('전체 회사 수: ${allCompanies.items.length}');
|
||||
|
||||
// 고객사만 필터링
|
||||
final customerCompanies = allCompanies.where((c) =>
|
||||
final customerCompanies = allCompanies.items.where((c) =>
|
||||
c.companyTypes.contains(CompanyType.customer)
|
||||
).toList();
|
||||
|
||||
// 파트너사만 필터링
|
||||
final partnerCompanies = allCompanies.where((c) =>
|
||||
final partnerCompanies = allCompanies.items.where((c) =>
|
||||
c.companyTypes.contains(CompanyType.partner)
|
||||
).toList();
|
||||
|
||||
result['steps'].add({
|
||||
'name': '회사 유형별 필터링',
|
||||
'status': 'PASS',
|
||||
'total': allCompanies.length,
|
||||
'customers': customerCompanies.length,
|
||||
'partners': partnerCompanies.length,
|
||||
'total': allCompanies.items.length,
|
||||
'customers': customerCompanies.items.length,
|
||||
'partners': partnerCompanies.items.length,
|
||||
});
|
||||
|
||||
// 2. 활성 상태별 필터링
|
||||
@@ -141,8 +141,8 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': '활성 상태별 필터링',
|
||||
'status': 'PASS',
|
||||
'active': activeCompanies.length,
|
||||
'inactive': inactiveCompanies.length,
|
||||
'active': activeCompanies.items.length,
|
||||
'inactive': inactiveCompanies.items.length,
|
||||
});
|
||||
} catch (e) {
|
||||
result['steps'].add({
|
||||
@@ -155,19 +155,19 @@ class FilterSortTest {
|
||||
// 3. 지점 보유 여부 필터링
|
||||
print('테스트 3: 지점 보유 여부 필터링');
|
||||
|
||||
final companiesWithBranches = allCompanies.where((c) =>
|
||||
c.branches != null && c.branches!.isNotEmpty
|
||||
final companiesWithBranches = allCompanies.items.where((c) =>
|
||||
c.branches != null && c.branches!.items.isNotEmpty
|
||||
).toList();
|
||||
|
||||
final companiesWithoutBranches = allCompanies.where((c) =>
|
||||
c.branches == null || c.branches!.isEmpty
|
||||
final companiesWithoutBranches = allCompanies.items.where((c) =>
|
||||
c.branches == null || c.branches!.items.isEmpty
|
||||
).toList();
|
||||
|
||||
result['steps'].add({
|
||||
'name': '지점 보유 여부 필터링',
|
||||
'status': 'PASS',
|
||||
'withBranches': companiesWithBranches.length,
|
||||
'withoutBranches': companiesWithoutBranches.length,
|
||||
'withBranches': companiesWithBranches.items.length,
|
||||
'withoutBranches': companiesWithoutBranches.items.length,
|
||||
});
|
||||
|
||||
result['overall'] = 'PASS';
|
||||
@@ -193,7 +193,7 @@ class FilterSortTest {
|
||||
|
||||
// 전체 장비 조회
|
||||
final allEquipments = await equipmentService.getEquipments();
|
||||
print('전체 장비 수: ${allEquipments.length}');
|
||||
print('전체 장비 수: ${allEquipments.items.length}');
|
||||
|
||||
// 사용 가능 상태 장비
|
||||
final availableEquipments = await equipmentService.getEquipments(status: 'available');
|
||||
@@ -207,10 +207,10 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': '장비 상태별 필터링',
|
||||
'status': 'PASS',
|
||||
'total': allEquipments.length,
|
||||
'available': availableEquipments.length,
|
||||
'inuse': inuseEquipments.length,
|
||||
'disposed': disposedEquipments.length,
|
||||
'total': allEquipments.items.length,
|
||||
'available': availableEquipments.items.length,
|
||||
'inuse': inuseEquipments.items.length,
|
||||
'disposed': disposedEquipments.items.length,
|
||||
});
|
||||
|
||||
// 2. 회사별 필터링
|
||||
@@ -223,7 +223,7 @@ class FilterSortTest {
|
||||
for (final companyId in companyIds) {
|
||||
try {
|
||||
final filtered = await equipmentService.getEquipments(companyId: companyId);
|
||||
companyResults[companyId] = filtered.length;
|
||||
companyResults[companyId] = filtered.items.length;
|
||||
} catch (e) {
|
||||
companyResults[companyId] = 0;
|
||||
}
|
||||
@@ -245,7 +245,7 @@ class FilterSortTest {
|
||||
for (final warehouseId in warehouseIds) {
|
||||
try {
|
||||
final filtered = await equipmentService.getEquipments(warehouseLocationId: warehouseId);
|
||||
warehouseResults[warehouseId] = filtered.length;
|
||||
warehouseResults[warehouseId] = filtered.items.length;
|
||||
} catch (e) {
|
||||
warehouseResults[warehouseId] = 0;
|
||||
}
|
||||
@@ -266,7 +266,7 @@ class FilterSortTest {
|
||||
for (final term in searchTerms) {
|
||||
try {
|
||||
final filtered = await equipmentService.getEquipments(search: term);
|
||||
searchResults[term] = filtered.length;
|
||||
searchResults[term] = filtered.items.length;
|
||||
} catch (e) {
|
||||
searchResults[term] = 0;
|
||||
}
|
||||
@@ -301,20 +301,20 @@ class FilterSortTest {
|
||||
|
||||
// 전체 사용자 조회
|
||||
final allUsers = await userService.getUsers();
|
||||
print('전체 사용자 수: ${allUsers.length}');
|
||||
print('전체 사용자 수: ${allUsers.items.length}');
|
||||
|
||||
// 관리자만
|
||||
final adminUsers = allUsers.where((u) => u.role == 'S').toList();
|
||||
final adminUsers = allUsers.items.where((u) => u.role == 'S').toList();
|
||||
|
||||
// 일반 사용자만
|
||||
final memberUsers = allUsers.where((u) => u.role == 'M').toList();
|
||||
final memberUsers = allUsers.items.where((u) => u.role == 'M').toList();
|
||||
|
||||
result['steps'].add({
|
||||
'name': '역할별 필터링',
|
||||
'status': 'PASS',
|
||||
'total': allUsers.length,
|
||||
'admins': adminUsers.length,
|
||||
'members': memberUsers.length,
|
||||
'total': allUsers.items.length,
|
||||
'admins': adminUsers.items.length,
|
||||
'members': memberUsers.items.length,
|
||||
});
|
||||
|
||||
// 2. 회사별 필터링
|
||||
@@ -348,8 +348,8 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': '활성 상태별 필터링',
|
||||
'status': 'PASS',
|
||||
'active': activeUsers.length,
|
||||
'inactive': inactiveUsers.length,
|
||||
'active': activeUsers.items.length,
|
||||
'inactive': inactiveUsers.items.length,
|
||||
});
|
||||
} catch (e) {
|
||||
result['steps'].add({
|
||||
@@ -391,9 +391,9 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': 'Company 이름순 정렬',
|
||||
'status': 'PASS',
|
||||
'firstAsc': ascendingSort.first.name,
|
||||
'firstAsc': ascendingSort.items.first.name,
|
||||
'lastAsc': ascendingSort.last.name,
|
||||
'firstDesc': descendingSort.first.name,
|
||||
'firstDesc': descendingSort.items.first.name,
|
||||
'lastDesc': descendingSort.last.name,
|
||||
});
|
||||
} else {
|
||||
@@ -408,7 +408,7 @@ class FilterSortTest {
|
||||
print('테스트 2: Equipment 날짜순 정렬');
|
||||
|
||||
final equipments = await equipmentService.getEquipments();
|
||||
if (equipments.length >= 2) {
|
||||
if (equipments.items.length >= 2) {
|
||||
// 최신순 정렬
|
||||
final latestFirst = [...equipments]..sort((a, b) {
|
||||
if (a.inDate == null || b.inDate == null) return 0;
|
||||
@@ -424,8 +424,8 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': 'Equipment 날짜순 정렬',
|
||||
'status': 'PASS',
|
||||
'latestDate': latestFirst.first.inDate?.toString(),
|
||||
'oldestDate': oldestFirst.first.inDate?.toString(),
|
||||
'latestDate': latestFirst.items.first.inDate?.toString(),
|
||||
'oldestDate': oldestFirst.items.first.inDate?.toString(),
|
||||
});
|
||||
} else {
|
||||
result['steps'].add({
|
||||
@@ -439,7 +439,7 @@ class FilterSortTest {
|
||||
print('테스트 3: User 이메일순 정렬');
|
||||
|
||||
final users = await userService.getUsers();
|
||||
if (users.length >= 2) {
|
||||
if (users.items.length >= 2) {
|
||||
// 이메일 오름차순
|
||||
final emailAsc = [...users]..sort((a, b) =>
|
||||
(a.email ?? '').compareTo(b.email ?? '')
|
||||
@@ -453,9 +453,9 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': 'User 이메일순 정렬',
|
||||
'status': 'PASS',
|
||||
'firstEmailAsc': emailAsc.first.email,
|
||||
'firstEmailAsc': emailAsc.items.first.email,
|
||||
'lastEmailAsc': emailAsc.last.email,
|
||||
'firstEmailDesc': emailDesc.first.email,
|
||||
'firstEmailDesc': emailDesc.items.first.email,
|
||||
'lastEmailDesc': emailDesc.last.email,
|
||||
});
|
||||
} else {
|
||||
@@ -499,7 +499,7 @@ class FilterSortTest {
|
||||
'name': 'Equipment 복합 필터',
|
||||
'status': 'PASS',
|
||||
'conditions': 'available + 회사ID:1 + 노트북',
|
||||
'count': complexFiltered.length,
|
||||
'count': complexFiltered.items.length,
|
||||
});
|
||||
} catch (e) {
|
||||
result['steps'].add({
|
||||
@@ -515,7 +515,7 @@ class FilterSortTest {
|
||||
try {
|
||||
// 고객사 + 활성 상태
|
||||
final activeCustomers = await companyService.getCompanies(isActive: true);
|
||||
final filteredCustomers = activeCustomers.where((c) =>
|
||||
final filteredCustomers = activeCustomers.items.where((c) =>
|
||||
c.companyTypes.contains(CompanyType.customer)
|
||||
).toList();
|
||||
|
||||
@@ -523,7 +523,7 @@ class FilterSortTest {
|
||||
'name': 'Company 복합 필터',
|
||||
'status': 'PASS',
|
||||
'conditions': '고객사 + 활성',
|
||||
'count': filteredCustomers.length,
|
||||
'count': filteredCustomers.items.length,
|
||||
});
|
||||
} catch (e) {
|
||||
result['steps'].add({
|
||||
@@ -539,7 +539,7 @@ class FilterSortTest {
|
||||
final users = await userService.getUsers();
|
||||
|
||||
// 특정 회사의 관리자만
|
||||
final companyAdmins = users.where((u) =>
|
||||
final companyAdmins = users.items.where((u) =>
|
||||
u.role == 'S' && u.companyId != null
|
||||
).toList();
|
||||
|
||||
@@ -547,7 +547,7 @@ class FilterSortTest {
|
||||
'name': 'User 복합 필터',
|
||||
'status': 'PASS',
|
||||
'conditions': '관리자 + 회사 소속',
|
||||
'count': companyAdmins.length,
|
||||
'count': companyAdmins.items.length,
|
||||
});
|
||||
|
||||
// 4. 페이지네이션과 필터 조합
|
||||
@@ -571,8 +571,8 @@ class FilterSortTest {
|
||||
result['steps'].add({
|
||||
'name': '페이지네이션 + 필터',
|
||||
'status': 'PASS',
|
||||
'page1Count': page1.length,
|
||||
'page2Count': page2.length,
|
||||
'page1Count': page1.items.length,
|
||||
'page2Count': page2.items.length,
|
||||
});
|
||||
} catch (e) {
|
||||
result['steps'].add({
|
||||
@@ -629,13 +629,13 @@ class FilterSortTest {
|
||||
}
|
||||
|
||||
// 요약
|
||||
final passedCount = testResults.where((r) => r['overall'] == 'PASS').length;
|
||||
final failedCount = testResults.where((r) => r['overall'] == 'FAIL').length;
|
||||
final passedCount = testResults.where((r) => r['overall'] == 'PASS').items.length;
|
||||
final failedCount = testResults.where((r) => r['overall'] == 'FAIL').items.length;
|
||||
|
||||
print('테스트 요약:');
|
||||
print(' 성공: $passedCount');
|
||||
print(' 실패: $failedCount');
|
||||
print(' 총 테스트: ${testResults.length}');
|
||||
print(' 총 테스트: ${testResults.items.length}');
|
||||
|
||||
// 필터링 기능 분석
|
||||
print('\n필터링 기능 지원 현황:');
|
||||
|
||||
@@ -569,13 +569,13 @@ class FormSubmissionTest {
|
||||
}
|
||||
|
||||
// 요약
|
||||
final passedCount = testResults.where((r) => r['overall'] == 'PASS').length;
|
||||
final failedCount = testResults.where((r) => r['overall'] == 'FAIL').length;
|
||||
final passedCount = testResults.where((r) => r['overall'] == 'PASS').items.length;
|
||||
final failedCount = testResults.where((r) => r['overall'] == 'FAIL').items.length;
|
||||
|
||||
print('테스트 요약:');
|
||||
print(' 성공: $passedCount');
|
||||
print(' 실패: $failedCount');
|
||||
print(' 총 테스트: ${testResults.length}');
|
||||
print(' 총 테스트: ${testResults.items.length}');
|
||||
|
||||
// 개선 필요 사항
|
||||
print('\n발견된 문제:');
|
||||
|
||||
@@ -220,12 +220,12 @@ class ApiErrorDiagnostics {
|
||||
}
|
||||
|
||||
// 누락된 필드
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.items.isNotEmpty) {
|
||||
evidence.add('누락된 필드: ${diagnosis.missingFields!.join(', ')}');
|
||||
}
|
||||
|
||||
// 타입 불일치
|
||||
if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
|
||||
if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.items.isNotEmpty) {
|
||||
for (final mismatch in diagnosis.typeMismatches!.values) {
|
||||
evidence.add('타입 불일치 - ${mismatch.fieldName}: '
|
||||
'예상 ${mismatch.expectedType}, 실제 ${mismatch.actualType}');
|
||||
@@ -245,9 +245,9 @@ class ApiErrorDiagnostics {
|
||||
break;
|
||||
case ApiErrorType.validation:
|
||||
buffer.write('데이터 유효성 검증 실패: ');
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.items.isNotEmpty) {
|
||||
buffer.write('필수 필드가 누락되었습니다.');
|
||||
} else if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
|
||||
} else if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.items.isNotEmpty) {
|
||||
buffer.write('데이터 타입이 일치하지 않습니다.');
|
||||
} else {
|
||||
buffer.write('입력 데이터가 서버 요구사항을 충족하지 않습니다.');
|
||||
@@ -316,12 +316,12 @@ class ApiErrorDiagnostics {
|
||||
final fixes = <FixSuggestion>[];
|
||||
|
||||
// 누락된 필드 추가
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
|
||||
if (diagnosis.missingFields != null && diagnosis.missingFields!.items.isNotEmpty) {
|
||||
fixes.add(FixSuggestion(
|
||||
fixId: 'validation_add_fields',
|
||||
type: FixType.addMissingField,
|
||||
description: '누락된 필수 필드를 추가합니다.',
|
||||
actions: diagnosis.missingFields!.map((field) => FixAction(
|
||||
actions: diagnosis.missingFields!.items.map((field) => FixAction(
|
||||
type: FixActionType.updateField,
|
||||
actionType: 'add_field',
|
||||
target: 'request_body',
|
||||
@@ -338,12 +338,12 @@ class ApiErrorDiagnostics {
|
||||
}
|
||||
|
||||
// 타입 불일치 수정
|
||||
if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
|
||||
if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.items.isNotEmpty) {
|
||||
fixes.add(FixSuggestion(
|
||||
fixId: 'validation_convert_types',
|
||||
type: FixType.convertType,
|
||||
description: '잘못된 데이터 타입을 변환합니다.',
|
||||
actions: diagnosis.typeMismatches!.values.map((mismatch) => FixAction(
|
||||
actions: diagnosis.typeMismatches!.values.items.map((mismatch) => FixAction(
|
||||
type: FixActionType.convertDataType,
|
||||
actionType: 'convert_type',
|
||||
target: 'request_body',
|
||||
@@ -604,7 +604,7 @@ class ApiErrorDiagnostics {
|
||||
/// 패턴 업데이트
|
||||
void _updatePattern(ErrorPattern pattern, FixResult fixResult) {
|
||||
// 성공한 수정 전략 추가 (중복 제거)
|
||||
final fixIds = pattern.successfulFixes.map((f) => f.fixId).toSet();
|
||||
final fixIds = pattern.successfulFixes.items.map((f) => f.fixId).toSet();
|
||||
for (final action in fixResult.executedActions) {
|
||||
if (!fixIds.contains(action.actionType)) {
|
||||
// 새로운 수정 전략 추가는 실제 FixSuggestion 객체가 필요하므로 생략
|
||||
@@ -782,14 +782,14 @@ class ValidationDiagnosticRule implements DiagnosticRule {
|
||||
// "필수 필드가 누락되었습니다: field1, field2" 형식 파싱
|
||||
if (message.contains('필수 필드가 누락되었습니다:')) {
|
||||
final fieldsStr = message.split(':').last.trim();
|
||||
return fieldsStr.split(',').map((f) => f.trim()).toList();
|
||||
return fieldsStr.split(',').items.map((f) => f.trim()).toList();
|
||||
}
|
||||
}
|
||||
|
||||
// validation_errors 필드 확인
|
||||
if (responseBody['validation_errors'] is Map) {
|
||||
final errors = responseBody['validation_errors'] as Map;
|
||||
return errors.keys.map((k) => k.toString()).toList();
|
||||
return errors.keys.items.map((k) => k.toString()).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -939,7 +939,7 @@ class NotFoundDiagnosticRule implements DiagnosticRule {
|
||||
final segments = uri.pathSegments;
|
||||
|
||||
// URL의 마지막 세그먼트가 숫자인 경우 ID로 간주
|
||||
if (segments.isNotEmpty) {
|
||||
if (segments.items.isNotEmpty) {
|
||||
final lastSegment = segments.last;
|
||||
if (int.tryParse(lastSegment) != null) {
|
||||
return lastSegment;
|
||||
|
||||
@@ -23,11 +23,11 @@ class ApiAutoFixer {
|
||||
|
||||
// 자동 수정 가능한 제안 필터링
|
||||
final autoFixableSuggestions = suggestions
|
||||
.where((s) => s.isAutoFixable)
|
||||
.items.where((s) => s.isAutoFixable)
|
||||
.toList()
|
||||
..sort((a, b) => b.successProbability.compareTo(a.successProbability));
|
||||
|
||||
if (autoFixableSuggestions.isEmpty) {
|
||||
if (autoFixableSuggestions.items.isEmpty) {
|
||||
return AutoFixResult(
|
||||
success: false,
|
||||
fixId: fixId,
|
||||
@@ -37,7 +37,7 @@ class ApiAutoFixer {
|
||||
}
|
||||
|
||||
// 가장 높은 성공 확률을 가진 수정 방법 선택
|
||||
final selectedFix = autoFixableSuggestions.first;
|
||||
final selectedFix = autoFixableSuggestions.items.first;
|
||||
|
||||
// 수정 시도 카운트 증가
|
||||
_fixAttempts[selectedFix.type.toString()] =
|
||||
@@ -61,7 +61,7 @@ class ApiAutoFixer {
|
||||
executedActions: executedActions,
|
||||
duration: stopwatch.elapsed.inMilliseconds,
|
||||
error: actionResult['error']?.toString() ?? '액션 실행 실패',
|
||||
fixedData: fixedData.isEmpty ? null : fixedData,
|
||||
fixedData: fixedData.items.isEmpty ? null : fixedData,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class ApiAutoFixer {
|
||||
fixId: fixId,
|
||||
executedActions: executedActions,
|
||||
duration: stopwatch.elapsed.inMilliseconds,
|
||||
fixedData: fixedData.isEmpty ? null : fixedData,
|
||||
fixedData: fixedData.items.isEmpty ? null : fixedData,
|
||||
);
|
||||
|
||||
// 이력에 추가
|
||||
@@ -249,18 +249,18 @@ class ApiAutoFixer {
|
||||
/// 학습된 패턴 수 가져오기
|
||||
int _getLearnedPatternsCount() {
|
||||
// 실제 구현에서는 diagnostics에서 학습된 패턴 수를 가져옵니다
|
||||
return _fixHistory.length;
|
||||
return _fixHistory.items.length;
|
||||
}
|
||||
|
||||
/// 평균 수정 시간 가져오기
|
||||
String _getAverageFixDuration() {
|
||||
if (_fixHistory.isEmpty) return '0ms';
|
||||
if (_fixHistory.items.isEmpty) return '0ms';
|
||||
|
||||
final totalDuration = _fixHistory
|
||||
.map((h) => h.fixResult.duration)
|
||||
.items.map((h) => h.fixResult.duration)
|
||||
.fold(0, (a, b) => a + b);
|
||||
|
||||
final average = totalDuration ~/ _fixHistory.length;
|
||||
final average = totalDuration ~/ _fixHistory.items.length;
|
||||
return '${average}ms';
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ class ApiAutoFixer {
|
||||
/// 수정 이력 가져오기
|
||||
List<FixHistoryEntry> getFixHistory({int? limit}) {
|
||||
if (limit != null) {
|
||||
return _fixHistory.reversed.take(limit).toList();
|
||||
return _fixHistory.reversed.items.take(limit).toList();
|
||||
}
|
||||
return _fixHistory.reversed.toList();
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ class AutoTestSystem {
|
||||
// 검증 에러 - 데이터 수정
|
||||
// debugPrint('[AutoTestSystem] 검증 에러 감지 - 데이터 수정 시도');
|
||||
final validationErrors = _extractValidationErrors(error);
|
||||
if (validationErrors.isNotEmpty) {
|
||||
if (validationErrors.items.isNotEmpty) {
|
||||
// debugPrint('[AutoTestSystem] 검증 에러 필드: ${validationErrors.keys.join(', ')}');
|
||||
// 여기서 데이터 수정 로직 구현
|
||||
return true;
|
||||
@@ -213,9 +213,9 @@ class AutoTestSystem {
|
||||
final responseData = error.response?.data;
|
||||
if (responseData is Map && responseData['errors'] is Map) {
|
||||
return Map<String, List<String>>.from(
|
||||
responseData['errors'].map((key, value) => MapEntry(
|
||||
responseData['errors'].items.map((key, value) => MapEntry(
|
||||
key.toString(),
|
||||
value is List ? value.map((e) => e.toString()).toList() : [value.toString()],
|
||||
value is List ? value.items.map((e) => e.toString()).toList() : [value.toString()],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ abstract class ScreenTestFramework {
|
||||
diagnosis,
|
||||
);
|
||||
|
||||
if (suggestions.isNotEmpty) {
|
||||
if (suggestions.items.isNotEmpty) {
|
||||
final fixResult = await autoFixer.attemptAutoFix(ErrorDiagnosis(
|
||||
type: ApiErrorType.unknown,
|
||||
errorType: ErrorType.unknown,
|
||||
@@ -173,7 +173,7 @@ abstract class ScreenTestFramework {
|
||||
screenReports: [],
|
||||
summary: report_models.TestSummary(
|
||||
totalScreens: 1,
|
||||
totalFeatures: basicReport.features.length,
|
||||
totalFeatures: basicReport.features.items.length,
|
||||
totalTestCases: basicReport.testResult.totalTests,
|
||||
passedTestCases: basicReport.testResult.passedTests,
|
||||
failedTestCases: basicReport.testResult.failedTests,
|
||||
@@ -204,7 +204,7 @@ abstract class ScreenTestFramework {
|
||||
fields: [],
|
||||
relationships: [],
|
||||
constraints: feature.dataConstraints ?? {},
|
||||
quantity: feature.testCases.length,
|
||||
quantity: feature.testCases.items.length,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class TestDataGenerator {
|
||||
}
|
||||
|
||||
static T getRandomElement<T>(List<T> list) {
|
||||
return list[_random.nextInt(list.length)];
|
||||
return list[_random.nextInt(list.items.length)];
|
||||
}
|
||||
|
||||
// 추가 메서드들 (인스턴스 메서드로 변경)
|
||||
@@ -276,7 +276,7 @@ class TestDataGenerator {
|
||||
final model = getRandomElement(models);
|
||||
final String actualCategory = category ?? getRandomElement(_categories);
|
||||
|
||||
final serialNumber = '${actualManufacturer.length >= 2 ? actualManufacturer.substring(0, 2).toUpperCase() : actualManufacturer.toUpperCase()}'
|
||||
final serialNumber = '${actualManufacturer.items.length >= 2 ? actualManufacturer.substring(0, 2).toUpperCase() : actualManufacturer.toUpperCase()}'
|
||||
'${DateTime.now().year}'
|
||||
'${_random.nextInt(1000000).toString().padLeft(6, '0')}';
|
||||
|
||||
@@ -428,7 +428,7 @@ class TestDataGenerator {
|
||||
final departments = ['개발팀', '디자인팀', '영업팀', '운영팀'];
|
||||
|
||||
for (final dept in departments) {
|
||||
final deptUserCount = userCount! ~/ departments.length;
|
||||
final deptUserCount = userCount! ~/ departments.items.length;
|
||||
for (int i = 0; i < deptUserCount; i++) {
|
||||
final userData = createSmartUserData(
|
||||
companyId: company.id!,
|
||||
@@ -732,8 +732,8 @@ class TestDataGenerator {
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
return '${field.prefix ?? ''}$timestamp';
|
||||
case 'realistic':
|
||||
if (field.pool != null && field.pool!.isNotEmpty) {
|
||||
return field.pool![_random.nextInt(field.pool!.length)];
|
||||
if (field.pool != null && field.pool!.items.isNotEmpty) {
|
||||
return field.pool![_random.nextInt(field.pool!.items.length)];
|
||||
}
|
||||
if (field.relatedTo == 'manufacturer') {
|
||||
// manufacturer에 따른 모델명 생성
|
||||
@@ -741,8 +741,8 @@ class TestDataGenerator {
|
||||
}
|
||||
break;
|
||||
case 'enum':
|
||||
if (field.values != null && field.values!.isNotEmpty) {
|
||||
return field.values![_random.nextInt(field.values!.length)];
|
||||
if (field.values != null && field.values!.items.isNotEmpty) {
|
||||
return field.values![_random.nextInt(field.values!.items.length)];
|
||||
}
|
||||
break;
|
||||
case 'fixed':
|
||||
@@ -754,8 +754,8 @@ class TestDataGenerator {
|
||||
static String _generateRealisticModel(String manufacturer) {
|
||||
// 간단한 모델명 생성 로직
|
||||
final models = _realProductModels[manufacturer];
|
||||
if (models != null && models.isNotEmpty) {
|
||||
return models[_random.nextInt(models.length)];
|
||||
if (models != null && models.items.isNotEmpty) {
|
||||
return models[_random.nextInt(models.items.length)];
|
||||
}
|
||||
return 'Model-${_random.nextInt(1000)}';
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ void main() {
|
||||
|
||||
expect(scenario.company.name, equals('테크장비관리 주식회사'));
|
||||
expect(scenario.warehouse.name, equals('중앙 물류센터'));
|
||||
expect(scenario.equipments.length, equals(3));
|
||||
expect(scenario.equipments.items.length, equals(3));
|
||||
|
||||
// Equipment 모델에 currentCompanyId와 warehouseLocationId 필드가 없음
|
||||
// 대신 장비 수만 확인
|
||||
@@ -139,7 +139,7 @@ void main() {
|
||||
);
|
||||
|
||||
expect(scenario.company.name, equals('스마트HR 솔루션'));
|
||||
expect(scenario.users.length, equals(8));
|
||||
expect(scenario.users.items.length, equals(8));
|
||||
|
||||
// 모든 사용자가 같은 회사에 속하는지 확인
|
||||
for (final user in scenario.users) {
|
||||
@@ -147,8 +147,8 @@ void main() {
|
||||
}
|
||||
|
||||
// 매니저가 있는지 확인
|
||||
final managers = scenario.users.where((u) => u.role == 'manager');
|
||||
expect(managers.isNotEmpty, isTrue);
|
||||
final managers = scenario.users.items.where((u) => u.role == 'manager');
|
||||
expect(managers.items.isNotEmpty, isTrue);
|
||||
});
|
||||
|
||||
test('라이선스 관리 시나리오 테스트', () async {
|
||||
@@ -157,15 +157,15 @@ void main() {
|
||||
);
|
||||
|
||||
expect(scenario.company.name, equals('소프트웨어 라이선스 매니지먼트'));
|
||||
expect(scenario.users.length, equals(5));
|
||||
expect(scenario.licenses.length, equals(6));
|
||||
expect(scenario.users.items.length, equals(5));
|
||||
expect(scenario.licenses.items.length, equals(6));
|
||||
|
||||
// 할당된 라이선스와 미할당 라이선스 확인
|
||||
expect(scenario.assignedLicenses.length, greaterThan(0));
|
||||
expect(scenario.unassignedLicenses.length, greaterThan(0));
|
||||
expect(scenario.assignedLicenses.items.length, greaterThan(0));
|
||||
expect(scenario.unassignedLicenses.items.length, greaterThan(0));
|
||||
expect(
|
||||
scenario.assignedLicenses.length + scenario.unassignedLicenses.length,
|
||||
equals(scenario.licenses.length),
|
||||
scenario.assignedLicenses.items.length + scenario.unassignedLicenses.items.length,
|
||||
equals(scenario.licenses.items.length),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -128,9 +128,9 @@ class ReportCollector {
|
||||
}
|
||||
|
||||
return TestResult(
|
||||
totalTests: totalTests == 0 ? _steps.length : totalTests,
|
||||
passedTests: passedTests == 0 ? _steps.where((s) => s.success).length : passedTests,
|
||||
failedTests: failedTests == 0 ? _steps.where((s) => !s.success).length : failedTests,
|
||||
totalTests: totalTests == 0 ? _steps.items.length : totalTests,
|
||||
passedTests: passedTests == 0 ? _steps.items.where((s) => s.success).items.length : passedTests,
|
||||
failedTests: failedTests == 0 ? _steps.items.where((s) => !s.success).items.length : failedTests,
|
||||
skippedTests: skippedTests,
|
||||
failures: failures,
|
||||
);
|
||||
@@ -187,22 +187,22 @@ class ReportCollector {
|
||||
buffer.writeln('- 성공: ${testResult.passedTests}개');
|
||||
buffer.writeln('- 실패: ${testResult.failedTests}개');
|
||||
|
||||
if (_autoFixes.isNotEmpty) {
|
||||
if (_autoFixes.items.isNotEmpty) {
|
||||
buffer.writeln('\n자동 수정 요약:');
|
||||
buffer.writeln('- 총 ${_autoFixes.length}개 항목 자동 수정됨');
|
||||
final fixTypes = _autoFixes.map((f) => f.errorType).toSet();
|
||||
buffer.writeln('- 총 ${_autoFixes.items.length}개 항목 자동 수정됨');
|
||||
final fixTypes = _autoFixes.items.map((f) => f.errorType).toSet();
|
||||
for (final type in fixTypes) {
|
||||
final count = _autoFixes.where((f) => f.errorType == type).length;
|
||||
final count = _autoFixes.items.where((f) => f.errorType == type).items.length;
|
||||
buffer.writeln(' - $type: $count개');
|
||||
}
|
||||
}
|
||||
|
||||
if (_errors.isNotEmpty) {
|
||||
if (_errors.items.isNotEmpty) {
|
||||
buffer.writeln('\n에러 요약:');
|
||||
buffer.writeln('- 총 ${_errors.length}개 에러 발생');
|
||||
final errorTypes = _errors.map((e) => e.errorType).toSet();
|
||||
buffer.writeln('- 총 ${_errors.items.length}개 에러 발생');
|
||||
final errorTypes = _errors.items.map((e) => e.errorType).toSet();
|
||||
for (final type in errorTypes) {
|
||||
final count = _errors.where((e) => e.errorType == type).length;
|
||||
final count = _errors.items.where((e) => e.errorType == type).items.length;
|
||||
buffer.writeln(' - $type: $count개');
|
||||
}
|
||||
}
|
||||
@@ -222,13 +222,13 @@ class ReportCollector {
|
||||
/// 통계 정보 조회
|
||||
Map<String, dynamic> getStatistics() {
|
||||
return {
|
||||
'totalSteps': _steps.length,
|
||||
'successfulSteps': _steps.where((s) => s.success).length,
|
||||
'failedSteps': _steps.where((s) => !s.success).length,
|
||||
'totalErrors': _errors.length,
|
||||
'totalAutoFixes': _autoFixes.length,
|
||||
'totalFeatures': _features.length,
|
||||
'totalApiCalls': _apiCalls.values.expand((calls) => calls).length,
|
||||
'totalSteps': _steps.items.length,
|
||||
'successfulSteps': _steps.items.where((s) => s.success).items.length,
|
||||
'failedSteps': _steps.items.where((s) => !s.success).items.length,
|
||||
'totalErrors': _errors.items.length,
|
||||
'totalAutoFixes': _autoFixes.items.length,
|
||||
'totalFeatures': _features.items.length,
|
||||
'totalApiCalls': _apiCalls.values.expand((calls) => calls).items.length,
|
||||
'duration': DateTime.now().difference(_startTime).inSeconds,
|
||||
};
|
||||
}
|
||||
@@ -272,7 +272,7 @@ class ReportCollector {
|
||||
buffer.writeln();
|
||||
|
||||
// 기능별 결과
|
||||
if (report.features.isNotEmpty) {
|
||||
if (report.features.items.isNotEmpty) {
|
||||
buffer.writeln('## 🎯 기능별 테스트 결과');
|
||||
buffer.writeln();
|
||||
buffer.writeln('| 기능 | 전체 | 성공 | 실패 | 성공률 |');
|
||||
@@ -288,7 +288,7 @@ class ReportCollector {
|
||||
}
|
||||
|
||||
// 실패 상세
|
||||
if (report.testResult.failures.isNotEmpty) {
|
||||
if (report.testResult.failures.items.isNotEmpty) {
|
||||
buffer.writeln('## ❌ 실패한 테스트');
|
||||
buffer.writeln();
|
||||
|
||||
@@ -303,7 +303,7 @@ class ReportCollector {
|
||||
}
|
||||
|
||||
// 자동 수정
|
||||
if (report.autoFixes.isNotEmpty) {
|
||||
if (report.autoFixes.items.isNotEmpty) {
|
||||
buffer.writeln('## 🔧 자동 수정 내역');
|
||||
buffer.writeln();
|
||||
|
||||
@@ -341,17 +341,17 @@ class ReportCollector {
|
||||
: '0.0',
|
||||
},
|
||||
'statistics': stats,
|
||||
'features': report.features.map((key, value) => MapEntry(key, {
|
||||
'features': report.features.items.map((key, value) => MapEntry(key, {
|
||||
'totalTests': value.totalTests,
|
||||
'passedTests': value.passedTests,
|
||||
'failedTests': value.failedTests,
|
||||
})),
|
||||
'failures': report.testResult.failures.map((f) => {
|
||||
'failures': report.testResult.failures.items.map((f) => {
|
||||
'feature': f.feature,
|
||||
'message': f.message,
|
||||
'stackTrace': f.stackTrace,
|
||||
}).toList(),
|
||||
'autoFixes': report.autoFixes.map((f) => {
|
||||
'autoFixes': report.autoFixes.items.map((f) => {
|
||||
'errorType': f.errorType,
|
||||
'cause': f.cause,
|
||||
'solution': f.solution,
|
||||
|
||||
@@ -117,7 +117,7 @@ class ErrorDiagnosis {
|
||||
'affectedEndpoints': affectedEndpoints,
|
||||
'serverErrorCode': serverErrorCode,
|
||||
'missingFields': missingFields,
|
||||
'typeMismatches': typeMismatches?.map(
|
||||
'typeMismatches': typeMismatches?.items.map(
|
||||
(key, value) => MapEntry(key, value.toJson()),
|
||||
),
|
||||
'originalMessage': originalMessage,
|
||||
@@ -225,7 +225,7 @@ class FixSuggestion {
|
||||
'fixId': fixId,
|
||||
'type': type.toString(),
|
||||
'description': description,
|
||||
'actions': actions.map((a) => a.toJson()).toList(),
|
||||
'actions': actions.items.map((a) => a.toJson()).toList(),
|
||||
'successProbability': successProbability,
|
||||
'isAutoFixable': isAutoFixable,
|
||||
'estimatedDuration': estimatedDuration,
|
||||
@@ -306,7 +306,7 @@ class FixResult {
|
||||
return {
|
||||
'fixId': fixId,
|
||||
'success': success,
|
||||
'executedActions': executedActions.map((a) => a.toJson()).toList(),
|
||||
'executedActions': executedActions.items.map((a) => a.toJson()).toList(),
|
||||
'executedAt': executedAt.toIso8601String(),
|
||||
'duration': duration,
|
||||
'error': error,
|
||||
@@ -405,7 +405,7 @@ class ErrorPattern {
|
||||
'patternId': patternId,
|
||||
'errorType': errorType.toString(),
|
||||
'matchingRules': matchingRules,
|
||||
'successfulFixes': successfulFixes.map((f) => f.toJson()).toList(),
|
||||
'successfulFixes': successfulFixes.items.map((f) => f.toJson()).toList(),
|
||||
'occurrenceCount': occurrenceCount,
|
||||
'lastOccurred': lastOccurred.toIso8601String(),
|
||||
'confidence': confidence,
|
||||
@@ -550,7 +550,7 @@ class RootCause {
|
||||
'description': description,
|
||||
'evidence': evidence,
|
||||
'diagnosis': diagnosis.toJson(),
|
||||
'recommendedFixes': recommendedFixes.map((f) => f.toJson()).toList(),
|
||||
'recommendedFixes': recommendedFixes.items.map((f) => f.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ class TestReport {
|
||||
'reportId': reportId,
|
||||
'generatedAt': generatedAt.toIso8601String(),
|
||||
'type': type.toString(),
|
||||
'screenReports': screenReports.map((r) => r.toJson()).toList(),
|
||||
'screenReports': screenReports.items.map((r) => r.toJson()).toList(),
|
||||
'summary': summary.toJson(),
|
||||
'errorAnalyses': errorAnalyses.map((e) => e.toJson()).toList(),
|
||||
'performanceMetrics': performanceMetrics.map((m) => m.toJson()).toList(),
|
||||
'errorAnalyses': errorAnalyses.items.map((e) => e.toJson()).toList(),
|
||||
'performanceMetrics': performanceMetrics.items.map((m) => m.toJson()).toList(),
|
||||
'metadata': metadata,
|
||||
};
|
||||
}
|
||||
@@ -132,7 +132,7 @@ class ScreenTestReport {
|
||||
Map<String, dynamic> toJson() => {
|
||||
'screenName': screenName,
|
||||
'testResult': testResult.toJson(),
|
||||
'featureReports': featureReports.map((r) => r.toJson()).toList(),
|
||||
'featureReports': featureReports.items.map((r) => r.toJson()).toList(),
|
||||
'coverage': coverage,
|
||||
'recommendations': recommendations,
|
||||
};
|
||||
@@ -171,7 +171,7 @@ class FeatureReport {
|
||||
'failedTests': failedTests,
|
||||
'successRate': successRate,
|
||||
'totalDuration': totalDuration.inMilliseconds,
|
||||
'testCaseReports': testCaseReports.map((r) => r.toJson()).toList(),
|
||||
'testCaseReports': testCaseReports.items.map((r) => r.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ class TestCaseReport {
|
||||
'duration': duration.inMilliseconds,
|
||||
'errorMessage': errorMessage,
|
||||
'stackTrace': stackTrace,
|
||||
'steps': steps.map((s) => s.toJson()).toList(),
|
||||
'steps': steps.items.map((s) => s.toJson()).toList(),
|
||||
'additionalInfo': additionalInfo,
|
||||
};
|
||||
}
|
||||
@@ -316,7 +316,7 @@ class ErrorAnalysis {
|
||||
'affectedScreens': affectedScreens,
|
||||
'affectedFeatures': affectedFeatures,
|
||||
'rootCause': rootCause?.toJson(),
|
||||
'suggestedFixes': suggestedFixes.map((f) => f.toJson()).toList(),
|
||||
'suggestedFixes': suggestedFixes.items.map((f) => f.toJson()).toList(),
|
||||
'wasAutoFixed': wasAutoFixed,
|
||||
'context': context,
|
||||
};
|
||||
@@ -424,7 +424,7 @@ class TestResult {
|
||||
'passedTests': passedTests,
|
||||
'failedTests': failedTests,
|
||||
'skippedTests': skippedTests,
|
||||
'failures': failures.map((f) => f.toJson()).toList(),
|
||||
'failures': failures.items.map((f) => f.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -596,11 +596,11 @@ class BasicTestReport {
|
||||
'duration': duration.inMilliseconds,
|
||||
'environment': environment,
|
||||
'testResult': testResult.toJson(),
|
||||
'steps': steps.map((s) => s.toJson()).toList(),
|
||||
'errors': errors.map((e) => e.toJson()).toList(),
|
||||
'autoFixes': autoFixes.map((f) => f.toJson()).toList(),
|
||||
'features': features.map((k, v) => MapEntry(k, v.toJson())),
|
||||
'apiCalls': apiCalls.map((k, v) => MapEntry(k, v.map((c) => c.toJson()).toList())),
|
||||
'steps': steps.items.map((s) => s.toJson()).toList(),
|
||||
'errors': errors.items.map((e) => e.toJson()).toList(),
|
||||
'autoFixes': autoFixes.items.map((f) => f.toJson()).toList(),
|
||||
'features': features.items.map((k, v) => MapEntry(k, v.toJson())),
|
||||
'apiCalls': apiCalls.items.map((k, v) => MapEntry(k, v.items.map((c) => c.toJson()).toList())),
|
||||
'summary': summary,
|
||||
};
|
||||
}
|
||||
@@ -15,7 +15,7 @@ class ScreenMetadata {
|
||||
Map<String, dynamic> toJson() => {
|
||||
'screenName': screenName,
|
||||
'controllerType': controllerType.toString(),
|
||||
'relatedEndpoints': relatedEndpoints.map((e) => e.toJson()).toList(),
|
||||
'relatedEndpoints': relatedEndpoints.items.map((e) => e.toJson()).toList(),
|
||||
'screenCapabilities': screenCapabilities,
|
||||
};
|
||||
}
|
||||
@@ -267,7 +267,7 @@ class TestResult {
|
||||
this.endTime,
|
||||
});
|
||||
|
||||
bool get success => errors.isEmpty && featureResults.every((r) => r.success);
|
||||
bool get success => errors.items.isEmpty && featureResults.items.every((r) => r.success);
|
||||
bool get passed => success; // 호환성을 위한 별칭
|
||||
|
||||
Duration get duration => endTime != null
|
||||
@@ -277,37 +277,37 @@ class TestResult {
|
||||
// 테스트 카운트 관련 getter들
|
||||
int get totalTests => featureResults
|
||||
.expand((r) => r.testCaseResults)
|
||||
.length;
|
||||
.items.length;
|
||||
|
||||
int get passedTests => featureResults
|
||||
.expand((r) => r.testCaseResults)
|
||||
.where((r) => r.success)
|
||||
.length;
|
||||
.items.where((r) => r.success)
|
||||
.items.length;
|
||||
|
||||
int get failedTests => totalTests - passedTests;
|
||||
|
||||
void calculateMetrics() {
|
||||
metrics['totalFeatures'] = featureResults.length;
|
||||
metrics['successfulFeatures'] = featureResults.where((r) => r.success).length;
|
||||
metrics['failedFeatures'] = featureResults.where((r) => !r.success).length;
|
||||
metrics['totalFeatures'] = featureResults.items.length;
|
||||
metrics['successfulFeatures'] = featureResults.items.where((r) => r.success).items.length;
|
||||
metrics['failedFeatures'] = featureResults.items.where((r) => !r.success).items.length;
|
||||
metrics['totalTestCases'] = featureResults
|
||||
.expand((r) => r.testCaseResults)
|
||||
.length;
|
||||
.items.length;
|
||||
metrics['successfulTestCases'] = featureResults
|
||||
.expand((r) => r.testCaseResults)
|
||||
.where((r) => r.success)
|
||||
.length;
|
||||
.items.where((r) => r.success)
|
||||
.items.length;
|
||||
metrics['averageDuration'] = _calculateAverageDuration();
|
||||
}
|
||||
|
||||
double _calculateAverageDuration() {
|
||||
final allDurations = featureResults
|
||||
.expand((r) => r.testCaseResults)
|
||||
.map((r) => r.duration.inMilliseconds);
|
||||
.items.map((r) => r.duration.inMilliseconds);
|
||||
|
||||
if (allDurations.isEmpty) return 0;
|
||||
if (allDurations.items.isEmpty) return 0;
|
||||
|
||||
return allDurations.reduce((a, b) => a + b) / allDurations.length;
|
||||
return allDurations.reduce((a, b) => a + b) / allDurations.items.length;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
@@ -316,8 +316,8 @@ class TestResult {
|
||||
'startTime': startTime.toIso8601String(),
|
||||
'endTime': endTime?.toIso8601String(),
|
||||
'duration': duration.inMilliseconds,
|
||||
'featureResults': featureResults.map((r) => r.toJson()).toList(),
|
||||
'errors': errors.map((e) => e.toJson()).toList(),
|
||||
'featureResults': featureResults.items.map((r) => r.toJson()).toList(),
|
||||
'errors': errors.items.map((e) => e.toJson()).toList(),
|
||||
'metrics': metrics,
|
||||
};
|
||||
}
|
||||
@@ -336,27 +336,27 @@ class FeatureTestResult {
|
||||
this.endTime,
|
||||
});
|
||||
|
||||
bool get success => testCaseResults.every((r) => r.success);
|
||||
bool get success => testCaseResults.items.every((r) => r.success);
|
||||
|
||||
Duration get duration => endTime != null
|
||||
? endTime!.difference(startTime)
|
||||
: Duration.zero;
|
||||
|
||||
void calculateMetrics() {
|
||||
metrics['totalTestCases'] = testCaseResults.length;
|
||||
metrics['successfulTestCases'] = testCaseResults.where((r) => r.success).length;
|
||||
metrics['failedTestCases'] = testCaseResults.where((r) => !r.success).length;
|
||||
metrics['totalTestCases'] = testCaseResults.items.length;
|
||||
metrics['successfulTestCases'] = testCaseResults.items.where((r) => r.success).items.length;
|
||||
metrics['failedTestCases'] = testCaseResults.items.where((r) => !r.success).items.length;
|
||||
metrics['averageDuration'] = _calculateAverageDuration();
|
||||
}
|
||||
|
||||
double _calculateAverageDuration() {
|
||||
if (testCaseResults.isEmpty) return 0;
|
||||
if (testCaseResults.items.isEmpty) return 0;
|
||||
|
||||
final totalMs = testCaseResults
|
||||
.map((r) => r.duration.inMilliseconds)
|
||||
.items.map((r) => r.duration.inMilliseconds)
|
||||
.reduce((a, b) => a + b);
|
||||
|
||||
return totalMs / testCaseResults.length;
|
||||
return totalMs / testCaseResults.items.length;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
@@ -365,7 +365,7 @@ class FeatureTestResult {
|
||||
'startTime': startTime.toIso8601String(),
|
||||
'endTime': endTime?.toIso8601String(),
|
||||
'duration': duration.inMilliseconds,
|
||||
'testCaseResults': testCaseResults.map((r) => r.toJson()).toList(),
|
||||
'testCaseResults': testCaseResults.items.map((r) => r.toJson()).toList(),
|
||||
'metrics': metrics,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class TapAction extends BaseTestableAction {
|
||||
|
||||
@override
|
||||
Future<bool> canExecute(WidgetTester tester) async {
|
||||
return finder.evaluate().isNotEmpty;
|
||||
return finder.evaluate().items.isNotEmpty;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -157,7 +157,7 @@ class EnterTextAction extends BaseTestableAction {
|
||||
|
||||
@override
|
||||
Future<bool> canExecute(WidgetTester tester) async {
|
||||
return finder.evaluate().isNotEmpty;
|
||||
return finder.evaluate().items.isNotEmpty;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -251,7 +251,7 @@ class ScrollAction extends BaseTestableAction {
|
||||
if (target != null) {
|
||||
// 타겟을 찾을 때까지 스크롤
|
||||
for (int i = 0; i < maxAttempts; i++) {
|
||||
if (target!.evaluate().isNotEmpty) {
|
||||
if (target!.evaluate().items.isNotEmpty) {
|
||||
return ActionResult.success(
|
||||
message: 'Found target after $i scrolls',
|
||||
executionTime: stopwatch.elapsed,
|
||||
@@ -348,7 +348,7 @@ class CompositeAction extends BaseTestableAction {
|
||||
String get name => compositeName;
|
||||
|
||||
@override
|
||||
String get description => 'Execute ${actions.length} actions for $compositeName';
|
||||
String get description => 'Execute ${actions.items.length} actions for $compositeName';
|
||||
|
||||
@override
|
||||
Future<ActionResult> execute(WidgetTester tester) async {
|
||||
@@ -386,8 +386,8 @@ class CompositeAction extends BaseTestableAction {
|
||||
}
|
||||
}
|
||||
|
||||
final successCount = results.where((r) => r.success).length;
|
||||
final totalCount = results.length;
|
||||
final successCount = results.items.where((r) => r.success).items.length;
|
||||
final totalCount = results.items.length;
|
||||
|
||||
return ActionResult.success(
|
||||
message: 'Completed $successCount/$totalCount actions successfully',
|
||||
|
||||
@@ -64,7 +64,7 @@ class HtmlReportGenerator {
|
||||
buffer.writeln(' </section>');
|
||||
|
||||
// 실패 상세
|
||||
if (report.testResult.failures.isNotEmpty) {
|
||||
if (report.testResult.failures.items.isNotEmpty) {
|
||||
buffer.writeln(' <section class="failures">');
|
||||
buffer.writeln(' <h2>❌ 실패한 테스트</h2>');
|
||||
buffer.writeln(' <div class="failure-list">');
|
||||
@@ -85,7 +85,7 @@ class HtmlReportGenerator {
|
||||
}
|
||||
|
||||
// 기능별 리포트
|
||||
if (report.features.isNotEmpty) {
|
||||
if (report.features.items.isNotEmpty) {
|
||||
buffer.writeln(' <section class="features">');
|
||||
buffer.writeln(' <h2>🎯 기능별 테스트 결과</h2>');
|
||||
buffer.writeln(' <table class="feature-table">');
|
||||
@@ -119,7 +119,7 @@ class HtmlReportGenerator {
|
||||
}
|
||||
|
||||
// 자동 수정 섹션
|
||||
if (report.autoFixes.isNotEmpty) {
|
||||
if (report.autoFixes.items.isNotEmpty) {
|
||||
buffer.writeln(' <section class="auto-fixes">');
|
||||
buffer.writeln(' <h2>🔧 자동 수정 내역</h2>');
|
||||
buffer.writeln(' <div class="fix-list">');
|
||||
|
||||
@@ -121,14 +121,14 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '빈 검색어 조회',
|
||||
'status': companies != null ? 'PASS' : 'FAIL',
|
||||
'count': companies?.length ?? 0,
|
||||
'count': companies?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${companies?.length ?? 0}개 회사 조회됨');
|
||||
print(' 결과: ${companies?.items.length ?? 0}개 회사 조회됨');
|
||||
|
||||
// 2. 특정 검색어 테스트
|
||||
if (companies != null && companies.isNotEmpty) {
|
||||
final testCompany = companies.first;
|
||||
final searchKeyword = testCompany.name.substring(0, testCompany.name.length > 3 ? 3 : testCompany.name.length);
|
||||
final searchKeyword = testCompany.name.substring(0, testCompany.name.items.length > 3 ? 3 : testCompany.name.items.length);
|
||||
|
||||
print('테스트 2: "$searchKeyword" 검색어로 조회');
|
||||
companies = await companyService.getCompanies(
|
||||
@@ -137,7 +137,7 @@ class InteractiveSearchTest {
|
||||
search: searchKeyword,
|
||||
);
|
||||
|
||||
final hasMatch = companies?.any((c) =>
|
||||
final hasMatch = companies?.items.any((c) =>
|
||||
c.name.toLowerCase().contains(searchKeyword.toLowerCase())
|
||||
) ?? false;
|
||||
|
||||
@@ -145,9 +145,9 @@ class InteractiveSearchTest {
|
||||
'name': '검색어 필터링',
|
||||
'status': hasMatch ? 'PASS' : 'FAIL',
|
||||
'keyword': searchKeyword,
|
||||
'count': companies?.length ?? 0,
|
||||
'count': companies?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${companies?.length ?? 0}개 회사 조회됨 (매칭: $hasMatch)');
|
||||
print(' 결과: ${companies?.items.length ?? 0}개 회사 조회됨 (매칭: $hasMatch)');
|
||||
}
|
||||
|
||||
// 3. 특수문자 검색 테스트
|
||||
@@ -161,7 +161,7 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '특수문자 검색',
|
||||
'status': 'PASS',
|
||||
'count': companies?.length ?? 0,
|
||||
'count': companies?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: 에러 없이 처리됨');
|
||||
} catch (e) {
|
||||
@@ -185,7 +185,7 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '긴 검색어',
|
||||
'status': 'PASS',
|
||||
'keywordLength': longKeyword.length,
|
||||
'keywordLength': longKeyword.items.length,
|
||||
});
|
||||
print(' 결과: 에러 없이 처리됨');
|
||||
} catch (e) {
|
||||
@@ -208,9 +208,9 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '한글 검색',
|
||||
'status': 'PASS',
|
||||
'count': companies?.length ?? 0,
|
||||
'count': companies?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${companies?.length ?? 0}개 회사 조회됨');
|
||||
print(' 결과: ${companies?.items.length ?? 0}개 회사 조회됨');
|
||||
} catch (e) {
|
||||
result['tests'].add({
|
||||
'name': '한글 검색',
|
||||
@@ -248,14 +248,14 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '빈 검색어 조회',
|
||||
'status': users != null ? 'PASS' : 'FAIL',
|
||||
'count': users?.length ?? 0,
|
||||
'count': users?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${users?.length ?? 0}명 사용자 조회됨');
|
||||
print(' 결과: ${users?.items.length ?? 0}명 사용자 조회됨');
|
||||
|
||||
// 2. 이름으로 검색
|
||||
if (users != null && users.isNotEmpty) {
|
||||
final testUser = users.first;
|
||||
final searchKeyword = testUser.name.substring(0, testUser.name.length > 2 ? 2 : testUser.name.length);
|
||||
if (users != null && users.items.isNotEmpty) {
|
||||
final testUser = users.items.first;
|
||||
final searchKeyword = testUser.name.substring(0, testUser.name.items.length > 2 ? 2 : testUser.name.items.length);
|
||||
|
||||
print('테스트 2: "$searchKeyword" 검색어로 조회');
|
||||
// UserService에 search 파라미터 지원 확인 필요
|
||||
@@ -295,9 +295,9 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '빈 검색어 조회',
|
||||
'status': licenses != null ? 'PASS' : 'FAIL',
|
||||
'count': licenses?.length ?? 0,
|
||||
'count': licenses?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${licenses?.length ?? 0}개 라이선스 조회됨');
|
||||
print(' 결과: ${licenses?.items.length ?? 0}개 라이선스 조회됨');
|
||||
|
||||
result['overall'] = 'PARTIAL';
|
||||
} catch (e) {
|
||||
@@ -327,9 +327,9 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '빈 검색어 조회',
|
||||
'status': warehouses != null ? 'PASS' : 'FAIL',
|
||||
'count': warehouses?.length ?? 0,
|
||||
'count': warehouses?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${warehouses?.length ?? 0}개 창고 위치 조회됨');
|
||||
print(' 결과: ${warehouses?.items.length ?? 0}개 창고 위치 조회됨');
|
||||
|
||||
result['overall'] = 'PARTIAL';
|
||||
} catch (e) {
|
||||
@@ -360,15 +360,15 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '빈 검색어 조회',
|
||||
'status': equipments != null ? 'PASS' : 'FAIL',
|
||||
'count': equipments?.length ?? 0,
|
||||
'count': equipments?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${equipments?.length ?? 0}개 장비 조회됨');
|
||||
print(' 결과: ${equipments?.items.length ?? 0}개 장비 조회됨');
|
||||
|
||||
// 2. 특정 검색어 테스트
|
||||
if (equipments != null && equipments.isNotEmpty) {
|
||||
final testEquipment = equipments.first;
|
||||
if (equipments != null && equipments.items.isNotEmpty) {
|
||||
final testEquipment = equipments.items.first;
|
||||
final searchKeyword = testEquipment.manufacturer?.substring(0,
|
||||
testEquipment.manufacturer!.length > 3 ? 3 : testEquipment.manufacturer!.length) ?? 'test';
|
||||
testEquipment.manufacturer!.items.length > 3 ? 3 : testEquipment.manufacturer!.items.length) ?? 'test';
|
||||
|
||||
print('테스트 2: "$searchKeyword" 검색어로 조회');
|
||||
equipments = await equipmentService.getEquipmentsWithStatus(
|
||||
@@ -377,7 +377,7 @@ class InteractiveSearchTest {
|
||||
search: searchKeyword,
|
||||
);
|
||||
|
||||
final hasMatch = equipments?.any((e) =>
|
||||
final hasMatch = equipments?.items.any((e) =>
|
||||
(e.manufacturer?.toLowerCase().contains(searchKeyword.toLowerCase()) ?? false) ||
|
||||
(e.modelName?.toLowerCase().contains(searchKeyword.toLowerCase()) ?? false) ||
|
||||
(e.equipmentNumber?.toLowerCase().contains(searchKeyword.toLowerCase()) ?? false)
|
||||
@@ -387,9 +387,9 @@ class InteractiveSearchTest {
|
||||
'name': '검색어 필터링',
|
||||
'status': hasMatch ? 'PASS' : 'FAIL',
|
||||
'keyword': searchKeyword,
|
||||
'count': equipments?.length ?? 0,
|
||||
'count': equipments?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${equipments?.length ?? 0}개 장비 조회됨 (매칭: $hasMatch)');
|
||||
print(' 결과: ${equipments?.items.length ?? 0}개 장비 조회됨 (매칭: $hasMatch)');
|
||||
}
|
||||
|
||||
// 3. 특수문자 검색 테스트
|
||||
@@ -403,7 +403,7 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '특수문자 검색',
|
||||
'status': 'PASS',
|
||||
'count': equipments?.length ?? 0,
|
||||
'count': equipments?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: 에러 없이 처리됨');
|
||||
} catch (e) {
|
||||
@@ -426,9 +426,9 @@ class InteractiveSearchTest {
|
||||
result['tests'].add({
|
||||
'name': '한글 검색',
|
||||
'status': 'PASS',
|
||||
'count': equipments?.length ?? 0,
|
||||
'count': equipments?.items.length ?? 0,
|
||||
});
|
||||
print(' 결과: ${equipments?.length ?? 0}개 장비 조회됨');
|
||||
print(' 결과: ${equipments?.items.length ?? 0}개 장비 조회됨');
|
||||
} catch (e) {
|
||||
result['tests'].add({
|
||||
'name': '한글 검색',
|
||||
@@ -477,7 +477,7 @@ class InteractiveSearchTest {
|
||||
|
||||
// 수정이 필요한 항목 식별
|
||||
print('수정 필요 항목:');
|
||||
if (testResults.any((r) => r['screen'] == 'Equipment' && r['overall'] == 'PASS')) {
|
||||
if (testResults.items.any((r) => r['screen'] == 'Equipment' && r['overall'] == 'PASS')) {
|
||||
print('✅ Equipment 화면: 검색 기능 구현 완료!');
|
||||
} else {
|
||||
print('❌ Equipment 화면: 검색 기능 오류');
|
||||
|
||||
@@ -157,19 +157,19 @@ void _runLicenseTestsInternal() {
|
||||
|
||||
// 전체 목록 조회
|
||||
final licenses = await licenseService.getLicenses();
|
||||
print('✅ 전체 라이센스 ${licenses.length}개 조회');
|
||||
print('✅ 전체 라이센스 ${licenses.items.length}개 조회');
|
||||
expect(licenses, isA<List<License>>());
|
||||
|
||||
// 페이지네이션 테스트
|
||||
print('📄 페이지네이션 테스트...');
|
||||
final page1 = await licenseService.getLicenses(page: 1, perPage: 5);
|
||||
print(' - 1페이지: ${page1.length}개');
|
||||
print(' - 1페이지: ${page1.items.length}개');
|
||||
|
||||
final page2 = await licenseService.getLicenses(page: 2, perPage: 5);
|
||||
print(' - 2페이지: ${page2.length}개');
|
||||
print(' - 2페이지: ${page2.items.length}개');
|
||||
|
||||
expect(page1.length, lessThanOrEqualTo(5));
|
||||
expect(page2.length, lessThanOrEqualTo(5));
|
||||
expect(page1.items.length, lessThanOrEqualTo(5));
|
||||
expect(page2.items.length, lessThanOrEqualTo(5));
|
||||
|
||||
// 전체 개수 확인
|
||||
final total = await licenseService.getTotalLicenses();
|
||||
@@ -181,9 +181,9 @@ void _runLicenseTestsInternal() {
|
||||
print('\n➕ 라이센스 생성 테스트...');
|
||||
|
||||
// 실제 비즈니스 데이터로 라이센스 생성
|
||||
final productIndex = random.nextInt(testData['products']!.length);
|
||||
final vendorIndex = random.nextInt(testData['vendors']!.length);
|
||||
final typeIndex = random.nextInt(testData['licenseTypes']!.length);
|
||||
final productIndex = random.nextInt(testData['products']!.items.length);
|
||||
final vendorIndex = random.nextInt(testData['vendors']!.items.length);
|
||||
final typeIndex = random.nextInt(testData['licenseTypes']!.items.length);
|
||||
|
||||
final newLicense = License(
|
||||
licenseKey: 'LIC-${DateTime.now().millisecondsSinceEpoch}',
|
||||
@@ -220,7 +220,7 @@ void _runLicenseTestsInternal() {
|
||||
|
||||
// 목록에서 첫 번째 라이센스 선택
|
||||
final licenses = await licenseService.getLicenses();
|
||||
if (licenses.isEmpty) {
|
||||
if (licenses.items.isEmpty) {
|
||||
print('⚠️ 조회할 라이센스가 없습니다. 새로 생성...');
|
||||
|
||||
// 라이센스 생성
|
||||
@@ -245,7 +245,7 @@ void _runLicenseTestsInternal() {
|
||||
expect(license.id, equals(created.id));
|
||||
} else {
|
||||
// 기존 라이센스 상세 조회
|
||||
final targetId = licenses.first.id!;
|
||||
final targetId = licenses.items.first.id!;
|
||||
final license = await licenseService.getLicenseById(targetId);
|
||||
|
||||
print('✅ 라이센스 상세 정보:');
|
||||
@@ -353,7 +353,7 @@ void _runLicenseTestsInternal() {
|
||||
// 활성 라이센스만 조회
|
||||
print('📌 활성 라이센스 필터링...');
|
||||
final activeLicenses = await licenseService.getLicenses(isActive: true);
|
||||
print('✅ 활성 라이센스: ${activeLicenses.length}개');
|
||||
print('✅ 활성 라이센스: ${activeLicenses.items.length}개');
|
||||
expect(activeLicenses, isA<List<License>>());
|
||||
|
||||
// 특정 회사 라이센스만 조회
|
||||
@@ -361,7 +361,7 @@ void _runLicenseTestsInternal() {
|
||||
final companyLicenses = await licenseService.getLicenses(
|
||||
companyId: testCompany.id,
|
||||
);
|
||||
print('✅ ${testCompany.name} 라이센스: ${companyLicenses.length}개');
|
||||
print('✅ ${testCompany.name} 라이센스: ${companyLicenses.items.length}개');
|
||||
expect(companyLicenses, isA<List<License>>());
|
||||
|
||||
// 라이센스 타입별 필터링
|
||||
@@ -369,7 +369,7 @@ void _runLicenseTestsInternal() {
|
||||
final subscriptionLicenses = await licenseService.getLicenses(
|
||||
licenseType: 'subscription',
|
||||
);
|
||||
print('✅ 구독형 라이센스: ${subscriptionLicenses.length}개');
|
||||
print('✅ 구독형 라이센스: ${subscriptionLicenses.items.length}개');
|
||||
});
|
||||
|
||||
test('7. ⏰ 만료 예정 라이센스 조회', () async {
|
||||
@@ -397,12 +397,12 @@ void _runLicenseTestsInternal() {
|
||||
final expiringLicenses = await licenseService.getExpiringLicenses(days: 30);
|
||||
|
||||
print('📊 만료 예정 라이센스 현황:');
|
||||
for (var license in expiringLicenses.take(5)) {
|
||||
for (var license in expiringLicenses.items.take(5)) {
|
||||
final daysLeft = license.expiryDate?.difference(DateTime.now()).inDays ?? 0;
|
||||
print(' - ${license.productName}: ${daysLeft}일 남음');
|
||||
}
|
||||
|
||||
print('✅ 만료 예정 라이센스 ${expiringLicenses.length}개 조회');
|
||||
print('✅ 만료 예정 라이센스 ${expiringLicenses.items.length}개 조회');
|
||||
expect(expiringLicenses, isA<List<License>>());
|
||||
});
|
||||
|
||||
@@ -501,11 +501,11 @@ void _runLicenseTestsInternal() {
|
||||
final createdIds = <int>[];
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
final productIndex = random.nextInt(testData['products']!.length);
|
||||
final productIndex = random.nextInt(testData['products']!.items.length);
|
||||
final bulkLicense = License(
|
||||
licenseKey: 'BULK-${DateTime.now().millisecondsSinceEpoch}-$i',
|
||||
productName: testData['products']![productIndex],
|
||||
vendor: testData['vendors']![random.nextInt(testData['vendors']!.length)],
|
||||
vendor: testData['vendors']![random.nextInt(testData['vendors']!.items.length)],
|
||||
licenseType: 'volume',
|
||||
userCount: random.nextInt(100) + 10,
|
||||
purchaseDate: DateTime.now(),
|
||||
|
||||
@@ -65,7 +65,7 @@ class ScreenTestResult {
|
||||
'failedTests': testResult?.failedTests ?? 0,
|
||||
'startTime': startTime.toIso8601String(),
|
||||
'endTime': endTime.toIso8601String(),
|
||||
'failures': testResult?.failures?.map((f) => {
|
||||
'failures': testResult?.failures?.items.map((f) => {
|
||||
'feature': f.feature ?? '',
|
||||
'message': f.message ?? '',
|
||||
})?.toList() ?? [],
|
||||
@@ -136,7 +136,7 @@ class MasterTestSuite {
|
||||
|
||||
// 2. 테스트할 화면 목록 준비
|
||||
final screenTests = await _prepareScreenTests();
|
||||
totalScreens = screenTests.length;
|
||||
totalScreens = screenTests.items.length;
|
||||
|
||||
_log('테스트할 화면: $totalScreens개');
|
||||
_log('실행 모드: ${options.parallel ? "병렬" : "순차"}');
|
||||
@@ -272,7 +272,7 @@ class MasterTestSuite {
|
||||
}
|
||||
|
||||
// 포함 목록이 비어있거나, 포함 목록에 있으면 true
|
||||
return options.includeScreens.isEmpty ||
|
||||
return options.includeScreens.items.isEmpty ||
|
||||
options.includeScreens.contains(screenName);
|
||||
}
|
||||
|
||||
@@ -446,8 +446,8 @@ class MasterTestSuite {
|
||||
}
|
||||
|
||||
// 실패 상세
|
||||
final failedResults = results.where((r) => !r.passed);
|
||||
if (failedResults.isNotEmpty) {
|
||||
final failedResults = results.items.where((r) => !r.passed);
|
||||
if (failedResults.items.isNotEmpty) {
|
||||
buffer.writeln('');
|
||||
buffer.writeln('## ❌ 실패 상세');
|
||||
buffer.writeln('');
|
||||
@@ -478,7 +478,7 @@ class MasterTestSuite {
|
||||
buffer.writeln('| 순위 | 화면 | 소요시간 |');
|
||||
buffer.writeln('|------|------|----------|');
|
||||
|
||||
for (var i = 0; i < 5 && i < sortedByDuration.length; i++) {
|
||||
for (var i = 0; i < 5 && i < sortedByDuration.items.length; i++) {
|
||||
final result = sortedByDuration[i];
|
||||
buffer.writeln('| ${i + 1} | ${result.screenName} | ${_formatDuration(result.duration)} |');
|
||||
}
|
||||
@@ -502,7 +502,7 @@ class MasterTestSuite {
|
||||
buffer.writeln('- 실패한 테스트를 우선적으로 수정하세요');
|
||||
}
|
||||
|
||||
final slowTests = sortedByDuration.where((r) => r.duration.inSeconds > 30).length;
|
||||
final slowTests = sortedByDuration.items.where((r) => r.duration.inSeconds > 30).items.length;
|
||||
if (slowTests > 0) {
|
||||
buffer.writeln('- **$slowTests개 화면**이 30초 이상 소요됩니다');
|
||||
buffer.writeln('- 성능 최적화를 고려하세요');
|
||||
@@ -573,7 +573,7 @@ class MasterTestSuite {
|
||||
'failedScreens': failedScreens,
|
||||
'successRate': _calculateSuccessRate(),
|
||||
},
|
||||
'results': results.map((r) => r.toJson()).toList(),
|
||||
'results': results.items.map((r) => r.toJson()).toList(),
|
||||
'exitCode': failedScreens > 0 ? 1 : 0,
|
||||
};
|
||||
|
||||
@@ -631,7 +631,7 @@ class MasterTestSuite {
|
||||
|
||||
if (failedScreens > 0) {
|
||||
_log('⚠️ 실패한 화면:');
|
||||
for (final result in results.where((r) => !r.passed)) {
|
||||
for (final result in results.items.where((r) => !r.passed)) {
|
||||
_log(' • ${result.screenName}: ${result.testResult.failedTests}개 테스트 실패');
|
||||
}
|
||||
_log('');
|
||||
@@ -702,7 +702,7 @@ class _Semaphore {
|
||||
|
||||
void _release() {
|
||||
_currentCount--;
|
||||
if (_waiters.isNotEmpty) {
|
||||
if (_waiters.items.isNotEmpty) {
|
||||
final waiter = _waiters.removeAt(0);
|
||||
waiter.complete();
|
||||
_currentCount++;
|
||||
|
||||
@@ -130,10 +130,10 @@ Future<TestResult> runOverviewTests({
|
||||
|
||||
final activities = response.data['data'] as List;
|
||||
|
||||
if (verbose) debugPrint('✅ 최근 활동 내역 조회 성공: ${activities.length}개');
|
||||
if (verbose) debugPrint('✅ 최근 활동 내역 조회 성공: ${activities.items.length}개');
|
||||
|
||||
// 최근 5개 활동 표시
|
||||
final displayCount = activities.length > 5 ? 5 : activities.length;
|
||||
final displayCount = activities.items.length > 5 ? 5 : activities.items.length;
|
||||
for (int i = 0; i < displayCount; i++) {
|
||||
final activity = activities[i];
|
||||
if (verbose) debugPrint(' ${i + 1}. ${activity['action']} - ${activity['timestamp']}');
|
||||
@@ -160,7 +160,7 @@ Future<TestResult> runOverviewTests({
|
||||
|
||||
final expiringLicenses = response.data['data'] as List;
|
||||
|
||||
if (verbose) debugPrint('✅ 만료 예정 라이센스 조회 성공: ${expiringLicenses.length}개');
|
||||
if (verbose) debugPrint('✅ 만료 예정 라이센스 조회 성공: ${expiringLicenses.items.length}개');
|
||||
|
||||
for (final license in expiringLicenses) {
|
||||
if (verbose) debugPrint(' - ${license['product_name']}: ${license['expire_date']} 만료');
|
||||
@@ -176,7 +176,7 @@ Future<TestResult> runOverviewTests({
|
||||
final altResponse = await dio.get('$baseUrl/licenses/expiring');
|
||||
if (altResponse.statusCode == 200) {
|
||||
final licenses = altResponse.data['data'] as List;
|
||||
if (verbose) debugPrint('✅ 대체 API로 조회 성공: ${licenses.length}개');
|
||||
if (verbose) debugPrint('✅ 대체 API로 조회 성공: ${licenses.items.length}개');
|
||||
passedCount++;
|
||||
} else {
|
||||
passedCount++;
|
||||
@@ -324,10 +324,10 @@ Future<TestResult> runOverviewTests({
|
||||
|
||||
final trendData = response.data['data'] as List;
|
||||
|
||||
if (verbose) debugPrint('✅ 일별 트렌드 데이터 조회 성공: ${trendData.length}일치');
|
||||
if (verbose) debugPrint('✅ 일별 트렌드 데이터 조회 성공: ${trendData.items.length}일치');
|
||||
|
||||
// 최근 7일 데이터 표시
|
||||
final displayDays = trendData.length > 7 ? 7 : trendData.length;
|
||||
final displayDays = trendData.items.length > 7 ? 7 : trendData.items.length;
|
||||
for (int i = 0; i < displayDays; i++) {
|
||||
final day = trendData[i];
|
||||
if (verbose) debugPrint(' - ${day['date']}: 입고 ${day['in_count']}건, 출고 ${day['out_count']}건');
|
||||
@@ -616,10 +616,10 @@ void main() {
|
||||
|
||||
final activities = response.data['data'] as List;
|
||||
|
||||
debugPrint('✅ 최근 활동 내역 조회 성공: ${activities.length}개');
|
||||
debugPrint('✅ 최근 활동 내역 조회 성공: ${activities.items.length}개');
|
||||
|
||||
// 최근 5개 활동 표시
|
||||
final displayCount = activities.length > 5 ? 5 : activities.length;
|
||||
final displayCount = activities.items.length > 5 ? 5 : activities.items.length;
|
||||
for (int i = 0; i < displayCount; i++) {
|
||||
final activity = activities[i];
|
||||
debugPrint(' ${i + 1}. ${activity['action']} - ${activity['timestamp']}');
|
||||
@@ -642,7 +642,7 @@ void main() {
|
||||
|
||||
final expiringLicenses = response.data['data'] as List;
|
||||
|
||||
debugPrint('✅ 만료 예정 라이센스 조회 성공: ${expiringLicenses.length}개');
|
||||
debugPrint('✅ 만료 예정 라이센스 조회 성공: ${expiringLicenses.items.length}개');
|
||||
|
||||
for (final license in expiringLicenses) {
|
||||
debugPrint(' - ${license['product_name']}: ${license['expire_date']} 만료');
|
||||
@@ -656,7 +656,7 @@ void main() {
|
||||
final altResponse = await dio.get('$baseUrl/licenses/expiring');
|
||||
if (altResponse.statusCode == 200) {
|
||||
final licenses = altResponse.data['data'] as List;
|
||||
debugPrint('✅ 대체 API로 조회 성공: ${licenses.length}개');
|
||||
debugPrint('✅ 대체 API로 조회 성공: ${licenses.items.length}개');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ 대체 방법도 실패: $e');
|
||||
@@ -780,10 +780,10 @@ void main() {
|
||||
|
||||
final trendData = response.data['data'] as List;
|
||||
|
||||
debugPrint('✅ 일별 트렌드 데이터 조회 성공: ${trendData.length}일치');
|
||||
debugPrint('✅ 일별 트렌드 데이터 조회 성공: ${trendData.items.length}일치');
|
||||
|
||||
// 최근 7일 데이터 표시
|
||||
final displayDays = trendData.length > 7 ? 7 : trendData.length;
|
||||
final displayDays = trendData.items.length > 7 ? 7 : trendData.items.length;
|
||||
for (int i = 0; i < displayDays; i++) {
|
||||
final day = trendData[i];
|
||||
debugPrint(' - ${day['date']}: 입고 ${day['in_count']}건, 출고 ${day['out_count']}건');
|
||||
|
||||
@@ -109,8 +109,8 @@ class PaginationTest {
|
||||
'status': 'PASS',
|
||||
'page': 1,
|
||||
'perPage': 5,
|
||||
'count': page1.length,
|
||||
'firstItem': page1.isNotEmpty ? page1.first.name : null,
|
||||
'count': page1.items.length,
|
||||
'firstItem': page1.items.isNotEmpty ? page1.items.first.name : null,
|
||||
});
|
||||
|
||||
// 2. 두 번째 페이지 조회
|
||||
@@ -125,15 +125,15 @@ class PaginationTest {
|
||||
'status': 'PASS',
|
||||
'page': 2,
|
||||
'perPage': 5,
|
||||
'count': page2.length,
|
||||
'firstItem': page2.isNotEmpty ? page2.first.name : null,
|
||||
'count': page2.items.length,
|
||||
'firstItem': page2.items.isNotEmpty ? page2.items.first.name : null,
|
||||
});
|
||||
|
||||
// 3. 페이지 간 중복 체크
|
||||
print('테스트 3: 페이지 간 중복 체크');
|
||||
if (page1.isNotEmpty && page2.isNotEmpty) {
|
||||
final page1Ids = page1.map((c) => c.id).toSet();
|
||||
final page2Ids = page2.map((c) => c.id).toSet();
|
||||
if (page1.items.isNotEmpty && page2.items.isNotEmpty) {
|
||||
final page1Ids = page1.items.map((c) => c.id).toSet();
|
||||
final page2Ids = page2.items.map((c) => c.id).toSet();
|
||||
final hasDuplicates = page1Ids.intersection(page2Ids).isNotEmpty;
|
||||
|
||||
result['steps'].add({
|
||||
@@ -155,8 +155,8 @@ class PaginationTest {
|
||||
'name': '마지막 페이지',
|
||||
'status': 'PASS',
|
||||
'page': 100,
|
||||
'count': lastPage.length,
|
||||
'note': lastPage.isEmpty ? '빈 페이지 반환 (정상)' : '데이터 있음',
|
||||
'count': lastPage.items.length,
|
||||
'note': lastPage.items.isEmpty ? '빈 페이지 반환 (정상)' : '데이터 있음',
|
||||
});
|
||||
|
||||
result['overall'] = 'PASS';
|
||||
@@ -189,8 +189,8 @@ class PaginationTest {
|
||||
'status': 'PASS',
|
||||
'page': 1,
|
||||
'perPage': 10,
|
||||
'count': page1.length,
|
||||
'firstItem': page1.isNotEmpty ? page1.first.name : null,
|
||||
'count': page1.items.length,
|
||||
'firstItem': page1.items.isNotEmpty ? page1.items.first.name : null,
|
||||
});
|
||||
|
||||
// 2. 페이지 크기 테스트
|
||||
@@ -205,10 +205,10 @@ class PaginationTest {
|
||||
|
||||
result['steps'].add({
|
||||
'name': 'perPage=$size',
|
||||
'status': page.length <= size ? 'PASS' : 'FAIL',
|
||||
'status': page.items.length <= size ? 'PASS' : 'FAIL',
|
||||
'requested': size,
|
||||
'received': page.length,
|
||||
'note': page.length > size ? '요청보다 많은 데이터 반환' : '정상',
|
||||
'received': page.items.length,
|
||||
'note': page.items.length > size ? '요청보다 많은 데이터 반환' : '정상',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -279,8 +279,8 @@ class PaginationTest {
|
||||
result['steps'].add({
|
||||
'name': '기본 페이지네이션',
|
||||
'status': 'PASS',
|
||||
'page1Count': page1.length,
|
||||
'page2Count': page2.length,
|
||||
'page1Count': page1.items.length,
|
||||
'page2Count': page2.items.length,
|
||||
});
|
||||
|
||||
// 2. 필터와 페이지네이션 조합
|
||||
@@ -297,8 +297,8 @@ class PaginationTest {
|
||||
'name': '필터 + 페이지네이션',
|
||||
'status': 'PASS',
|
||||
'filter': 'role=S',
|
||||
'count': adminPage1.length,
|
||||
'allAreAdmins': adminPage1.every((u) => u.role == 'S'),
|
||||
'count': adminPage1.items.length,
|
||||
'allAreAdmins': adminPage1.items.every((u) => u.role == 'S'),
|
||||
});
|
||||
|
||||
// 3. 빈 페이지 처리
|
||||
@@ -312,8 +312,8 @@ class PaginationTest {
|
||||
'name': '빈 페이지 처리',
|
||||
'status': 'PASS',
|
||||
'page': 999,
|
||||
'isEmpty': emptyPage.isEmpty,
|
||||
'note': emptyPage.isEmpty ? '빈 리스트 반환 (정상)' : '데이터 있음',
|
||||
'isEmpty': emptyPage.items.isEmpty,
|
||||
'note': emptyPage.items.isEmpty ? '빈 리스트 반환 (정상)' : '데이터 있음',
|
||||
});
|
||||
|
||||
result['overall'] = 'PASS';
|
||||
@@ -452,8 +452,8 @@ class PaginationTest {
|
||||
'name': '매우 큰 페이지',
|
||||
'status': 'PASS',
|
||||
'page': 999999,
|
||||
'isEmpty': hugePage.isEmpty,
|
||||
'note': hugePage.isEmpty ? '빈 리스트 반환 (정상)' : '데이터 있음',
|
||||
'isEmpty': hugePage.items.isEmpty,
|
||||
'note': hugePage.items.isEmpty ? '빈 리스트 반환 (정상)' : '데이터 있음',
|
||||
});
|
||||
|
||||
// 5. 매우 큰 perPage
|
||||
@@ -468,7 +468,7 @@ class PaginationTest {
|
||||
'name': '매우 큰 perPage',
|
||||
'status': 'PASS',
|
||||
'perPage': 10000,
|
||||
'count': hugePerPage.length,
|
||||
'count': hugePerPage.items.length,
|
||||
'note': '처리됨',
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -62,7 +62,7 @@ void main() {
|
||||
debugPrint('─────────────────────────────────────────────────────────────────');
|
||||
|
||||
final tests = results['tests'] as List;
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
for (var i = 0; i < tests.items.length; i++) {
|
||||
final test = tests[i];
|
||||
final status = test['passed'] ? '✅' : '❌';
|
||||
final retryInfo = test['retryCount'] > 0 ? ' (재시도: ${test['retryCount']}회)' : '';
|
||||
@@ -130,7 +130,7 @@ Future<void> _generateReports(Map<String, dynamic> results, Duration duration) a
|
||||
mdContent.writeln('');
|
||||
|
||||
final tests = results['tests'] as List;
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
for (var i = 0; i < tests.items.length; i++) {
|
||||
final test = tests[i];
|
||||
final status = test['passed'] ? '✅ 성공' : '❌ 실패';
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ void main() {
|
||||
|
||||
// 자동 수정된 항목
|
||||
final fixes = reportCollector.getAutoFixes();
|
||||
if (fixes.isNotEmpty) {
|
||||
if (fixes.items.isNotEmpty) {
|
||||
debugPrint('\n=== 자동 수정된 항목 ===');
|
||||
for (final fix in fixes) {
|
||||
debugPrint('- ${fix.errorType}: ${fix.solution}');
|
||||
|
||||
@@ -55,11 +55,11 @@ void main() {
|
||||
// 메타데이터 가져오기
|
||||
final metadata = equipmentOutTest.getScreenMetadata();
|
||||
debugPrint('화면: ${metadata.screenName}');
|
||||
debugPrint('엔드포인트 수: ${metadata.relatedEndpoints.length}');
|
||||
debugPrint('엔드포인트 수: ${metadata.relatedEndpoints.items.length}');
|
||||
|
||||
// 기능 감지
|
||||
final features = await equipmentOutTest.detectFeatures(metadata);
|
||||
debugPrint('감지된 기능: ${features.length}개');
|
||||
debugPrint('감지된 기능: ${features.items.length}개');
|
||||
|
||||
// 테스트 실행
|
||||
final result = await equipmentOutTest.executeTests(features);
|
||||
|
||||
@@ -55,11 +55,11 @@ void main() {
|
||||
// 메타데이터 가져오기
|
||||
final metadata = overviewTest.getScreenMetadata();
|
||||
debugPrint('화면: ${metadata.screenName}');
|
||||
debugPrint('엔드포인트 수: ${metadata.relatedEndpoints.length}');
|
||||
debugPrint('엔드포인트 수: ${metadata.relatedEndpoints.items.length}');
|
||||
|
||||
// 기능 감지
|
||||
final features = await overviewTest.detectFeatures(metadata);
|
||||
debugPrint('감지된 기능: ${features.length}개');
|
||||
debugPrint('감지된 기능: ${features.items.length}개');
|
||||
|
||||
// 테스트 실행
|
||||
final result = await overviewTest.executeTests(features);
|
||||
|
||||
@@ -62,17 +62,17 @@ void main() {
|
||||
'테스트 이름: ${report.testName}\n'
|
||||
'테스트 결과: ${report.testResult.passedTests == report.testResult.totalTests ? '성공' : '실패'}\n'
|
||||
'소요 시간: ${report.duration}\n'
|
||||
'에러 수: ${report.errors.length}개',
|
||||
'에러 수: ${report.errors.items.length}개',
|
||||
details: {
|
||||
'testName': report.testName,
|
||||
'passed': report.testResult.passedTests == report.testResult.totalTests,
|
||||
'duration': report.duration.toString(),
|
||||
'errorCount': report.errors.length,
|
||||
'errorCount': report.errors.items.length,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (report.errors.isNotEmpty) {
|
||||
if (report.errors.items.isNotEmpty) {
|
||||
for (final error in report.errors) {
|
||||
reportCollector.addError(
|
||||
report_models.ErrorReport(
|
||||
|
||||
@@ -128,7 +128,7 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
|
||||
// 기능 감지
|
||||
final features = await detectFeatures(metadata);
|
||||
_log('감지된 기능: ${features.map((f) => f.featureName).join(', ')}');
|
||||
_log('감지된 기능: ${features.items.map((f) => f.featureName).join(', ')}');
|
||||
|
||||
// 테스트 실행
|
||||
final result = await executeTests(features);
|
||||
@@ -266,7 +266,7 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
// createdIds를 resourceType별로 분류
|
||||
for (final id in createdIds) {
|
||||
final parts = id.split(':');
|
||||
if (parts.length == 2) {
|
||||
if (parts.items.length == 2) {
|
||||
final resourceType = parts[0];
|
||||
final resourceId = parts[1];
|
||||
resourcesByType.putIfAbsent(resourceType, () => []).add(resourceId);
|
||||
@@ -375,9 +375,9 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
);
|
||||
|
||||
testContext.setData('readResults', results);
|
||||
testContext.setData('readCount', results is List ? results.length : 1);
|
||||
testContext.setData('readCount', results is List ? results.items.length : 1);
|
||||
|
||||
_log('[READ] 성공: ${results is List ? results.length : 1}개 항목');
|
||||
_log('[READ] 성공: ${results is List ? results.items.length : 1}개 항목');
|
||||
} catch (e) {
|
||||
_log('[READ] 실패: $e');
|
||||
|
||||
@@ -496,7 +496,7 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
await performCreate(data);
|
||||
|
||||
final service = getService();
|
||||
final searchKeyword = data.data['name']?.toString().split(' ').first ?? 'test';
|
||||
final searchKeyword = data.data['name']?.toString().split(' ').items.first ?? 'test';
|
||||
|
||||
final results = await service.search(searchKeyword);
|
||||
testContext.setData('searchResults', results);
|
||||
@@ -511,9 +511,9 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
expect(searchResults, isNotNull, reason: '검색 결과가 없음');
|
||||
expect(searchResults, isA<List>(), reason: '올바른 검색 결과 형식이 아님');
|
||||
|
||||
if (searchResults.isNotEmpty) {
|
||||
if (searchResults.items.isNotEmpty) {
|
||||
// 검색 결과가 키워드를 포함하는지 확인
|
||||
final firstResult = searchResults.first;
|
||||
final firstResult = searchResults.items.first;
|
||||
expect(
|
||||
firstResult.toString().toLowerCase(),
|
||||
contains(searchKeyword.toLowerCase()),
|
||||
@@ -564,9 +564,9 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
expect(page2Results, isNotNull, reason: '두 번째 페이지 결과가 없음');
|
||||
|
||||
// 페이지별 결과가 다른지 확인 (데이터가 충분한 경우)
|
||||
if (page1Results.isNotEmpty && page2Results.isNotEmpty) {
|
||||
if (page1Results.items.isNotEmpty && page2Results.items.isNotEmpty) {
|
||||
expect(
|
||||
page1Results.first.id != page2Results.first.id,
|
||||
page1Results.items.first.id != page2Results.items.first.id,
|
||||
isTrue,
|
||||
reason: '페이지네이션이 올바르게 작동하지 않음',
|
||||
);
|
||||
@@ -658,7 +658,7 @@ abstract class BaseScreenTest extends ScreenTestFramework {
|
||||
final fixResult = await autoFixer.attemptAutoFix(diagnosis);
|
||||
|
||||
if (fixResult.success) {
|
||||
_log('자동 수정 성공: ${fixResult.executedActions.length}개 액션 적용');
|
||||
_log('자동 수정 성공: ${fixResult.executedActions.items.length}개 액션 적용');
|
||||
|
||||
// 수정 액션 적용 (AutoFixResult는 String 액션을 반환)
|
||||
// TODO: String 액션을 FixAction으로 변환하거나 별도 처리 필요
|
||||
|
||||
@@ -169,11 +169,11 @@ class ExampleEquipmentScreenTest extends BaseScreenTest {
|
||||
final equipmentData = data.data;
|
||||
|
||||
// 필수 필드 검증
|
||||
if (equipmentData['manufacturer'] == null || equipmentData['manufacturer'].isEmpty) {
|
||||
if (equipmentData['manufacturer'] == null || equipmentData['manufacturer'].items.isEmpty) {
|
||||
throw ValidationError('제조사는 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
if (equipmentData['name'] == null || equipmentData['name'].isEmpty) {
|
||||
if (equipmentData['name'] == null || equipmentData['name'].items.isEmpty) {
|
||||
throw ValidationError('장비명은 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ class EquipmentInAutomatedTest extends BaseScreenTest {
|
||||
);
|
||||
|
||||
expect(diagnosis.errorType, equals(ErrorType.missingRequiredField));
|
||||
_log('진단 결과: ${diagnosis.missingFields?.length ?? 0}개 필드 누락');
|
||||
_log('진단 결과: ${diagnosis.missingFields?.items.length ?? 0}개 필드 누락');
|
||||
|
||||
// 자동 수정
|
||||
final fixResult = await autoFixer.attemptAutoFix(diagnosis);
|
||||
|
||||
@@ -34,8 +34,8 @@ void assertTrue(bool condition, {String? message}) {
|
||||
}
|
||||
|
||||
void assertIsNotEmpty(dynamic collection, {String? message}) {
|
||||
if (collection == null || (collection is Iterable && collection.isEmpty) ||
|
||||
(collection is Map && collection.isEmpty)) {
|
||||
if (collection == null || (collection is Iterable && collection.items.isEmpty) ||
|
||||
(collection is Map && collection.items.isEmpty)) {
|
||||
throw AssertionError(message ?? 'Expected non-empty collection');
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ class EquipmentInFullTest {
|
||||
_test10CompleteIncoming,
|
||||
];
|
||||
|
||||
results['totalTests'] = tests.length;
|
||||
results['totalTests'] = tests.items.length;
|
||||
|
||||
// 각 테스트 실행
|
||||
for (final test in tests) {
|
||||
@@ -234,7 +234,7 @@ class EquipmentInFullTest {
|
||||
|
||||
assertEqual(statusFilter.statusCode, 200, message: '상태 필터링 응답이 200이어야 합니다');
|
||||
final availableEquipment = statusFilter.data['data'] as List;
|
||||
debugPrint('[TEST 2] 사용 가능한 장비 수: ${availableEquipment.length}');
|
||||
debugPrint('[TEST 2] 사용 가능한 장비 수: ${availableEquipment.items.length}');
|
||||
|
||||
// 모든 조회된 장비가 'available' 상태인지 확인
|
||||
for (final equipment in availableEquipment) {
|
||||
@@ -243,8 +243,8 @@ class EquipmentInFullTest {
|
||||
}
|
||||
|
||||
// 회사별 필터링 (예시)
|
||||
if (availableEquipment.isNotEmpty) {
|
||||
final companyId = availableEquipment.first['company_id'];
|
||||
if (availableEquipment.items.isNotEmpty) {
|
||||
final companyId = availableEquipment.items.first['company_id'];
|
||||
final companyFilter = await apiClient.dio.get(
|
||||
'/equipment',
|
||||
queryParameters: {
|
||||
@@ -256,7 +256,7 @@ class EquipmentInFullTest {
|
||||
|
||||
assertEqual(companyFilter.statusCode, 200,
|
||||
message: '회사별 필터링 응답이 200이어야 합니다');
|
||||
debugPrint('[TEST 2] 회사 ID $companyId의 장비 수: ${companyFilter.data['data'].length}');
|
||||
debugPrint('[TEST 2] 회사 ID $companyId의 장비 수: ${companyFilter.data['data'].items.length}');
|
||||
}
|
||||
|
||||
debugPrint('[TEST 2] ✅ 장비 검색 및 필터링 성공');
|
||||
@@ -312,7 +312,7 @@ class EquipmentInFullTest {
|
||||
debugPrint('[TEST 4] 장비 정보 수정 시작...');
|
||||
|
||||
// 수정할 장비가 없으면 먼저 생성
|
||||
if (createdEquipmentIds.isEmpty) {
|
||||
if (createdEquipmentIds.items.isEmpty) {
|
||||
await _createTestEquipment();
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ class EquipmentInFullTest {
|
||||
debugPrint('[TEST 6] 장비 상태 변경 시작...');
|
||||
|
||||
// 상태 변경할 장비가 없으면 생성
|
||||
if (createdEquipmentIds.isEmpty) {
|
||||
if (createdEquipmentIds.items.isEmpty) {
|
||||
await _createTestEquipment();
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ class EquipmentInFullTest {
|
||||
debugPrint('[TEST 7] 장비 이력 추가 시작...');
|
||||
|
||||
// 이력 추가할 장비가 없으면 생성
|
||||
if (createdEquipmentIds.isEmpty) {
|
||||
if (createdEquipmentIds.items.isEmpty) {
|
||||
await _createTestEquipment();
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ class EquipmentInFullTest {
|
||||
// 실제 이미지 업로드는 파일 시스템 접근이 필요하므로
|
||||
// 여기서는 메타데이터만 테스트
|
||||
|
||||
if (createdEquipmentIds.isEmpty) {
|
||||
if (createdEquipmentIds.items.isEmpty) {
|
||||
await _createTestEquipment();
|
||||
}
|
||||
|
||||
@@ -524,10 +524,10 @@ class EquipmentInFullTest {
|
||||
);
|
||||
|
||||
final results = response.data['data'] as List;
|
||||
if (results.isEmpty) {
|
||||
if (results.items.isEmpty) {
|
||||
debugPrint('[TEST 9] 바코드에 해당하는 장비 없음 - 새 장비 등록 필요');
|
||||
} else {
|
||||
debugPrint('[TEST 9] 바코드에 해당하는 장비 찾음: ${results.first['name']}');
|
||||
debugPrint('[TEST 9] 바코드에 해당하는 장비 찾음: ${results.items.first['name']}');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[TEST 9] 바코드 검색 중 에러 (예상됨): $e');
|
||||
@@ -547,7 +547,7 @@ class EquipmentInFullTest {
|
||||
debugPrint('[TEST 10] 입고 완료 처리 시작...');
|
||||
|
||||
// 입고 처리할 장비가 없으면 생성
|
||||
if (createdEquipmentIds.isEmpty) {
|
||||
if (createdEquipmentIds.items.isEmpty) {
|
||||
await _createTestEquipment();
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class EquipmentOutScreenTest extends BaseScreenTest {
|
||||
perPage: 10,
|
||||
);
|
||||
|
||||
if (equipments.isEmpty) {
|
||||
if (equipments.items.isEmpty) {
|
||||
_log('출고 가능한 장비가 없음, 새 장비 생성 필요');
|
||||
// 테스트를 위해 장비를 먼저 입고시킴
|
||||
await _createAndStockEquipment();
|
||||
@@ -170,7 +170,7 @@ class EquipmentOutScreenTest extends BaseScreenTest {
|
||||
|
||||
expect(availableEquipments, isNotEmpty, reason: '출고 가능한 장비가 없습니다');
|
||||
|
||||
final targetEquipment = availableEquipments.first;
|
||||
final targetEquipment = availableEquipments.items.first;
|
||||
_log('출고 대상 장비: ${targetEquipment.name} (ID: ${targetEquipment.id})');
|
||||
|
||||
// 2. 출고 요청 데이터 생성
|
||||
@@ -266,13 +266,13 @@ class EquipmentOutScreenTest extends BaseScreenTest {
|
||||
perPage: 10,
|
||||
);
|
||||
|
||||
if (equipments.isEmpty) {
|
||||
if (equipments.items.isEmpty) {
|
||||
_log('테스트할 장비가 없음');
|
||||
testContext.setData('insufficientInventoryTested', false);
|
||||
return;
|
||||
}
|
||||
|
||||
final targetEquipment = equipments.first;
|
||||
final targetEquipment = equipments.items.first;
|
||||
final availableQuantity = targetEquipment.quantity;
|
||||
|
||||
// 재고보다 많은 수량으로 출고 시도
|
||||
|
||||
@@ -427,10 +427,10 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
_log('만료 예정 라이선스 조회 중...');
|
||||
final expiringLicenses = await licenseService.getExpiringLicenses(days: 30);
|
||||
|
||||
_log('30일 이내 만료 예정 라이선스: ${expiringLicenses.length}개');
|
||||
_log('30일 이내 만료 예정 라이선스: ${expiringLicenses.items.length}개');
|
||||
|
||||
// 3. 방금 생성한 라이선스가 포함되어 있는지 확인
|
||||
final hasOurLicense = expiringLicenses.any((l) => l.id == created.id);
|
||||
final hasOurLicense = expiringLicenses.items.any((l) => l.id == created.id);
|
||||
|
||||
testContext.setData('expiringLicenseCreated', created);
|
||||
testContext.setData('expiringLicensesList', expiringLicenses);
|
||||
@@ -494,10 +494,10 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
isActive: false,
|
||||
);
|
||||
|
||||
_log('비활성 라이선스: ${inactiveLicenses.length}개');
|
||||
_log('비활성 라이선스: ${inactiveLicenses.items.length}개');
|
||||
|
||||
// 3. 만료된 라이선스가 비활성 목록에 있는지 확인
|
||||
final hasExpiredLicense = inactiveLicenses.any((l) => l.id == created.id);
|
||||
final hasExpiredLicense = inactiveLicenses.items.any((l) => l.id == created.id);
|
||||
|
||||
testContext.setData('expiredLicenseCreated', created);
|
||||
testContext.setData('inactiveLicensesList', inactiveLicenses);
|
||||
@@ -551,7 +551,7 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
await licenseService.createLicense(invalidLicense);
|
||||
_log('⚠️ 잘못된 키가 허용됨: "$invalidKey"');
|
||||
} catch (e) {
|
||||
_log('✓ 예상된 검증 에러 발생: "$invalidKey" - ${e.toString().split('\n').first}');
|
||||
_log('✓ 예상된 검증 에러 발생: "$invalidKey" - ${e.toString().split('\n').items.first}');
|
||||
validationErrors++;
|
||||
}
|
||||
}
|
||||
@@ -645,7 +645,7 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
await licenseService.createLicense(duplicateLicense);
|
||||
_log('⚠️ 중복 라이선스 키가 허용되었습니다');
|
||||
} catch (e) {
|
||||
_log('✓ 예상된 중복 에러 발생: ${e.toString().split('\n').first}');
|
||||
_log('✓ 예상된 중복 에러 발생: ${e.toString().split('\n').items.first}');
|
||||
duplicateRejected = true;
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
);
|
||||
|
||||
expect(diagnosis.errorType, equals(ErrorType.missingRequiredField));
|
||||
_log('진단 결과: ${diagnosis.missingFields?.length ?? 0}개 필드 누락');
|
||||
_log('진단 결과: ${diagnosis.missingFields?.items.length ?? 0}개 필드 누락');
|
||||
|
||||
// 자동 수정
|
||||
final fixResult = await autoFixer.attemptAutoFix(diagnosis);
|
||||
@@ -892,8 +892,8 @@ class LicenseScreenTest extends BaseScreenTest {
|
||||
// 2. 사용자 목록 조회 (할당할 사용자 찾기)
|
||||
final users = await userService.getUsers(page: 1, perPage: 10);
|
||||
|
||||
if (users.isNotEmpty) {
|
||||
final targetUser = users.first;
|
||||
if (users.items.isNotEmpty) {
|
||||
final targetUser = users.items.first;
|
||||
_log('할당 대상 사용자: ${targetUser.name} (ID: ${targetUser.id})');
|
||||
|
||||
// 3. 라이선스 할당
|
||||
@@ -1034,7 +1034,7 @@ class LicenseTestData {
|
||||
// 라이선스 키 생성기
|
||||
static String generateLicenseKey() {
|
||||
final prefixes = ['PRO', 'ENT', 'STD', 'TRIAL', 'DEV', 'PROD'];
|
||||
final prefix = prefixes[random.nextInt(prefixes.length)];
|
||||
final prefix = prefixes[random.nextInt(prefixes.items.length)];
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch.toString().substring(6);
|
||||
final randomPart = random.nextInt(9999).toString().padLeft(4, '0');
|
||||
|
||||
@@ -1061,7 +1061,7 @@ class LicenseTestData {
|
||||
'MongoDB Enterprise',
|
||||
];
|
||||
|
||||
return products[random.nextInt(products.length)];
|
||||
return products[random.nextInt(products.items.length)];
|
||||
}
|
||||
|
||||
// 벤더명 생성기
|
||||
@@ -1084,13 +1084,13 @@ class LicenseTestData {
|
||||
'Elastic',
|
||||
];
|
||||
|
||||
return vendors[random.nextInt(vendors.length)];
|
||||
return vendors[random.nextInt(vendors.items.length)];
|
||||
}
|
||||
|
||||
// 라이선스 타입 생성기
|
||||
static String generateLicenseType() {
|
||||
final types = ['perpetual', 'subscription', 'trial', 'oem', 'academic', 'nfr'];
|
||||
return types[random.nextInt(types.length)];
|
||||
return types[random.nextInt(types.items.length)];
|
||||
}
|
||||
|
||||
// 구매일 생성기 (과거 2년 이내)
|
||||
|
||||
@@ -178,7 +178,7 @@ class OverviewScreenTest extends BaseScreenTest {
|
||||
'totalEquipment': overviewController.overviewStats?.totalEquipment ?? 0,
|
||||
'activeEquipment': overviewController.overviewStats?.availableEquipment ?? 0,
|
||||
'totalLicenses': overviewController.overviewStats?.totalLicenses ?? 0,
|
||||
'expiringLicenses': overviewController.expiringLicenses.length,
|
||||
'expiringLicenses': overviewController.expiringLicenses.items.length,
|
||||
'totalCompanies': overviewController.totalCompanies,
|
||||
'totalUsers': overviewController.totalUsers,
|
||||
'totalWarehouses': overviewController.overviewStats?.totalWarehouseLocations ?? 0,
|
||||
@@ -361,7 +361,7 @@ class OverviewScreenTest extends BaseScreenTest {
|
||||
'totalEquipment': overviewController.overviewStats?.totalEquipment ?? 0,
|
||||
'activeEquipment': overviewController.overviewStats?.availableEquipment ?? 0,
|
||||
'totalLicenses': overviewController.overviewStats?.totalLicenses ?? 0,
|
||||
'expiringLicenses': overviewController.expiringLicenses.length,
|
||||
'expiringLicenses': overviewController.expiringLicenses.items.length,
|
||||
'totalCompanies': overviewController.totalCompanies,
|
||||
'totalUsers': overviewController.totalUsers,
|
||||
'totalWarehouses': overviewController.overviewStats?.totalWarehouseLocations ?? 0,
|
||||
|
||||
@@ -82,7 +82,7 @@ class TestSuiteResult {
|
||||
buffer.writeln('⚠️ 실패한 테스트가 있습니다.');
|
||||
buffer.writeln('\n실패한 테스트 목록:');
|
||||
for (final result in results) {
|
||||
if (result.failedTestNames.isNotEmpty) {
|
||||
if (result.failedTestNames.items.isNotEmpty) {
|
||||
buffer.writeln('\n${result.name}:');
|
||||
for (final testName in result.failedTestNames) {
|
||||
buffer.writeln(' - $testName');
|
||||
@@ -102,6 +102,6 @@ class TestSuiteResult {
|
||||
'failedTests': failedTests,
|
||||
'overallPassRate': overallPassRate,
|
||||
'totalExecutionTimeMs': totalExecutionTime.inMilliseconds,
|
||||
'results': results.map((r) => r.toJson()).toList(),
|
||||
'results': results.items.map((r) => r.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
@@ -44,7 +44,7 @@ void main() {
|
||||
|
||||
// 대시보드 새로고침 버튼 테스트
|
||||
final refreshButton = find.byIcon(Icons.refresh);
|
||||
if (refreshButton.evaluate().isNotEmpty) {
|
||||
if (refreshButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(refreshButton);
|
||||
await tester.pumpAndSettle();
|
||||
// expect(find.byType(CircularProgressIndicator), findsNothing);
|
||||
@@ -52,7 +52,7 @@ void main() {
|
||||
|
||||
// 필터 버튼 테스트
|
||||
final filterButton = find.byIcon(Icons.filter_list);
|
||||
if (filterButton.evaluate().isNotEmpty) {
|
||||
if (filterButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(filterButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ void main() {
|
||||
|
||||
// 장비 추가 버튼 테스트
|
||||
final addButton = find.byIcon(Icons.add);
|
||||
if (addButton.evaluate().isNotEmpty) {
|
||||
if (addButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(addButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
@@ -78,7 +78,7 @@ void main() {
|
||||
|
||||
// 검색 버튼 테스트
|
||||
final searchButton = find.byIcon(Icons.search);
|
||||
if (searchButton.evaluate().isNotEmpty) {
|
||||
if (searchButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(searchButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -93,13 +93,13 @@ void main() {
|
||||
|
||||
// 회사 추가 버튼 테스트
|
||||
final addCompanyButton = find.text('회사 등록');
|
||||
if (addCompanyButton.evaluate().isNotEmpty) {
|
||||
if (addCompanyButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(addCompanyButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 폼에서 취소 버튼 클릭
|
||||
final cancelButton = find.byIcon(Icons.arrow_back);
|
||||
if (cancelButton.evaluate().isNotEmpty) {
|
||||
if (cancelButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(cancelButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -117,13 +117,13 @@ void main() {
|
||||
|
||||
// 상태 드롭다운 찾기
|
||||
final statusDropdown = find.byKey(Key('status_dropdown'));
|
||||
if (statusDropdown.evaluate().isNotEmpty) {
|
||||
if (statusDropdown.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(statusDropdown);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 드롭다운 옵션 선택
|
||||
final availableOption = find.text('재고').last;
|
||||
if (availableOption.evaluate().isNotEmpty) {
|
||||
if (availableOption.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(availableOption);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -139,13 +139,13 @@ void main() {
|
||||
|
||||
// 회사 유형 체크박스 테스트
|
||||
final customerCheckbox = find.text('고객사');
|
||||
if (customerCheckbox.evaluate().isNotEmpty) {
|
||||
if (customerCheckbox.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(customerCheckbox);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
final partnerCheckbox = find.text('파트너사');
|
||||
if (partnerCheckbox.evaluate().isNotEmpty) {
|
||||
if (partnerCheckbox.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(partnerCheckbox);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -167,14 +167,14 @@ void main() {
|
||||
|
||||
// 저장 버튼 클릭
|
||||
final saveButton = find.text('저장');
|
||||
if (saveButton.evaluate().isNotEmpty) {
|
||||
if (saveButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(saveButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 에러 메시지나 성공 메시지 확인
|
||||
// expect(
|
||||
// find.byType(SnackBar).evaluate().isNotEmpty ||
|
||||
// find.byType(AlertDialog).evaluate().isNotEmpty,
|
||||
// find.byType(SnackBar).evaluate().items.isNotEmpty ||
|
||||
// find.byType(AlertDialog).evaluate().items.isNotEmpty,
|
||||
// isTrue,
|
||||
// );
|
||||
}
|
||||
@@ -193,7 +193,7 @@ void main() {
|
||||
|
||||
// 저장 버튼 클릭
|
||||
final saveButton = find.text('저장');
|
||||
if (saveButton.evaluate().isNotEmpty) {
|
||||
if (saveButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(saveButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -209,14 +209,14 @@ void main() {
|
||||
await navigateToScreen(tester, 'equipment');
|
||||
|
||||
// 검색 필드에 텍스트 입력
|
||||
final searchField = find.byType(TextField).first;
|
||||
if (searchField.evaluate().isNotEmpty) {
|
||||
final searchField = find.byType(TextField).items.first;
|
||||
if (searchField.evaluate().items.isNotEmpty) {
|
||||
await tester.enterText(searchField, 'Samsung');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 검색 버튼 클릭
|
||||
final searchButton = find.byIcon(Icons.search);
|
||||
if (searchButton.evaluate().isNotEmpty) {
|
||||
if (searchButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(searchButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -231,8 +231,8 @@ void main() {
|
||||
await navigateToScreen(tester, 'company');
|
||||
|
||||
// 검색 필드에 텍스트 입력
|
||||
final searchField = find.byType(TextField).first;
|
||||
if (searchField.evaluate().isNotEmpty) {
|
||||
final searchField = find.byType(TextField).items.first;
|
||||
if (searchField.evaluate().items.isNotEmpty) {
|
||||
await tester.enterText(searchField, '삼성');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
@@ -253,21 +253,21 @@ void main() {
|
||||
|
||||
// 다음 페이지 버튼 찾기
|
||||
final nextPageButton = find.byIcon(Icons.arrow_forward);
|
||||
if (nextPageButton.evaluate().isNotEmpty) {
|
||||
if (nextPageButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(nextPageButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
// 이전 페이지 버튼 찾기
|
||||
final prevPageButton = find.byIcon(Icons.arrow_back);
|
||||
if (prevPageButton.evaluate().isNotEmpty) {
|
||||
if (prevPageButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(prevPageButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
// 페이지 번호 직접 선택
|
||||
final pageNumber = find.text('2');
|
||||
if (pageNumber.evaluate().isNotEmpty) {
|
||||
if (pageNumber.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(pageNumber);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -283,14 +283,14 @@ void main() {
|
||||
await navigateToScreen(tester, 'equipment');
|
||||
|
||||
// 삭제 버튼 찾기 (보통 각 행에 있음)
|
||||
final deleteButton = find.byIcon(Icons.delete).first;
|
||||
if (deleteButton.evaluate().isNotEmpty) {
|
||||
final deleteButton = find.byIcon(Icons.delete).items.first;
|
||||
if (deleteButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(deleteButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 확인 다이얼로그 처리
|
||||
final confirmButton = find.text('삭제');
|
||||
if (confirmButton.evaluate().isNotEmpty) {
|
||||
if (confirmButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(confirmButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -307,21 +307,21 @@ void main() {
|
||||
await navigateToScreen(tester, 'company');
|
||||
|
||||
// 수정 버튼 찾기 (보통 각 행에 있음)
|
||||
final editButton = find.byIcon(Icons.edit).first;
|
||||
if (editButton.evaluate().isNotEmpty) {
|
||||
final editButton = find.byIcon(Icons.edit).items.first;
|
||||
if (editButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(editButton);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// 수정 폼에서 필드 변경
|
||||
final nameField = find.byType(TextField).first;
|
||||
if (nameField.evaluate().isNotEmpty) {
|
||||
final nameField = find.byType(TextField).items.first;
|
||||
if (nameField.evaluate().items.isNotEmpty) {
|
||||
await tester.enterText(nameField, 'Updated Company Name');
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
// 저장 버튼 클릭
|
||||
final saveButton = find.text('수정 완료');
|
||||
if (saveButton.evaluate().isNotEmpty) {
|
||||
if (saveButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(saveButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -344,7 +344,7 @@ void main() {
|
||||
|
||||
// 3. 저장
|
||||
final saveButton = find.text('저장');
|
||||
if (saveButton.evaluate().isNotEmpty) {
|
||||
if (saveButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(saveButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -358,8 +358,8 @@ void main() {
|
||||
|
||||
// 6. 출고 버튼 클릭
|
||||
final checkoutButton = find.text('출고');
|
||||
if (checkoutButton.evaluate().isNotEmpty) {
|
||||
await tester.tap(checkoutButton.first);
|
||||
if (checkoutButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(checkoutButton.items.first);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
});
|
||||
@@ -373,45 +373,45 @@ Future<void> navigateToScreen(WidgetTester tester, String route) async {
|
||||
switch (route) {
|
||||
case 'equipment':
|
||||
final equipmentNav = find.text('장비관리');
|
||||
if (equipmentNav.evaluate().isNotEmpty) {
|
||||
if (equipmentNav.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(equipmentNav);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
break;
|
||||
case 'company':
|
||||
final companyNav = find.text('회사관리');
|
||||
if (companyNav.evaluate().isNotEmpty) {
|
||||
if (companyNav.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(companyNav);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
break;
|
||||
case 'equipment/in':
|
||||
final equipmentInNav = find.text('장비입고');
|
||||
if (equipmentInNav.evaluate().isNotEmpty) {
|
||||
if (equipmentInNav.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(equipmentInNav);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
break;
|
||||
case 'warehouse/form':
|
||||
final warehouseNav = find.text('입고지관리');
|
||||
if (warehouseNav.evaluate().isNotEmpty) {
|
||||
if (warehouseNav.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(warehouseNav);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
final addButton = find.byIcon(Icons.add);
|
||||
if (addButton.evaluate().isNotEmpty) {
|
||||
if (addButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(addButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
break;
|
||||
case 'company/form':
|
||||
final companyNav = find.text('회사관리');
|
||||
if (companyNav.evaluate().isNotEmpty) {
|
||||
if (companyNav.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(companyNav);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
final addButton = find.text('회사 등록');
|
||||
if (addButton.evaluate().isNotEmpty) {
|
||||
if (addButton.evaluate().items.isNotEmpty) {
|
||||
await tester.tap(addButton);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
@@ -421,11 +421,11 @@ Future<void> navigateToScreen(WidgetTester tester, String route) async {
|
||||
|
||||
Future<void> enterText(WidgetTester tester, String fieldKey, String text) async {
|
||||
final field = find.byKey(Key(fieldKey));
|
||||
if (field.evaluate().isEmpty) {
|
||||
if (field.evaluate().items.isEmpty) {
|
||||
// If not found by key, try by type
|
||||
final textField = find.byType(TextField);
|
||||
if (textField.evaluate().isNotEmpty) {
|
||||
await tester.enterText(textField.first, text);
|
||||
if (textField.evaluate().items.isNotEmpty) {
|
||||
await tester.enterText(textField.items.first, text);
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -699,13 +699,15 @@ class UserAutomatedTest extends BaseScreenTest {
|
||||
|
||||
@override
|
||||
Future<dynamic> performReadOperation(TestData data) async {
|
||||
return await userService.getUsers(
|
||||
final result = await userService.getUsers(
|
||||
page: data.data['page'] ?? 1,
|
||||
perPage: data.data['perPage'] ?? 20,
|
||||
isActive: data.data['isActive'],
|
||||
companyId: data.data['companyId'],
|
||||
role: data.data['role'],
|
||||
);
|
||||
// PaginatedResponse의 items를 반환하여 List처럼 사용할 수 있도록 함
|
||||
return result.items;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -60,7 +60,7 @@ Future<TestResult> runUserTests({
|
||||
if (response.statusCode == 200) {
|
||||
final users = response.data['data'] ?? [];
|
||||
if (verbose) {
|
||||
debugPrint('✅ 사용자 ${users.length}개 조회 성공');
|
||||
debugPrint('✅ 사용자 ${users.items.length}개 조회 성공');
|
||||
}
|
||||
passedTests++;
|
||||
} else {
|
||||
@@ -78,8 +78,8 @@ Future<TestResult> runUserTests({
|
||||
if (verbose) debugPrint('\n➕ 일반 사용자 생성 테스트...');
|
||||
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final nameIndex = random.nextInt(testUserData['names']!.length);
|
||||
final deptIndex = random.nextInt(testUserData['departments']!.length);
|
||||
final nameIndex = random.nextInt(testUserData['names']!.items.length);
|
||||
final deptIndex = random.nextInt(testUserData['departments']!.items.length);
|
||||
|
||||
try {
|
||||
final newUser = {
|
||||
@@ -88,7 +88,7 @@ Future<TestResult> runUserTests({
|
||||
'password': 'Password123!',
|
||||
'name': testUserData['names']![nameIndex],
|
||||
'department': testUserData['departments']![deptIndex],
|
||||
'position': testUserData['positions']![random.nextInt(testUserData['positions']!.length)],
|
||||
'position': testUserData['positions']![random.nextInt(testUserData['positions']!.items.length)],
|
||||
'phone': '010-${1000 + random.nextInt(9000)}-${1000 + random.nextInt(9000)}',
|
||||
'role': 'user', // 일반 사용자
|
||||
};
|
||||
@@ -169,14 +169,14 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n🔍 사용자 상세 조회 테스트...');
|
||||
|
||||
if (createdUserIds.isEmpty) {
|
||||
if (createdUserIds.items.isEmpty) {
|
||||
failedTestNames.add('사용자 상세 조회');
|
||||
if (verbose) debugPrint('⚠️ 조회할 사용자가 없음');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final userId = createdUserIds.first;
|
||||
final userId = createdUserIds.items.first;
|
||||
final response = await dio.get('$baseUrl/users/$userId');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
@@ -204,14 +204,14 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n✏️ 사용자 정보 수정 테스트...');
|
||||
|
||||
if (createdUserIds.isEmpty) {
|
||||
if (createdUserIds.items.isEmpty) {
|
||||
failedTestNames.add('사용자 정보 수정');
|
||||
if (verbose) debugPrint('⚠️ 수정할 사용자가 없음');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final userId = createdUserIds.first;
|
||||
final userId = createdUserIds.items.first;
|
||||
final updatedData = {
|
||||
'name': '수정된이름_${random.nextInt(1000)}',
|
||||
'department': '수정된부서',
|
||||
@@ -243,14 +243,14 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n🔐 비밀번호 변경 테스트...');
|
||||
|
||||
if (createdUserIds.isEmpty) {
|
||||
if (createdUserIds.items.isEmpty) {
|
||||
failedTestNames.add('비밀번호 변경');
|
||||
if (verbose) debugPrint('⚠️ 대상 사용자가 없음');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final userId = createdUserIds.first;
|
||||
final userId = createdUserIds.items.first;
|
||||
final passwordData = {
|
||||
'current_password': 'Password123!',
|
||||
'new_password': 'NewPassword456!',
|
||||
@@ -281,7 +281,7 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n👤 사용자 권한 변경 테스트...');
|
||||
|
||||
if (createdUserIds.length < 2) {
|
||||
if (createdUserIds.items.length < 2) {
|
||||
failedTestNames.add('사용자 권한 변경');
|
||||
if (verbose) debugPrint('⚠️ 권한 변경할 사용자가 부족');
|
||||
return;
|
||||
@@ -317,14 +317,14 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n🔄 사용자 비활성화/활성화 테스트...');
|
||||
|
||||
if (createdUserIds.isEmpty) {
|
||||
if (createdUserIds.items.isEmpty) {
|
||||
failedTestNames.add('사용자 비활성화/활성화');
|
||||
if (verbose) debugPrint('⚠️ 대상 사용자가 없음');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final userId = createdUserIds.first;
|
||||
final userId = createdUserIds.items.first;
|
||||
|
||||
// 비활성화
|
||||
var response = await dio.patch(
|
||||
@@ -375,7 +375,7 @@ Future<TestResult> runUserTests({
|
||||
if (response.statusCode == 200) {
|
||||
final results = response.data['data'] ?? [];
|
||||
if (verbose) {
|
||||
debugPrint('✅ 사용자 검색 성공: ${results.length}개 결과');
|
||||
debugPrint('✅ 사용자 검색 성공: ${results.items.length}개 결과');
|
||||
}
|
||||
passedTests++;
|
||||
} else {
|
||||
@@ -392,7 +392,7 @@ Future<TestResult> runUserTests({
|
||||
totalTests++;
|
||||
if (verbose) debugPrint('\n🗑️ 사용자 삭제 테스트...');
|
||||
|
||||
if (createdUserIds.isEmpty) {
|
||||
if (createdUserIds.items.isEmpty) {
|
||||
failedTestNames.add('사용자 삭제');
|
||||
if (verbose) debugPrint('⚠️ 삭제할 사용자가 없음');
|
||||
return;
|
||||
|
||||
@@ -216,10 +216,12 @@ class WarehouseAutomatedTest extends BaseScreenTest {
|
||||
|
||||
@override
|
||||
Future<dynamic> performReadOperation(TestData data) async {
|
||||
return await warehouseService.getWarehouseLocations(
|
||||
final result = await warehouseService.getWarehouseLocations(
|
||||
page: 1,
|
||||
perPage: 20,
|
||||
);
|
||||
// PaginatedResponse의 items를 반환하여 List처럼 사용할 수 있도록 함
|
||||
return result.items;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -310,9 +312,9 @@ class WarehouseTestData {
|
||||
final purposes = ['물류', '보관', '배송', '집하', '분류', '냉동', '냉장', '특수', '일반', '대형'];
|
||||
final suffixes = ['창고', '센터', '물류센터', '보관소', '집하장'];
|
||||
|
||||
final type = types[random.nextInt(types.length)];
|
||||
final purpose = purposes[random.nextInt(purposes.length)];
|
||||
final suffix = suffixes[random.nextInt(suffixes.length)];
|
||||
final type = types[random.nextInt(types.items.length)];
|
||||
final purpose = purposes[random.nextInt(purposes.items.length)];
|
||||
final suffix = suffixes[random.nextInt(suffixes.items.length)];
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
return '$type $purpose$suffix - TEST$timestamp';
|
||||
@@ -329,9 +331,9 @@ class WarehouseTestData {
|
||||
'산업단지', '물류단지', '유통단지', '첨단산업단지', '일반산업단지', '국가산업단지'
|
||||
];
|
||||
|
||||
final city = cities[random.nextInt(cities.length)];
|
||||
final district = districts[random.nextInt(districts.length)];
|
||||
final industrial = industrialAreas[random.nextInt(industrialAreas.length)];
|
||||
final city = cities[random.nextInt(cities.items.length)];
|
||||
final district = districts[random.nextInt(districts.items.length)];
|
||||
final industrial = industrialAreas[random.nextInt(industrialAreas.items.length)];
|
||||
final number = random.nextInt(500) + 1;
|
||||
final detail = '$industrial $number블록 ${random.nextInt(10) + 1}호';
|
||||
|
||||
@@ -360,7 +362,7 @@ class WarehouseTestData {
|
||||
final featureCount = random.nextInt(3) + 1; // 1-3개 특징
|
||||
|
||||
for (int i = 0; i < featureCount; i++) {
|
||||
final feature = features[random.nextInt(features.length)];
|
||||
final feature = features[random.nextInt(features.items.length)];
|
||||
if (!selectedFeatures.contains(feature)) {
|
||||
selectedFeatures.add(feature);
|
||||
}
|
||||
@@ -374,8 +376,8 @@ class WarehouseTestData {
|
||||
final lastNames = ['김', '이', '박', '최', '정', '강', '조', '윤', '장', '임'];
|
||||
final firstNames = ['창고장', '소장', '센터장', '팀장', '과장', '부장', '이사', '실장'];
|
||||
|
||||
final lastName = lastNames[random.nextInt(lastNames.length)];
|
||||
final firstName = firstNames[random.nextInt(firstNames.length)];
|
||||
final lastName = lastNames[random.nextInt(lastNames.items.length)];
|
||||
final firstName = firstNames[random.nextInt(firstNames.items.length)];
|
||||
|
||||
return '$lastName$firstName';
|
||||
}
|
||||
@@ -383,7 +385,7 @@ class WarehouseTestData {
|
||||
// 연락처 생성기
|
||||
static String generateContact() {
|
||||
final areaCodes = ['02', '031', '032', '033', '041', '042', '043', '051', '052', '053'];
|
||||
final areaCode = areaCodes[random.nextInt(areaCodes.length)];
|
||||
final areaCode = areaCodes[random.nextInt(areaCodes.items.length)];
|
||||
final middle = random.nextInt(9000) + 1000;
|
||||
final last = random.nextInt(9000) + 1000;
|
||||
return '$areaCode-$middle-$last';
|
||||
@@ -392,7 +394,7 @@ class WarehouseTestData {
|
||||
// 창고 용량 생성기 (평방미터)
|
||||
static int generateCapacity() {
|
||||
final capacities = [500, 1000, 1500, 2000, 3000, 5000, 10000, 15000, 20000];
|
||||
return capacities[random.nextInt(capacities.length)];
|
||||
return capacities[random.nextInt(capacities.items.length)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +421,7 @@ extension on WarehouseAutomatedTest {
|
||||
await _testWarehouseUpdate(createdWarehouse.id);
|
||||
|
||||
// 6. 창고 검색 테스트
|
||||
await _testWarehouseSearch(createdWarehouse.name.split(' ').first);
|
||||
await _testWarehouseSearch(createdWarehouse.name.split(' ').items.first);
|
||||
|
||||
// 7. 활성/비활성 필터링 테스트
|
||||
await _testActiveFiltering();
|
||||
@@ -458,10 +460,11 @@ extension on WarehouseAutomatedTest {
|
||||
_log('창고 목록 조회 테스트 시작');
|
||||
|
||||
try {
|
||||
final warehouses = await warehouseService.getWarehouseLocations(
|
||||
final warehouseResult = await warehouseService.getWarehouseLocations(
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
);
|
||||
final warehouses = warehouseResult.items;
|
||||
|
||||
_log('창고 목록 조회 성공: ${warehouses.length}개 창고');
|
||||
if (warehouses.isNotEmpty) {
|
||||
@@ -600,12 +603,12 @@ extension on WarehouseAutomatedTest {
|
||||
try {
|
||||
// search 파라미터가 지원되는지 확인
|
||||
final searchResults = await warehouseService.searchWarehouseLocations(
|
||||
keyword: searchKeyword.split(' ').first, // 첫 단어만 사용
|
||||
keyword: searchKeyword.split(' ').items.first, // 첫 단어만 사용
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
);
|
||||
|
||||
_log('검색 결과: ${searchResults.length}개 창고');
|
||||
_log('검색 결과: ${searchResults.items.length}개 창고');
|
||||
testContext.setData('searchResults', searchResults);
|
||||
testContext.setData('searchSuccess', true);
|
||||
} catch (e) {
|
||||
@@ -613,16 +616,17 @@ extension on WarehouseAutomatedTest {
|
||||
|
||||
// 검색 기능이 없으면 전체 목록에서 필터링
|
||||
try {
|
||||
final allWarehouses = await warehouseService.getWarehouseLocations(
|
||||
final allWarehousesResult = await warehouseService.getWarehouseLocations(
|
||||
page: 1,
|
||||
perPage: 50,
|
||||
);
|
||||
final allWarehouses = allWarehousesResult.items;
|
||||
|
||||
final filtered = allWarehouses.where((w) =>
|
||||
final filtered = allWarehouses.items.where((w) =>
|
||||
w.name.toLowerCase().contains(searchKeyword.toLowerCase())
|
||||
).toList();
|
||||
|
||||
_log('필터링 결과: ${filtered.length}개 창고');
|
||||
_log('필터링 결과: ${filtered.items.length}개 창고');
|
||||
testContext.setData('searchResults', filtered);
|
||||
testContext.setData('searchSuccess', true);
|
||||
} catch (e2) {
|
||||
@@ -638,21 +642,23 @@ extension on WarehouseAutomatedTest {
|
||||
try {
|
||||
// 활성 창고만 조회
|
||||
_log('활성 창고 조회 중...');
|
||||
final activeWarehouses = await warehouseService.getWarehouseLocations(
|
||||
final activeWarehousesResult = await warehouseService.getWarehouseLocations(
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
isActive: true,
|
||||
);
|
||||
_log('활성 창고: ${activeWarehouses.length}개');
|
||||
final activeWarehouses = activeWarehousesResult.items;
|
||||
_log('활성 창고: ${activeWarehouses.items.length}개');
|
||||
|
||||
// 비활성 창고만 조회
|
||||
_log('비활성 창고 조회 중...');
|
||||
final inactiveWarehouses = await warehouseService.getWarehouseLocations(
|
||||
final inactiveWarehousesResult = await warehouseService.getWarehouseLocations(
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
isActive: false,
|
||||
);
|
||||
_log('비활성 창고: ${inactiveWarehouses.length}개');
|
||||
final inactiveWarehouses = inactiveWarehousesResult.items;
|
||||
_log('비활성 창고: ${inactiveWarehouses.items.length}개');
|
||||
|
||||
testContext.setData('activeWarehouses', activeWarehouses);
|
||||
testContext.setData('inactiveWarehouses', inactiveWarehouses);
|
||||
@@ -850,7 +856,7 @@ extension on WarehouseAutomatedTest {
|
||||
);
|
||||
|
||||
// expect(diagnosis.errorType, equals(ErrorType.missingRequiredField));
|
||||
_log('진단 결과: ${diagnosis.missingFields?.length ?? 0}개 필드 누락');
|
||||
_log('진단 결과: ${diagnosis.missingFields?.items.length ?? 0}개 필드 누락');
|
||||
|
||||
// 자동 수정
|
||||
final fixResult = await autoFixer.attemptAutoFix(diagnosis);
|
||||
@@ -897,7 +903,7 @@ extension on WarehouseAutomatedTest {
|
||||
// 1. 창고별 장비 목록 조회 (초기 상태)
|
||||
_log('창고별 장비 목록 조회 중...');
|
||||
final initialEquipment = await warehouseService.getWarehouseEquipment(warehouse.id);
|
||||
_log('초기 장비 수: ${initialEquipment.length}개');
|
||||
_log('초기 장비 수: ${initialEquipment.items.length}개');
|
||||
|
||||
// 2. 장비 입고 시뮬레이션 (실제로는 Equipment 서비스를 통해 수행)
|
||||
_log('장비 입고 프로세스는 Equipment 서비스에서 처리됩니다');
|
||||
@@ -905,17 +911,17 @@ extension on WarehouseAutomatedTest {
|
||||
// 3. 사용 중인 창고 목록 조회
|
||||
_log('사용 중인 창고 목록 조회 중...');
|
||||
final inUseWarehouses = await warehouseService.getInUseWarehouseLocations();
|
||||
_log('사용 중인 창고 수: ${inUseWarehouses.length}개');
|
||||
_log('사용 중인 창고 수: ${inUseWarehouses.items.length}개');
|
||||
|
||||
// 장비가 있는 창고는 사용 중으로 표시되어야 함
|
||||
if (initialEquipment.isNotEmpty) {
|
||||
final isInUse = inUseWarehouses.any((w) => w.id == warehouse.id);
|
||||
if (initialEquipment.items.isNotEmpty) {
|
||||
final isInUse = inUseWarehouses.items.any((w) => w.id == warehouse.id);
|
||||
// expect(isInUse, isTrue, reason: '장비가 있는 창고가 사용 중으로 표시되지 않았습니다');
|
||||
}
|
||||
|
||||
testContext.setData('equipmentIntegrationSuccess', true);
|
||||
testContext.setData('initialEquipmentCount', initialEquipment.length);
|
||||
testContext.setData('inUseWarehouseCount', inUseWarehouses.length);
|
||||
testContext.setData('initialEquipmentCount', initialEquipment.items.length);
|
||||
testContext.setData('inUseWarehouseCount', inUseWarehouses.items.length);
|
||||
|
||||
} catch (e) {
|
||||
_log('장비 연동 중 오류 발생: $e');
|
||||
@@ -946,7 +952,7 @@ extension on WarehouseAutomatedTest {
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
);
|
||||
_log('전체 창고 수: ${allWarehouses.length}개');
|
||||
_log('전체 창고 수: ${allWarehouses.items.length}개');
|
||||
|
||||
// 2. 활성 창고만 필터링
|
||||
_log('활성 창고만 필터링...');
|
||||
@@ -955,7 +961,7 @@ extension on WarehouseAutomatedTest {
|
||||
perPage: 100,
|
||||
isActive: true,
|
||||
);
|
||||
_log('활성 창고 수: ${activeWarehouses.length}개');
|
||||
_log('활성 창고 수: ${activeWarehouses.items.length}개');
|
||||
|
||||
// 3. 비활성 창고 필터링
|
||||
_log('비활성 창고 필터링...');
|
||||
@@ -964,21 +970,21 @@ extension on WarehouseAutomatedTest {
|
||||
perPage: 100,
|
||||
isActive: false,
|
||||
);
|
||||
_log('비활성 창고 수: ${inactiveWarehouses.length}개');
|
||||
_log('비활성 창고 수: ${inactiveWarehouses.items.length}개');
|
||||
|
||||
// 4. 사용 중인 창고 목록
|
||||
_log('사용 중인 창고 목록 조회...');
|
||||
final inUseWarehouses = await warehouseService.getInUseWarehouseLocations();
|
||||
_log('사용 중인 창고 수: ${inUseWarehouses.length}개');
|
||||
_log('사용 중인 창고 수: ${inUseWarehouses.items.length}개');
|
||||
|
||||
// 검증: 활성 + 비활성 = 전체 (대략적으로)
|
||||
// 페이지네이션 때문에 정확히 일치하지 않을 수 있음
|
||||
|
||||
testContext.setData('inUseManagementSuccess', true);
|
||||
testContext.setData('totalWarehouses', allWarehouses.length);
|
||||
testContext.setData('activeWarehouses', activeWarehouses.length);
|
||||
testContext.setData('inactiveWarehouses', inactiveWarehouses.length);
|
||||
testContext.setData('inUseWarehouses', inUseWarehouses.length);
|
||||
testContext.setData('totalWarehouses', allWarehouses.items.length);
|
||||
testContext.setData('activeWarehouses', activeWarehouses.items.length);
|
||||
testContext.setData('inactiveWarehouses', inactiveWarehouses.items.length);
|
||||
testContext.setData('inUseWarehouses', inUseWarehouses.items.length);
|
||||
|
||||
} catch (e) {
|
||||
_log('사용 중인 창고 관리 중 오류 발생: $e');
|
||||
@@ -1017,7 +1023,8 @@ extension WarehouseServiceExtension on WarehouseService {
|
||||
}) async {
|
||||
// 실제 검색 API가 있다면 사용
|
||||
// 없다면 전체 목록을 가져와서 필터링
|
||||
final all = await getWarehouseLocations(page: page, perPage: perPage * 5);
|
||||
final allResult = await getWarehouseLocations(page: page, perPage: perPage * 5);
|
||||
final all = allResult.items;
|
||||
return all.where((w) =>
|
||||
w.name.toLowerCase().contains(keyword.toLowerCase()) ||
|
||||
(w.address.toString().toLowerCase().contains(keyword.toLowerCase()))
|
||||
|
||||
@@ -59,7 +59,7 @@ Future<TestResult> runWarehouseTests({
|
||||
assert(response.statusCode == 200);
|
||||
assert(response.data['data'] is List);
|
||||
|
||||
if (response.data['data'].isNotEmpty) {
|
||||
if (response.data['data'].items.isNotEmpty) {
|
||||
final warehouse = response.data['data'][0];
|
||||
assert(warehouse['id'] != null);
|
||||
assert(warehouse['name'] != null);
|
||||
@@ -70,7 +70,7 @@ Future<TestResult> runWarehouseTests({
|
||||
}
|
||||
|
||||
passedCount++;
|
||||
if (verbose) debugPrint('✅ 창고 목록 조회 성공: ${response.data['data'].length}개');
|
||||
if (verbose) debugPrint('✅ 창고 목록 조회 성공: ${response.data['data'].items.length}개');
|
||||
} catch (e) {
|
||||
failedCount++;
|
||||
failedTests.add('창고 목록 조회');
|
||||
@@ -326,7 +326,7 @@ Future<TestResult> runWarehouseTests({
|
||||
assert(response.data['data'] is List);
|
||||
|
||||
passedCount++;
|
||||
if (verbose) debugPrint('✅ 창고 검색 성공: ${response.data['data'].length}개 찾음');
|
||||
if (verbose) debugPrint('✅ 창고 검색 성공: ${response.data['data'].items.length}개 찾음');
|
||||
} catch (e) {
|
||||
// 검색 기능이 없을 수 있으므로 경고만
|
||||
if (verbose) debugPrint('⚠️ 창고 검색 실패 (선택적): $e');
|
||||
|
||||
Reference in New Issue
Block a user