Skip to main content
Glama
encounter.test.ts6.5 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { HTTP_HL7_ORG } from '@medplum/core'; import type { Coding, Encounter, Patient, PlanDefinition, Practitioner, Appointment, Task } from '@medplum/fhirtypes'; import { MockClient } from '@medplum/mock'; import { describe, expect, test, beforeEach, vi } from 'vitest'; import { createEncounter, updateEncounterStatus } from './encounter'; describe('encounter utils', () => { let medplum: MockClient; let practitioner: Practitioner; let patient: Patient; let classification: Coding; beforeEach(() => { medplum = new MockClient(); practitioner = { resourceType: 'Practitioner', id: 'prac-1', name: [{ given: ['Demo'], family: 'Doctor' }], }; patient = { resourceType: 'Patient', id: 'patient-1', name: [{ given: ['Pat'], family: 'Smith' }] }; classification = { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'AMB' }; vi.spyOn(medplum, 'getProfile').mockReturnValue(practitioner); }); describe('createEncounter', () => { test('creates encounter and related resources', async () => { // Capture createResource calls and respond with deterministic IDs const createResourceSpy = vi.spyOn(medplum, 'createResource').mockImplementation(async (resource: any) => { if (resource.resourceType === 'Appointment') { return { ...resource, id: 'appt-1' }; } if (resource.resourceType === 'Encounter') { return { ...resource, id: 'enc-1' }; } if (resource.resourceType === 'ChargeItem') { return { ...resource, id: `charge-${Math.random()}` }; } return { ...resource }; }); const postSpy = vi.spyOn(medplum, 'post').mockResolvedValue({}); const searchSpy = vi.spyOn(medplum, 'search').mockResolvedValue({ entry: [ { resource: { resourceType: 'Task', focus: { reference: 'ServiceRequest/sr-1' }, } as Task, }, ], } as any); vi.spyOn(medplum, 'searchResources').mockResolvedValue([] as any); const readReferenceSpy = vi.spyOn(medplum, 'readReference').mockResolvedValue({ resourceType: 'ServiceRequest', id: 'sr-1', encounter: { reference: 'Encounter/enc-1' }, code: { coding: [{ system: 'http://www.ama-assn.org/go/cpt', code: '1234' }] }, occurrenceDateTime: '2020-01-01T12:00:00Z', extension: [ { url: 'http://medplum.com/fhir/StructureDefinition/applicable-charge-definition', valueCanonical: 'ChargeItemDefinition/1', }, ], } as any); const planDefinition: PlanDefinition = { resourceType: 'PlanDefinition', id: 'plan-1', extension: [ { url: `${HTTP_HL7_ORG}/fhir/uv/order-catalog/StructureDefinition/ServiceBillingCode`, valueCodeableConcept: { coding: [{ system: 'http://www.ama-assn.org/go/cpt', code: '99202', display: 'Office visit' }], }, }, { url: 'http://medplum.com/fhir/StructureDefinition/applicable-charge-definition', valueCanonical: 'ChargeItemDefinition/plan', }, ], status: 'active', }; const encounter = await createEncounter( medplum as any, new Date('2020-01-01T10:00:00Z'), new Date('2020-01-01T10:30:00Z'), classification, patient, planDefinition ); expect(encounter.status).toBe('planned'); expect(encounter.id).toBe('enc-1'); expect(createResourceSpy).toHaveBeenCalledWith(expect.objectContaining({ resourceType: 'Appointment' })); expect(postSpy).toHaveBeenCalled(); expect(searchSpy).toHaveBeenCalledWith('Task', expect.objectContaining({ encounter: 'Encounter/enc-1' })); expect(readReferenceSpy).toHaveBeenCalledWith({ reference: 'ServiceRequest/sr-1' }); // Ensure a ChargeItem was attempted from service request expect( createResourceSpy.mock.calls.some(([resource]) => resource.resourceType === 'ChargeItem' && resource.code) ).toBe(true); }); }); describe('updateEncounterStatus', () => { test('updates encounter period and appointment status', async () => { const encounter: Encounter = { resourceType: 'Encounter', id: 'enc-1', status: 'planned', class: classification, }; const appointment: Appointment = { resourceType: 'Appointment', id: 'appt-1', status: 'booked', participant: [ { actor: { reference: 'Practitioner/prac-1' }, status: 'accepted', }, ], }; const updateSpy = vi.spyOn(medplum, 'updateResource').mockImplementation(async (resource) => resource as any); const updatedEncounter = await updateEncounterStatus(medplum as any, encounter, appointment, 'in-progress'); expect(updateSpy).toHaveBeenCalledWith( expect.objectContaining({ resourceType: 'Appointment', status: 'checked-in' }) ); expect(updateSpy).toHaveBeenCalledWith( expect.objectContaining({ resourceType: 'Encounter', status: 'in-progress' }) ); expect(updatedEncounter.period?.start).toBeDefined(); // Move to finished state await updateEncounterStatus(medplum as any, updatedEncounter, appointment, 'finished'); expect(updateSpy).toHaveBeenCalledWith(expect.objectContaining({ status: 'fulfilled' })); }); test('updates appointment status for cancellation', async () => { const encounter: Encounter = { resourceType: 'Encounter', id: 'enc-2', status: 'in-progress', class: classification, }; const appointment: Appointment = { resourceType: 'Appointment', id: 'appt-2', status: 'booked', participant: [ { actor: { reference: 'Practitioner/prac-1' }, status: 'accepted', }, ], }; const updateSpy = vi.spyOn(medplum, 'updateResource').mockImplementation(async (resource) => resource as any); await updateEncounterStatus(medplum as any, encounter, appointment, 'cancelled'); expect(updateSpy).toHaveBeenCalledWith(expect.objectContaining({ status: 'cancelled' })); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server