Skip to main content
Glama
intake-utils.test.ts8.37 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import type { Coding, Patient, Questionnaire, QuestionnaireResponse, QuestionnaireResponseItemAnswer, Reference, Organization, } from '@medplum/fhirtypes'; import { MockClient } from '@medplum/mock'; import { describe, expect, test, beforeEach, vi } from 'vitest'; import { addAllergy, addConsent, addCoverage, addExtension, addLanguage, convertDateToDateTime, findQuestionnaireItem, getGroupRepeatedAnswers, getHumanName, getPatientAddress, observationCategoryMapping, observationCodeMapping, upsertObservation, } from './intake-utils'; describe('intake utils', () => { let medplum: MockClient; let patient: Patient; beforeEach(() => { medplum = new MockClient(); patient = { resourceType: 'Patient', id: 'patient-1' }; }); describe('addExtension', () => { test('adds coded extension with sub extension text', () => { const answer: QuestionnaireResponseItemAnswer = { valueCoding: { system: 'http://example.com', code: 'code', display: 'Display' }, }; addExtension(patient, 'http://example.com/ext', 'valueCoding', answer, 'ombCategory'); expect(patient.extension).toEqual([ { url: 'http://example.com/ext', extension: [ { url: 'ombCategory', valueCoding: { system: 'http://example.com', code: 'code', display: 'Display' }, }, { url: 'text', valueString: 'Display', }, ], }, ]); }); test('adds boolean extension and interprets undefined as false', () => { addExtension(patient, 'http://example.com/bool', 'valueBoolean', {}); expect(patient.extension).toEqual([ expect.objectContaining({ url: 'http://example.com/bool', valueBoolean: false, }), ]); }); }); describe('addLanguage', () => { test('adds and updates preferred language', () => { const coding: Coding = { system: 'urn:ietf:bcp:47', code: 'en', display: 'English' }; addLanguage(patient, coding); addLanguage(patient, coding, true); expect(patient.communication).toHaveLength(1); expect(patient.communication?.[0].preferred).toBe(true); }); }); describe('questionnaire helpers', () => { test('getHumanName builds full name', () => { const answers: Record<string, QuestionnaireResponseItemAnswer> = { 'first-name': { valueString: 'Ada' }, 'middle-name': { valueString: 'M.' }, 'last-name': { valueString: 'Lovelace' }, }; expect(getHumanName(answers)).toEqual({ given: ['Ada', 'M.'], family: 'Lovelace' }); }); test('getPatientAddress builds address', () => { const answers: Record<string, QuestionnaireResponseItemAnswer> = { street: { valueString: '1 Main St' }, city: { valueString: 'Springfield' }, state: { valueCoding: { code: 'CA' } }, zip: { valueString: '12345' }, }; expect(getPatientAddress(answers)).toEqual( expect.objectContaining({ city: 'Springfield', state: 'CA', postalCode: '12345', use: 'home' }) ); }); test('findQuestionnaireItem finds nested item', () => { const questionnaire: Questionnaire = { resourceType: 'Questionnaire', item: [ { linkId: 'group', type: 'group', item: [{ linkId: 'nested', type: 'string' }], }, ], status: 'active', }; const result = findQuestionnaireItem(questionnaire.item, 'nested'); expect(result?.linkId).toBe('nested'); }); test('getGroupRepeatedAnswers flattens repeating groups', () => { const questionnaire: Questionnaire = { status: 'active', resourceType: 'Questionnaire', item: [{ linkId: 'allergies', type: 'group', item: [{ linkId: 'allergy-substance', type: 'string' }] }], }; const response: QuestionnaireResponse = { status: 'completed', resourceType: 'QuestionnaireResponse', item: [ { linkId: 'allergies', item: [{ linkId: 'allergy-substance', answer: [{ valueString: 'Peanuts' }] }], }, { linkId: 'allergies', item: [{ linkId: 'allergy-substance', answer: [{ valueString: 'Shellfish' }] }], }, ], }; const answers = getGroupRepeatedAnswers(questionnaire, response, 'allergies'); expect(answers).toEqual([ { 'allergy-substance': { valueString: 'Peanuts' } }, { 'allergy-substance': { valueString: 'Shellfish' } }, ]); }); }); describe('convertDateToDateTime', () => { test('converts date to ISO string', () => { expect(convertDateToDateTime('2020-01-01')).toContain('2020-01-01T00:00:00'); expect(convertDateToDateTime(undefined)).toBeUndefined(); }); }); describe('upsertObservation', () => { test('upserts codeable concept observation', async () => { const upsertSpy = vi.spyOn(medplum, 'upsertResource').mockResolvedValue({} as any); await upsertObservation( medplum as any, patient, observationCodeMapping.smokingStatus, observationCategoryMapping.socialHistory, 'valueCodeableConcept', { valueCoding: { system: 'http://example.com', code: 'never' } } ); expect(upsertSpy).toHaveBeenCalled(); }); test('skips when no value provided', async () => { const upsertSpy = vi.spyOn(medplum, 'upsertResource'); await upsertObservation( medplum as any, patient, observationCodeMapping.smokingStatus, observationCategoryMapping.socialHistory, 'valueCodeableConcept', undefined ); expect(upsertSpy).not.toHaveBeenCalled(); }); }); describe('resource helpers', () => { test('addAllergy returns early without substance', async () => { const upsertSpy = vi.spyOn(medplum, 'upsertResource'); await addAllergy(medplum as any, patient, {}); expect(upsertSpy).not.toHaveBeenCalled(); }); test('addAllergy upserts when code present', async () => { const upsertSpy = vi.spyOn(medplum, 'upsertResource').mockResolvedValue({} as any); await addAllergy(medplum as any, patient, { 'allergy-substance': { valueCoding: { system: 'http://example.com', code: 'peanut' } }, }); expect(upsertSpy).toHaveBeenCalledWith( expect.objectContaining({ resourceType: 'AllergyIntolerance', }), expect.objectContaining({ patient: `Patient/${patient.id}`, }) ); }); test('addCoverage upserts coverage resource', async () => { const upsertSpy = vi.spyOn(medplum, 'upsertResource').mockResolvedValue({} as any); const answers: Record<string, QuestionnaireResponseItemAnswer> = { 'insurance-provider': { valueReference: { reference: 'Organization/org-1' } as Reference<Organization> }, 'subscriber-id': { valueString: 'sub-1' }, 'relationship-to-subscriber': { valueCoding: { code: 'self' } }, }; await addCoverage(medplum as any, patient, answers); expect(upsertSpy).toHaveBeenCalledWith( expect.objectContaining({ resourceType: 'Coverage', beneficiary: expect.objectContaining({ reference: `Patient/${patient.id}` }), }), expect.objectContaining({ beneficiary: `Patient/${patient.id}`, }) ); }); test('addConsent creates resource with provided scope', async () => { const createSpy = vi.spyOn(medplum, 'createResource').mockResolvedValue({} as any); await addConsent( medplum as any, patient, true, observationCategoryMapping.socialHistory, observationCategoryMapping.sdoh, undefined, '2020-01-01' ); expect(createSpy).toHaveBeenCalledWith( expect.objectContaining({ resourceType: 'Consent', patient: expect.objectContaining({ reference: `Patient/${patient.id}` }), status: 'active', dateTime: '2020-01-01', }) ); }); }); });

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