feature: Degraded Operations Visibility
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import DischargeSummaryPanel from '@/components/patient/DischargeSummaryPanel.vue'
|
||||
|
||||
vi.mock('@/api/encounters', () => ({
|
||||
fetchDischargeSummaryStatus: vi.fn(() => Promise.resolve({
|
||||
status: 'Ready',
|
||||
dischargedAt: '2026-06-23T10:00:00Z',
|
||||
})),
|
||||
fetchDischargeSummaryContent: vi.fn(() => Promise.resolve('DISCHARGE SUMMARY\nPatient: Jane Doe')),
|
||||
}))
|
||||
|
||||
describe('DischargeSummaryPanel', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('rendersSummaryWhenDischarged', async () => {
|
||||
const wrapper = mount(DischargeSummaryPanel, {
|
||||
props: {
|
||||
encounterId: 'enc-1',
|
||||
discharged: true,
|
||||
},
|
||||
})
|
||||
|
||||
await vi.waitFor(() => expect(wrapper.text()).toContain('DISCHARGE SUMMARY'))
|
||||
expect(wrapper.text()).toContain('Download')
|
||||
})
|
||||
|
||||
it('hidesWhenNotDischarged', () => {
|
||||
const wrapper = mount(DischargeSummaryPanel, {
|
||||
props: {
|
||||
encounterId: 'enc-1',
|
||||
discharged: false,
|
||||
},
|
||||
})
|
||||
expect(wrapper.text()).toBe('')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { mount, flushPromises } from '@vue/test-utils'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import GatewayOperations from '@/views/GatewayOperations.vue'
|
||||
|
||||
vi.mock('@/api/operations', () => ({
|
||||
fetchGatewayFleet: vi.fn(),
|
||||
fetchGatewayDetail: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/composables/usePolling', () => ({
|
||||
usePolling: (fn) => { fn(); return {} },
|
||||
}))
|
||||
|
||||
import { fetchGatewayFleet } from '@/api/operations'
|
||||
|
||||
describe('GatewayOperations', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
fetchGatewayFleet.mockResolvedValue([
|
||||
{
|
||||
id: 'gw-1',
|
||||
gatewayCode: 'GW-ICU-3B',
|
||||
department: 'ICU',
|
||||
siteName: 'Demo Hospital',
|
||||
status: 'DEGRADED',
|
||||
reportedBufferDepth: 847,
|
||||
minutesSinceHeartbeat: 12,
|
||||
lastSyncAt: null,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('rendersFleetTableWithDegradedBadge', async () => {
|
||||
const wrapper = mount(GatewayOperations)
|
||||
await flushPromises()
|
||||
expect(wrapper.text()).toContain('GW-ICU-3B')
|
||||
expect(wrapper.text()).toContain('DEGRADED')
|
||||
expect(wrapper.text()).toContain('847')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import ThresholdManagementView from '@/views/ThresholdManagementView.vue'
|
||||
|
||||
vi.mock('@/api/thresholds', () => ({
|
||||
fetchThresholds: vi.fn(() => Promise.resolve([
|
||||
{
|
||||
id: 'thr-1',
|
||||
observationCode: 'HEART_RATE',
|
||||
displayName: 'Heart Rate',
|
||||
unit: 'bpm',
|
||||
criticalLow: 30,
|
||||
warningLow: 50,
|
||||
warningHigh: 100,
|
||||
criticalHigh: 150,
|
||||
},
|
||||
])),
|
||||
createThreshold: vi.fn(),
|
||||
updateThreshold: vi.fn(),
|
||||
deleteThreshold: vi.fn(),
|
||||
}))
|
||||
|
||||
describe('ThresholdManagementView', () => {
|
||||
it('rendersThresholdTable', async () => {
|
||||
setActivePinia(createPinia())
|
||||
const wrapper = mount(ThresholdManagementView)
|
||||
await vi.waitFor(() => expect(wrapper.text()).toContain('HEART_RATE'))
|
||||
expect(wrapper.text()).toContain('Alert Thresholds')
|
||||
expect(wrapper.text()).toContain('Create Threshold')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { canAccessOps, filterNavLinks, isDashboardRole, roleCanAccessRoute, MAIN_NAV_LINKS } from '@/composables/roleAccess'
|
||||
|
||||
describe('roleAccess', () => {
|
||||
it('filtersNavLinksByRole', () => {
|
||||
const nurseLinks = filterNavLinks(MAIN_NAV_LINKS, 'NURSE')
|
||||
expect(nurseLinks.some((l) => l.to === '/feedback')).toBe(false)
|
||||
expect(nurseLinks.some((l) => l.to === '/alerts')).toBe(true)
|
||||
|
||||
const physicianLinks = filterNavLinks(MAIN_NAV_LINKS, 'PHYSICIAN')
|
||||
expect(physicianLinks.some((l) => l.to === '/feedback')).toBe(true)
|
||||
})
|
||||
|
||||
it('rejectsIntegrationDashboardRole', () => {
|
||||
expect(isDashboardRole('INTEGRATION')).toBe(false)
|
||||
expect(isDashboardRole('NURSE')).toBe(true)
|
||||
})
|
||||
|
||||
it('guardsRoutesByAllowedRoles', () => {
|
||||
expect(roleCanAccessRoute('NURSE', { allowedRoles: ['PHYSICIAN', 'ADMIN'] })).toBe(false)
|
||||
expect(roleCanAccessRoute('ADMIN', { allowedRoles: ['ADMIN'] })).toBe(true)
|
||||
expect(roleCanAccessRoute('INTEGRATION', { allowedRoles: ['NURSE'] })).toBe(false)
|
||||
})
|
||||
|
||||
it('restrictsOpsAccessToAdminByDefault', () => {
|
||||
expect(canAccessOps('ADMIN')).toBe(true)
|
||||
expect(canAccessOps('NURSE')).toBe(false)
|
||||
expect(canAccessOps('PHYSICIAN')).toBe(false)
|
||||
expect(canAccessOps('INTEGRATION')).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
emptyThresholdForm,
|
||||
thresholdFormToPayload,
|
||||
validateThresholdForm,
|
||||
} from '@/composables/thresholdForm'
|
||||
|
||||
describe('thresholdForm', () => {
|
||||
it('validatesRequiredFields', () => {
|
||||
const result = validateThresholdForm(emptyThresholdForm())
|
||||
expect(result.valid).toBe(false)
|
||||
expect(result.errors.observationCode).toBeTruthy()
|
||||
})
|
||||
|
||||
it('validatesThresholdOrdering', () => {
|
||||
const result = validateThresholdForm({
|
||||
observationCode: 'HEART_RATE',
|
||||
displayName: 'Heart Rate',
|
||||
unit: 'bpm',
|
||||
criticalLow: '60',
|
||||
warningLow: '50',
|
||||
warningHigh: '100',
|
||||
criticalHigh: '130',
|
||||
})
|
||||
expect(result.valid).toBe(false)
|
||||
expect(result.errors.warningLow).toBeTruthy()
|
||||
})
|
||||
|
||||
it('buildsPayloadWithNullBounds', () => {
|
||||
const payload = thresholdFormToPayload({
|
||||
observationCode: 'SPO2',
|
||||
displayName: 'SpO₂',
|
||||
unit: '%',
|
||||
criticalLow: '',
|
||||
warningLow: '92',
|
||||
warningHigh: '',
|
||||
criticalHigh: '88',
|
||||
})
|
||||
expect(payload).toEqual({
|
||||
observationCode: 'SPO2',
|
||||
displayName: 'SpO₂',
|
||||
unit: '%',
|
||||
criticalLow: null,
|
||||
warningLow: 92,
|
||||
warningHigh: null,
|
||||
criticalHigh: 88,
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user