feat: V/R 유지보수 시스템 전환 및 대시보드 테이블 형태 완성
- V/R 시스템 완전 전환: WARRANTY/CONTRACT/INSPECTION → V(방문)/R(원격) - 유지보수 대시보드 카드 → StandardDataTable 테이블 형태 전환 - "조회중..." 문제 해결: 백엔드 직접 필드 사용 (equipment_model, company_name) - MaintenanceDto 신규 필드 추가: company_id, company_name, equipment_serial, equipment_model - preloadEquipmentData 비활성화로 불필요한 equipment-history API 호출 제거 - CO-STAR 프레임워크 적용 및 CLAUDE.md v3.0 업데이트 - Flutter Analyze ERROR: 0 유지, 100% shadcn_ui 컴플라이언스 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
221
test/maintenance_dashboard_integration_test.dart
Normal file
221
test/maintenance_dashboard_integration_test.dart
Normal file
@@ -0,0 +1,221 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:superport/data/models/maintenance_stats_dto.dart';
|
||||
import 'package:superport/data/repositories/maintenance_stats_repository.dart';
|
||||
import 'package:superport/domain/usecases/get_maintenance_stats_usecase.dart';
|
||||
import 'package:superport/screens/maintenance/controllers/maintenance_dashboard_controller.dart';
|
||||
|
||||
// Mock 클래스 생성
|
||||
class MockMaintenanceStatsRepository extends Mock implements MaintenanceStatsRepository {}
|
||||
|
||||
void main() {
|
||||
group('Maintenance Dashboard Integration Tests', () {
|
||||
late MockMaintenanceStatsRepository mockRepository;
|
||||
late GetMaintenanceStatsUseCase useCase;
|
||||
late MaintenanceDashboardController controller;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockMaintenanceStatsRepository();
|
||||
useCase = GetMaintenanceStatsUseCase(repository: mockRepository);
|
||||
controller = MaintenanceDashboardController(
|
||||
getMaintenanceStatsUseCase: useCase,
|
||||
);
|
||||
});
|
||||
|
||||
test('should initialize with empty stats', () {
|
||||
// Assert
|
||||
expect(controller.stats, equals(const MaintenanceStatsDto()));
|
||||
expect(controller.isLoading, false);
|
||||
expect(controller.errorMessage, null);
|
||||
});
|
||||
|
||||
test('should load dashboard stats successfully', () async {
|
||||
// Arrange
|
||||
const mockStats = MaintenanceStatsDto(
|
||||
activeContracts: 10,
|
||||
totalContracts: 15,
|
||||
expiring60Days: 5,
|
||||
expiring30Days: 3,
|
||||
expiring7Days: 1,
|
||||
expiredContracts: 2,
|
||||
warrantyContracts: 8,
|
||||
maintenanceContracts: 5,
|
||||
inspectionContracts: 2,
|
||||
upcomingInspections: 3,
|
||||
overdueMaintenances: 1,
|
||||
totalRevenueAtRisk: 500000.0,
|
||||
completionRate: 0.85,
|
||||
updatedAt: null,
|
||||
);
|
||||
|
||||
when(mockRepository.getMaintenanceStats())
|
||||
.thenAnswer((_) async => mockStats);
|
||||
|
||||
// Act
|
||||
await controller.loadDashboardStats();
|
||||
|
||||
// Assert
|
||||
expect(controller.stats, equals(mockStats));
|
||||
expect(controller.isLoading, false);
|
||||
expect(controller.errorMessage, null);
|
||||
expect(controller.hasValidData, false); // updatedAt가 null이므로
|
||||
|
||||
// 카드 데이터 검증
|
||||
final cards = controller.dashboardCards;
|
||||
expect(cards.length, 4);
|
||||
expect(cards[0].count, 5); // 60일 내
|
||||
expect(cards[1].count, 3); // 30일 내
|
||||
expect(cards[2].count, 1); // 7일 내
|
||||
expect(cards[3].count, 2); // 만료됨
|
||||
});
|
||||
|
||||
test('should handle error state properly', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getMaintenanceStats())
|
||||
.thenThrow(Exception('Network error'));
|
||||
|
||||
// Act
|
||||
await controller.loadDashboardStats();
|
||||
|
||||
// Assert
|
||||
expect(controller.isLoading, false);
|
||||
expect(controller.errorMessage, contains('Network error'));
|
||||
expect(controller.stats, equals(const MaintenanceStatsDto()));
|
||||
});
|
||||
|
||||
test('should calculate risk score correctly', () async {
|
||||
// Arrange
|
||||
const highRiskStats = MaintenanceStatsDto(
|
||||
totalContracts: 10,
|
||||
expiring7Days: 3, // 30% 가중치
|
||||
expiring30Days: 2, // 20% 가중치
|
||||
expiring60Days: 1, // 10% 가중치
|
||||
expiredContracts: 4, // 40% 가중치
|
||||
);
|
||||
|
||||
when(mockRepository.getMaintenanceStats())
|
||||
.thenAnswer((_) async => highRiskStats);
|
||||
|
||||
// Act
|
||||
await controller.loadDashboardStats();
|
||||
|
||||
// Assert
|
||||
final riskScore = controller.riskScore;
|
||||
expect(riskScore, greaterThan(0.8)); // 높은 위험도
|
||||
expect(controller.riskStatus, MaintenanceCardStatus.critical);
|
||||
});
|
||||
|
||||
test('should format revenue at risk correctly', () async {
|
||||
// Arrange
|
||||
const statsWithRevenue = MaintenanceStatsDto(
|
||||
totalRevenueAtRisk: 1500000.0, // 150만원
|
||||
);
|
||||
|
||||
when(mockRepository.getMaintenanceStats())
|
||||
.thenAnswer((_) async => statsWithRevenue);
|
||||
|
||||
// Act
|
||||
await controller.loadDashboardStats();
|
||||
|
||||
// Assert
|
||||
expect(controller.formattedRevenueAtRisk, '1.5백만원');
|
||||
});
|
||||
|
||||
test('should handle refresh correctly', () async {
|
||||
// Arrange
|
||||
const mockStats = MaintenanceStatsDto(
|
||||
activeContracts: 5,
|
||||
updatedAt: null,
|
||||
);
|
||||
|
||||
when(mockRepository.getMaintenanceStats())
|
||||
.thenAnswer((_) async => mockStats);
|
||||
|
||||
// Act
|
||||
await controller.refreshDashboardStats();
|
||||
|
||||
// Assert
|
||||
expect(controller.isRefreshing, false);
|
||||
expect(controller.stats.activeContracts, 5);
|
||||
expect(controller.lastUpdated, isNotNull);
|
||||
});
|
||||
|
||||
test('should detect when refresh is needed', () {
|
||||
// Assert - 초기 상태에서는 새로고침 필요
|
||||
expect(controller.needsRefresh, true);
|
||||
|
||||
// 업데이트 시뮬레이션
|
||||
controller.loadDashboardStats();
|
||||
|
||||
// 즉시는 새로고침 불필요 (실제로는 시간이 지나야 true)
|
||||
// 이 테스트는 로직의 존재 여부만 확인
|
||||
expect(controller.timeSinceLastUpdate, isNotEmpty);
|
||||
});
|
||||
|
||||
test('should provide card status correctly', () {
|
||||
// 각 카드 상태 테스트
|
||||
expect(controller.expiring60DaysCard.title, '60일 내');
|
||||
expect(controller.expiring30DaysCard.title, '30일 내');
|
||||
expect(controller.expiring7DaysCard.title, '7일 내');
|
||||
expect(controller.expiredContractsCard.title, '만료됨');
|
||||
|
||||
// 기본 상태에서는 모두 active 상태여야 함
|
||||
expect(controller.expiring60DaysCard.status, MaintenanceCardStatus.active);
|
||||
expect(controller.expiring30DaysCard.status, MaintenanceCardStatus.active);
|
||||
expect(controller.expiring7DaysCard.status, MaintenanceCardStatus.active);
|
||||
expect(controller.expiredContractsCard.status, MaintenanceCardStatus.active);
|
||||
});
|
||||
});
|
||||
|
||||
group('MaintenanceStatsDto Tests', () {
|
||||
test('should create dashboard cards correctly', () {
|
||||
// Arrange
|
||||
const stats = MaintenanceStatsDto(
|
||||
expiring60Days: 10,
|
||||
expiring30Days: 5,
|
||||
expiring7Days: 2,
|
||||
expiredContracts: 3,
|
||||
);
|
||||
|
||||
// Act
|
||||
final cards = stats.dashboardCards;
|
||||
|
||||
// Assert
|
||||
expect(cards.length, 4);
|
||||
expect(cards[0].count, 10);
|
||||
expect(cards[0].status, MaintenanceCardStatus.warning);
|
||||
expect(cards[1].count, 5);
|
||||
expect(cards[1].status, MaintenanceCardStatus.urgent);
|
||||
expect(cards[2].count, 2);
|
||||
expect(cards[2].status, MaintenanceCardStatus.critical);
|
||||
expect(cards[3].count, 3);
|
||||
expect(cards[3].status, MaintenanceCardStatus.expired);
|
||||
});
|
||||
|
||||
test('should calculate risk score correctly', () {
|
||||
// Arrange
|
||||
const lowRiskStats = MaintenanceStatsDto(
|
||||
totalContracts: 100,
|
||||
expiring60Days: 5, // 5%
|
||||
expiring30Days: 2, // 2%
|
||||
expiring7Days: 0, // 0%
|
||||
expiredContracts: 1, // 1%
|
||||
);
|
||||
|
||||
const highRiskStats = MaintenanceStatsDto(
|
||||
totalContracts: 10,
|
||||
expiring60Days: 2, // 20%
|
||||
expiring30Days: 3, // 30%
|
||||
expiring7Days: 2, // 20%
|
||||
expiredContracts: 3, // 30%
|
||||
);
|
||||
|
||||
// Act & Assert
|
||||
expect(lowRiskStats.riskScore, lessThan(0.3));
|
||||
expect(lowRiskStats.riskStatus, MaintenanceCardStatus.active);
|
||||
|
||||
expect(highRiskStats.riskScore, greaterThan(0.7));
|
||||
expect(highRiskStats.riskStatus, MaintenanceCardStatus.critical);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user