// #region MaintenanceComponentTests [C:2] [TYPE Module] [SEMANTICS test, component, maintenance, events-table, badge] // @BRIEF Component tests for MaintenanceEventsTable and DashboardMaintenanceBadge. // @RELATION DEPENDS_ON -> [EXT:frontend:MaintenanceEventsTable] // @RELATION DEPENDS_ON -> [EXT:frontend:DashboardMaintenanceBadge] import { describe, it, expect, vi, beforeEach } from 'vitest'; // Create mutable mock data using vi.hoisted const { mockStoreState, mockStore } = vi.hoisted(() => { const sharedState = { activeEvents: [], completedEvents: [], settings: null, dashboardBanners: [], isLoading: false, error: null, }; const store = { get activeEvents() { return sharedState.activeEvents; }, get completedEvents() { return sharedState.completedEvents; }, get settings() { return sharedState.settings; }, get dashboardBanners() { return sharedState.dashboardBanners; }, get isLoading() { return sharedState.isLoading; }, get error() { return sharedState.error; }, loadEvents: vi.fn(), loadSettings: vi.fn(), loadDashboardBanners: vi.fn(), endEvent: vi.fn(), endAllEvents: vi.fn(), updateSettings: vi.fn(), init: vi.fn(), startPolling: vi.fn(), stopPolling: vi.fn(), }; return { mockStoreState: sharedState, mockStore: store }; }); function resetMockStore() { mockStoreState.activeEvents = []; mockStoreState.completedEvents = []; mockStoreState.settings = null; mockStoreState.dashboardBanners = []; mockStoreState.isLoading = false; mockStoreState.error = null; } // Mock toasts vi.mock('$lib/toasts.js', () => ({ addToast: vi.fn() })); // Mock i18n — $t is a derived store, needs subscribe method for Svelte $ prefix vi.mock('$lib/i18n', () => { const subscribers = new Set(); const tData = { maintenance: { active_events: 'Active Events', completed_events: 'Completed Events', no_active_events: 'No active maintenance events', no_completed_events: 'No completed maintenance events', remove_banners: 'Remove', remove_all: 'Remove All', maintenance_badge: 'Maintenance', maintenance_tooltip: 'Maintenance active: {start} — {end}', event_id: 'Event ID', tables: 'Tables', affected_dashboards: 'Dashboards', start_time: 'Start Time', end_time: 'End Time', status: 'Status', actions: 'Actions', }, common: {} }; return { t: { subscribe(run) { subscribers.add(run); run(tData); return () => subscribers.delete(run); } }, _: (key) => key, }; }); vi.mock('$lib/stores/maintenance.svelte.js', () => ({ maintenanceStore: mockStore, createMaintenanceStore: () => mockStore, })); // Mock the API module vi.mock('$lib/api.js', () => ({ api: { getEnvironments: vi.fn(() => Promise.resolve([])), getDashboards: vi.fn(() => Promise.resolve({ dashboards: [] })), }, requestApi: vi.fn(), })); // Mock $app/navigation vi.mock('$app/navigation', () => ({ goto: vi.fn(), })); // Mock $app/stores vi.mock('$app/stores', () => ({ page: { subscribe: vi.fn() }, navigating: { subscribe: vi.fn() }, updated: { subscribe: vi.fn() }, })); import { render, screen } from '@testing-library/svelte'; import MaintenanceEventsTable from '$lib/components/MaintenanceEventsTable.svelte'; import DashboardMaintenanceBadge from '$lib/components/DashboardMaintenanceBadge.svelte'; describe('MaintenanceEventsTable', () => { beforeEach(() => { vi.clearAllMocks(); resetMockStore(); }); it('renders empty state when no active events', async () => { mockStoreState.activeEvents = []; mockStoreState.completedEvents = []; render(MaintenanceEventsTable); expect(screen.getByText('No active maintenance events')).toBeTruthy(); }); it('renders active events in the table', async () => { mockStoreState.activeEvents = [ { id: 'ev-1', tables: ['raw.sales'], affected_count: 3, start_time: '2026-05-21T22:00:00Z', end_time: null, status: 'active' } ]; mockStoreState.completedEvents = []; render(MaintenanceEventsTable); expect(screen.getByText('ev-1')).toBeTruthy(); }); it('renders Remove All button when events exist', async () => { mockStoreState.activeEvents = [ { id: 'ev-1', tables: ['raw.sales'], affected_count: 3, start_time: '2026-05-21T22:00:00Z', end_time: null, status: 'active' } ]; mockStoreState.completedEvents = []; render(MaintenanceEventsTable); expect(screen.getByText('Remove All')).toBeTruthy(); }); }); describe('DashboardMaintenanceBadge', () => { beforeEach(() => { vi.clearAllMocks(); resetMockStore(); }); it('renders nothing when no banner state for dashboard', async () => { mockStoreState.dashboardBanners = []; const { container } = render(DashboardMaintenanceBadge, { props: { dashboardId: 42 } }); const badgeElements = container.querySelectorAll('.bg-orange-100'); expect(badgeElements.length).toBe(0); }); it('renders badge when banner is active for dashboard', async () => { mockStoreState.dashboardBanners = [ { dashboard_id: 42, active: true, events: ['ev-1'], start_time: '2026-05-21T22:00:00Z', end_time: null } ]; const { container } = render(DashboardMaintenanceBadge, { props: { dashboardId: 42 } }); const badge = container.querySelector('.bg-orange-100'); expect(badge).toBeTruthy(); expect(badge?.textContent).toContain('Maintenance'); }); it('renders nothing when banner exists but not active for this dashboard', async () => { mockStoreState.dashboardBanners = [ { dashboard_id: 57, active: true, events: ['ev-1'], start_time: '2026-05-21T22:00:00Z', end_time: null } ]; const { container } = render(DashboardMaintenanceBadge, { props: { dashboardId: 42 } }); const badge = container.querySelector('.bg-orange-100'); expect(badge).toBeNull(); }); }); // #endregion MaintenanceComponentTests