fix: finish all patient related upgrades
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import EncounterTimeline from '@/components/patient/EncounterTimeline.vue'
|
||||
|
||||
const events = [
|
||||
{
|
||||
type: 'observation',
|
||||
timestamp: '2026-06-23T10:00:00Z',
|
||||
observationCode: 'TEMP_C',
|
||||
value: 38.8,
|
||||
unit: 'C',
|
||||
},
|
||||
{
|
||||
type: 'alert',
|
||||
timestamp: '2026-06-23T11:00:00Z',
|
||||
alertType: 'QsofaScreen',
|
||||
severity: 'Warning',
|
||||
status: 'Open',
|
||||
},
|
||||
{
|
||||
type: 'medication',
|
||||
timestamp: '2026-06-23T12:00:00Z',
|
||||
drugName: 'Ceftriaxone',
|
||||
dose: 1,
|
||||
doseUnit: 'g',
|
||||
route: 'IV',
|
||||
},
|
||||
]
|
||||
|
||||
describe('EncounterTimeline', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date('2026-06-23T14:00:00Z'))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('rendersEvents', () => {
|
||||
const wrapper = mount(EncounterTimeline, { props: { events } })
|
||||
expect(wrapper.text()).toContain('Encounter Timeline')
|
||||
expect(wrapper.text()).toContain('Ceftriaxone')
|
||||
expect(wrapper.text()).toContain('qSOFA Screen')
|
||||
})
|
||||
|
||||
it('filtersByEventType', async () => {
|
||||
const wrapper = mount(EncounterTimeline, { props: { events } })
|
||||
const medToggle = wrapper.findAll('button').find(b => b.text() === 'Medications')
|
||||
await medToggle.trigger('click')
|
||||
expect(wrapper.text()).not.toContain('Ceftriaxone')
|
||||
expect(wrapper.text()).toContain('Temperature')
|
||||
})
|
||||
|
||||
it('collapsesWhenHeaderClicked', async () => {
|
||||
const wrapper = mount(EncounterTimeline, { props: { events } })
|
||||
await wrapper.find('button').trigger('click')
|
||||
expect(wrapper.text()).not.toContain('Ceftriaxone')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PatientBanner from '@/components/patient/PatientBanner.vue'
|
||||
|
||||
const encounter = {
|
||||
roomBed: 'ICU-3C',
|
||||
department: 'Icu',
|
||||
attendingPhysician: 'Dr. Smith',
|
||||
admissionReason: 'Sepsis workup',
|
||||
patient: {
|
||||
mrn: 'MRN-000123',
|
||||
firstName: 'Jane',
|
||||
lastName: 'Doe',
|
||||
dateOfBirth: '1985-03-20',
|
||||
gender: 'F',
|
||||
bloodType: 'AbNegative',
|
||||
allergies: 'Penicillin, Latex',
|
||||
emergencyContactName: 'John Doe',
|
||||
emergencyContactPhone: '555-0100',
|
||||
},
|
||||
}
|
||||
|
||||
describe('PatientBanner', () => {
|
||||
it('showsDemographicsAndEncounterFields', () => {
|
||||
const wrapper = mount(PatientBanner, { props: { encounter } })
|
||||
expect(wrapper.text()).toContain('Jane Doe')
|
||||
expect(wrapper.text()).toContain('MRN-000123')
|
||||
expect(wrapper.text()).toContain('AB-')
|
||||
expect(wrapper.text()).toContain('ICU')
|
||||
expect(wrapper.text()).toContain('ICU-3C')
|
||||
expect(wrapper.text()).toContain('Dr. Smith')
|
||||
expect(wrapper.text()).toContain('Sepsis workup')
|
||||
expect(wrapper.text()).toContain('John Doe')
|
||||
})
|
||||
|
||||
it('highlightsKnownAllergies', () => {
|
||||
const wrapper = mount(PatientBanner, { props: { encounter } })
|
||||
expect(wrapper.text()).toContain('Penicillin, Latex')
|
||||
const strip = wrapper.find('[role="status"]')
|
||||
expect(strip.classes().join(' ')).toMatch(/bg-red-600/)
|
||||
})
|
||||
|
||||
it('showsNkdaWhenNoAllergies', () => {
|
||||
const wrapper = mount(PatientBanner, {
|
||||
props: {
|
||||
encounter: {
|
||||
...encounter,
|
||||
patient: { ...encounter.patient, allergies: null },
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(wrapper.text()).toContain('NKDA')
|
||||
const strip = wrapper.find('[role="status"]')
|
||||
expect(strip.classes().join(' ')).not.toMatch(/bg-red-600/)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,57 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
filterMedicationsForWindow,
|
||||
formatMedicationTooltip,
|
||||
getMedicationsNearTimestamp,
|
||||
xPixelForMedicationTime,
|
||||
} from '@/composables/chartMedications'
|
||||
|
||||
const observations = [
|
||||
{ observationCode: 'HEART_RATE', value: 72, recordedAt: '2026-06-19T11:00:00Z' },
|
||||
{ observationCode: 'HEART_RATE', value: 80, recordedAt: '2026-06-19T13:00:00Z' },
|
||||
{ observationCode: 'RESP_RATE', value: 18, recordedAt: '2026-06-19T12:00:00Z' },
|
||||
]
|
||||
|
||||
const medications = [
|
||||
{
|
||||
id: '1',
|
||||
drugName: 'Metoprolol',
|
||||
dose: 5,
|
||||
doseUnit: 'mg',
|
||||
route: 'IV',
|
||||
administeredAt: '2026-06-19T12:30:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
drugName: 'Saline',
|
||||
dose: 500,
|
||||
doseUnit: 'mL',
|
||||
route: 'IV',
|
||||
administeredAt: '2026-06-19T10:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
describe('chartMedications', () => {
|
||||
it('filtersMedicationsToObservationWindow', () => {
|
||||
const result = filterMedicationsForWindow(observations, 'HEART_RATE', medications)
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].drugName).toBe('Metoprolol')
|
||||
})
|
||||
|
||||
it('formatsMedicationTooltip', () => {
|
||||
expect(formatMedicationTooltip(medications[0])).toContain('Metoprolol 5mg (IV)')
|
||||
})
|
||||
|
||||
it('findsMedicationsNearTimestamp', () => {
|
||||
const target = new Date('2026-06-19T12:35:00Z').getTime()
|
||||
const near = getMedicationsNearTimestamp(medications, target, 10 * 60 * 1000)
|
||||
expect(near).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('mapsMedicationTimeToChartPixel', () => {
|
||||
const chartArea = { left: 10, right: 110, top: 0, bottom: 100, width: 100, height: 100 }
|
||||
const timestamps = ['2026-06-19T11:00:00Z', '2026-06-19T13:00:00Z']
|
||||
const x = xPixelForMedicationTime('2026-06-19T12:00:00Z', timestamps, chartArea)
|
||||
expect(x).toBe(60)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
computeAge,
|
||||
formatAllergiesDisplay,
|
||||
formatBloodType,
|
||||
formatDepartment,
|
||||
formatDobWithAge,
|
||||
hasKnownAllergies,
|
||||
} from '@/composables/patientFormat'
|
||||
|
||||
describe('patientFormat', () => {
|
||||
it('computesAgeFromDob', () => {
|
||||
expect(computeAge('1990-06-15', new Date('2026-06-23'))).toBe(36)
|
||||
})
|
||||
|
||||
it('formatsBloodType', () => {
|
||||
expect(formatBloodType('AbNegative')).toBe('AB-')
|
||||
expect(formatBloodType('AB-')).toBe('AB-')
|
||||
})
|
||||
|
||||
it('formatsDepartment', () => {
|
||||
expect(formatDepartment('Icu')).toBe('ICU')
|
||||
expect(formatDepartment('GENERAL_MEDICINE')).toBe('General Medicine')
|
||||
})
|
||||
|
||||
it('showsNkdaWhenNoAllergies', () => {
|
||||
expect(hasKnownAllergies('')).toBe(false)
|
||||
expect(hasKnownAllergies(null)).toBe(false)
|
||||
expect(formatAllergiesDisplay('')).toBe('NKDA')
|
||||
expect(formatAllergiesDisplay(' Penicillin ')).toBe('Penicillin')
|
||||
})
|
||||
|
||||
it('formatsDobWithAge', () => {
|
||||
const text = formatDobWithAge('1990-06-15')
|
||||
expect(text).toContain('1990')
|
||||
expect(text).toMatch(/\(\d+y\)/)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import {
|
||||
formatTimelineEvent,
|
||||
timelineTypeLabel,
|
||||
TIMELINE_EVENT_TYPES,
|
||||
} from '@/composables/timelineFormat'
|
||||
|
||||
describe('timelineFormat', () => {
|
||||
it('formatsObservationEvent', () => {
|
||||
const text = formatTimelineEvent({
|
||||
type: 'observation',
|
||||
observationCode: 'HEART_RATE',
|
||||
value: 110,
|
||||
unit: 'bpm',
|
||||
})
|
||||
expect(text).toContain('Heart Rate')
|
||||
expect(text).toContain('110')
|
||||
})
|
||||
|
||||
it('formatsMedicationEvent', () => {
|
||||
const text = formatTimelineEvent({
|
||||
type: 'medication',
|
||||
drugName: 'Metoprolol',
|
||||
dose: 5,
|
||||
doseUnit: 'mg',
|
||||
route: 'IV',
|
||||
})
|
||||
expect(text).toBe('Metoprolol 5mg (IV)')
|
||||
})
|
||||
|
||||
it('listsAllEventTypes', () => {
|
||||
expect(TIMELINE_EVENT_TYPES.map(t => t.id)).toEqual([
|
||||
'observation',
|
||||
'alert',
|
||||
'order',
|
||||
'medication',
|
||||
'status',
|
||||
])
|
||||
expect(timelineTypeLabel('order')).toBe('Orders')
|
||||
})
|
||||
})
|
||||
@@ -26,6 +26,10 @@ describe('useChartData', () => {
|
||||
const { chartData } = mountChartData(observations, 'HEART_RATE')
|
||||
expect(chartData.value.datasets[0].data).toEqual([72, 80])
|
||||
expect(chartData.value.labels).toHaveLength(2)
|
||||
expect(chartData.value.timestamps).toEqual([
|
||||
'2026-06-19T11:00:00Z',
|
||||
'2026-06-19T12:00:00Z',
|
||||
])
|
||||
})
|
||||
|
||||
it('sortsChronologically', () => {
|
||||
|
||||
Reference in New Issue
Block a user