import { describe, it, expect, beforeEach, vi } from 'vitest' import { mount } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import SimulationControlView from '@/views/SimulationControlView.vue' const { fetchScenarios, fetchSessions, fetchRuns, fetchSimulationConfig, fetchDataSummary, startRun, startSession, stopRun, purgeData, } = vi.hoisted(() => ({ fetchScenarios: vi.fn(), fetchSessions: vi.fn(), fetchRuns: vi.fn(), fetchSimulationConfig: vi.fn(), fetchDataSummary: vi.fn(), startRun: vi.fn(), startSession: vi.fn(), stopRun: vi.fn(), purgeData: vi.fn(), })) vi.mock('@/api/simulation', () => ({ fetchScenarios, fetchSessions, fetchRuns, fetchSimulationConfig, fetchDataSummary, startRun, startSession, stopRun, purgeData, fetchRun: vi.fn(), })) vi.mock('@/stores/ward', () => ({ useWardStore: () => ({ loadEncounters: vi.fn() }), })) vi.mock('@/stores/alerts', () => ({ useAlertStore: () => ({ loadGlobalAlerts: vi.fn() }), })) const scenarios = [ { id: 'uti-sepsis-elderly-01', name: 'UTI Sepsis Elderly', description: 'Elderly patient with UTI progressing to sepsis.', durationMinutes: 480, tags: ['sepsis', 'uti'], department: 'GeneralMedicine', eventCount: 200, }, { id: 'stable-baseline-01', name: 'Stable Baseline', description: 'Control scenario.', durationMinutes: 480, tags: ['control', 'stable'], department: 'Surgery', eventCount: 312, }, ] const sessions = [ { id: 'session-a-orientation', name: 'Session A — Quick orientation', goal: 'Learn the interface.', estimatedMinutes: 25, defaultSpeed: 60, scenarios: [ { id: 'stable-baseline-01', name: 'Stable Baseline' }, { id: 'uti-sepsis-elderly-01', name: 'UTI Sepsis Elderly' }, ], }, ] describe('SimulationControlView', () => { beforeEach(() => { vi.clearAllMocks() setActivePinia(createPinia()) fetchScenarios.mockResolvedValue(scenarios) fetchSessions.mockResolvedValue(sessions) fetchRuns.mockResolvedValue([]) fetchDataSummary.mockResolvedValue({ simulatedPatients: 0, encounters: 0, observations: 0, alerts: 0, activeRuns: 0, }) fetchSimulationConfig.mockResolvedValue({ enabled: true, maxSpeed: 600, maxConcurrentRuns: 2, }) }) it('defaultsToSessionsTab', async () => { const wrapper = mount(SimulationControlView) await vi.waitFor(() => expect(wrapper.text()).toContain('Session A — Quick orientation')) expect(wrapper.text()).toContain('Testing sessions') expect(wrapper.text()).not.toContain('Scenario catalogue') }) it('switchesToScenariosTab', async () => { const wrapper = mount(SimulationControlView) await vi.waitFor(() => expect(wrapper.text()).toContain('Session A')) const scenariosTab = wrapper.findAll('button').find(b => b.text() === 'Scenarios') await scenariosTab.trigger('click') await vi.waitFor(() => expect(wrapper.text()).toContain('Scenario catalogue')) expect(wrapper.text()).toContain('UTI Sepsis Elderly') }) it('showsWallClockDurationForSelectedScenarioSpeed', async () => { const wrapper = mount(SimulationControlView) await vi.waitFor(() => expect(wrapper.text()).toContain('Session A')) const scenariosTab = wrapper.findAll('button').find(b => b.text() === 'Scenarios') await scenariosTab.trigger('click') await vi.waitFor(() => expect(wrapper.text()).toContain('UTI Sepsis Elderly')) // Default Fast (60×): 480 sim minutes → 8 wall-clock minutes expect(wrapper.text()).toMatch(/8 minutes for selected scenario/) const realTime = wrapper.findAll('button').find(b => b.text().includes('Real time')) expect(realTime.text()).toMatch(/8 hours for selected scenario/) const instant = wrapper.findAll('button').find(b => b.text().includes('Instant')) expect(instant.text()).toMatch(/1 minute for selected scenario/) }) it('filtersCatalogueByTag', async () => { const wrapper = mount(SimulationControlView) await vi.waitFor(() => expect(wrapper.text()).toContain('Session A')) const scenariosTab = wrapper.findAll('button').find(b => b.text() === 'Scenarios') await scenariosTab.trigger('click') await vi.waitFor(() => expect(wrapper.text()).toContain('Stable Baseline')) const sepsisChip = wrapper.findAll('button').find(b => b.text() === 'sepsis') await sepsisChip.trigger('click') expect(wrapper.text()).toContain('UTI Sepsis Elderly') expect(wrapper.text()).not.toContain('Stable Baseline') }) it('showsEmptyStateWhenCatalogueMissing', async () => { fetchScenarios.mockResolvedValue([]) const wrapper = mount(SimulationControlView) await vi.waitFor(() => expect(wrapper.text()).toContain('Session A')) const scenariosTab = wrapper.findAll('button').find(b => b.text() === 'Scenarios') await scenariosTab.trigger('click') await vi.waitFor(() => expect(wrapper.text()).toContain('Simulation:ScenarioDirectory'), ) }) })