169 lines
5.0 KiB
JavaScript
169 lines
5.0 KiB
JavaScript
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'),
|
||
)
|
||
})
|
||
})
|