import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import Dashboard from '../pages/Dashboard'; import { getDevices, getLatestData } from '../services/api'; // Mock the API services jest.mock('../services/api'); const mockGetDevices = getDevices as jest.MockedFunction; const mockGetLatestData = getLatestData as jest.MockedFunction; // Mock the hooks jest.mock('../hooks/useDevices'); jest.mock('../hooks/useSensorData'); const mockUseDevices = require('../hooks/useDevices').useDevices; const mockUseSensorData = require('../hooks/useSensorData').useSensorData; const renderWithRouter = (component: React.ReactElement) => { return render( {component} ); }; describe('Dashboard Integration', () => { const mockDevices = [ { id: 1, device_id: 'sensor-001', name: '테스트 센서', status: 'active', last_seen: '2025-08-01T10:00:00Z' } ]; const mockSensorData = [ { device_id: 'sensor-001', temperature: 25.5, humidity: 60.0, pm10: 15.2, pm25: 8.1, pressure: 1013.25, illumination: 500, tvoc: 120, co2: 450, o2: 20.9, co: 0.5, recorded_time: '2025-08-01T10:00:00Z' } ]; beforeEach(() => { jest.clearAllMocks(); // Mock useDevices hook mockUseDevices.mockReturnValue({ devices: mockDevices, loading: false, error: null, refetch: jest.fn() }); // Mock useSensorData hook mockUseSensorData.mockReturnValue({ latestData: mockSensorData, loading: false, error: null, refetch: jest.fn() }); }); it('should render dashboard with sensor data', async () => { renderWithRouter(); // Check if main title is rendered expect(screen.getByText('센서 대시보드')).toBeInTheDocument(); // Check if sensor cards are rendered await waitFor(() => { expect(screen.getByText('현재 온도')).toBeInTheDocument(); expect(screen.getByText('현재 습도')).toBeInTheDocument(); expect(screen.getByText('PM10')).toBeInTheDocument(); expect(screen.getByText('PM2.5')).toBeInTheDocument(); }); // Check if sensor values are displayed correctly expect(screen.getByText('25.5°C')).toBeInTheDocument(); expect(screen.getByText('60.0%')).toBeInTheDocument(); expect(screen.getByText('15.2μg/m³')).toBeInTheDocument(); expect(screen.getByText('8.1μg/m³')).toBeInTheDocument(); }); it('should display loading state', () => { mockUseDevices.mockReturnValue({ devices: [], loading: true, error: null, refetch: jest.fn() }); mockUseSensorData.mockReturnValue({ latestData: [], loading: true, error: null, refetch: jest.fn() }); renderWithRouter(); expect(screen.getByText('데이터를 불러오는 중...')).toBeInTheDocument(); }); it('should display error state', () => { mockUseDevices.mockReturnValue({ devices: [], loading: false, error: '디바이스 목록을 불러올 수 없습니다.', refetch: jest.fn() }); renderWithRouter(); expect(screen.getByText('오류가 발생했습니다')).toBeInTheDocument(); expect(screen.getByText('디바이스 목록을 불러올 수 없습니다.')).toBeInTheDocument(); expect(screen.getByText('다시 시도')).toBeInTheDocument(); }); it('should display device status table', async () => { renderWithRouter(); await waitFor(() => { expect(screen.getByText('디바이스 상태')).toBeInTheDocument(); expect(screen.getByText('sensor-001')).toBeInTheDocument(); expect(screen.getByText('테스트 센서')).toBeInTheDocument(); expect(screen.getByText('active')).toBeInTheDocument(); }); }); it('should display summary cards', async () => { renderWithRouter(); await waitFor(() => { expect(screen.getByText('활성 디바이스')).toBeInTheDocument(); expect(screen.getByText('1')).toBeInTheDocument(); // active device count expect(screen.getByText('총 데이터')).toBeInTheDocument(); expect(screen.getByText('1')).toBeInTheDocument(); // total data count }); }); it('should handle empty data gracefully', () => { mockUseDevices.mockReturnValue({ devices: [], loading: false, error: null, refetch: jest.fn() }); mockUseSensorData.mockReturnValue({ latestData: [], loading: false, error: null, refetch: jest.fn() }); renderWithRouter(); expect(screen.getByText('센서 대시보드')).toBeInTheDocument(); expect(screen.getByText('활성 디바이스')).toBeInTheDocument(); expect(screen.getByText('0')).toBeInTheDocument(); // no active devices }); it('should handle sensor data with invalid values', () => { const invalidSensorData = [ { device_id: 'sensor-001', temperature: 1e-40, // very small value humidity: undefined, pm10: null as any, pm25: Infinity, pressure: NaN, illumination: 500, tvoc: 120, co2: 450, o2: 20.9, co: 0.5, recorded_time: '2025-08-01T10:00:00Z' } ]; mockUseSensorData.mockReturnValue({ latestData: invalidSensorData, loading: false, error: null, refetch: jest.fn() }); renderWithRouter(); // Should display formatted values for invalid data expect(screen.getByText('0.0°C')).toBeInTheDocument(); // very small value expect(screen.getByText('N/A%')).toBeInTheDocument(); // undefined expect(screen.getByText('N/Aμg/m³')).toBeInTheDocument(); // null expect(screen.getByText('N/Aμg/m³')).toBeInTheDocument(); // Infinity expect(screen.getByText('N/AhPa')).toBeInTheDocument(); // NaN }); it('should display all sensor types', async () => { const completeSensorData = [ { device_id: 'sensor-001', temperature: 25.5, humidity: 60.0, pm10: 15.2, pm25: 8.1, pressure: 1013.25, illumination: 500, tvoc: 120, co2: 450, o2: 20.9, co: 0.5, recorded_time: '2025-08-01T10:00:00Z' } ]; mockUseSensorData.mockReturnValue({ latestData: completeSensorData, loading: false, error: null, refetch: jest.fn() }); renderWithRouter(); await waitFor(() => { // Check all sensor cards are rendered expect(screen.getByText('현재 온도')).toBeInTheDocument(); expect(screen.getByText('현재 습도')).toBeInTheDocument(); expect(screen.getByText('PM10')).toBeInTheDocument(); expect(screen.getByText('PM2.5')).toBeInTheDocument(); expect(screen.getByText('기압')).toBeInTheDocument(); expect(screen.getByText('조도')).toBeInTheDocument(); expect(screen.getByText('TVOC')).toBeInTheDocument(); expect(screen.getByText('CO2')).toBeInTheDocument(); expect(screen.getByText('O2')).toBeInTheDocument(); expect(screen.getByText('CO')).toBeInTheDocument(); }); }); it('should handle retry functionality', async () => { const mockRefetchDevices = jest.fn(); const mockRefetchData = jest.fn(); mockUseDevices.mockReturnValue({ devices: [], loading: false, error: '디바이스 목록을 불러올 수 없습니다.', refetch: mockRefetchDevices }); mockUseSensorData.mockReturnValue({ latestData: [], loading: false, error: '센서 데이터를 불러올 수 없습니다.', refetch: mockRefetchData }); renderWithRouter(); const retryButton = screen.getByText('다시 시도'); retryButton.click(); expect(mockRefetchDevices).toHaveBeenCalled(); expect(mockRefetchData).toHaveBeenCalled(); }); });