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:
@@ -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">');
|
||||
|
||||
Reference in New Issue
Block a user