Skip to main content
Glama
vital.test.ts10.4 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { indexSearchParameterBundle, indexStructureDefinitionBundle } from '@medplum/core'; import type { MedplumClient } from '@medplum/core'; import { SEARCH_PARAMETER_BUNDLE_FILES, readJson } from '@medplum/definitions'; import type { Bundle, Questionnaire, QuestionnaireItem, QuestionnaireItemAnswerOption, SearchParameter, } from '@medplum/fhirtypes'; import { MockClient } from '@medplum/mock'; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; import type { MockedFunction } from 'vitest'; import { handler } from './vital'; import type { Marker } from './vital'; global.fetch = vi.fn(); describe('Vital API', () => { beforeAll(() => { indexStructureDefinitionBundle(readJson('fhir/r4/profiles-types.json') as Bundle); indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle); for (const filename of SEARCH_PARAMETER_BUNDLE_FILES) { indexSearchParameterBundle(readJson(filename) as Bundle<SearchParameter>); } }); type Context = { medplum: MedplumClient; }; beforeEach<Context>(async (ctx) => { (global.fetch as MockedFunction<typeof fetch>).mockReset(); const medplum = new MockClient(); Object.assign(ctx, { medplum, }); }); afterEach(() => { vi.clearAllMocks(); vi.resetAllMocks(); }); test<Context>('Get Lab Tests', async (ctx) => { const apiKey = '3f2504e0-4f89-11d3-9a0c-0305e82c3301'; const baseURL = 'https://api.dev.tryvital.io'; const labTests = [ { lab: { id: 24, slug: 'ussl', name: 'USSL', collection_methods: ['testkit'], }, }, { lab: { id: 2, slug: 'spiriplex', name: 'Spiriplex', collection_methods: ['testkit'], }, }, { lab: { id: 27, slug: 'labcorp', name: 'Labcorp', collection_methods: ['at_home_phlebotomy', 'walk_in_test'], }, }, ]; (fetch as any).mockResolvedValue(createFetchResponse(labTests)); const labTestsResponse = await handler(ctx.medplum, { bot: { reference: 'Bot/123' }, input: { endpoint: 'get_lab_tests', }, contentType: 'application/fhir+json', secrets: { VITAL_BASE_URL: { name: 'VITAL_BASE_URL', valueString: baseURL, }, VITAL_API_KEY: { name: 'VITAL_API_KEY', valueString: apiKey, }, }, }); expect(fetch).toHaveBeenCalledWith(`${baseURL}/v3/lab_tests`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-vital-api-key': apiKey, }, }); expect(labTestsResponse).toStrictEqual(labTests); }); test<Context>('Get Lab Tests with lab filter', async (ctx) => { const apiKey = '3f2504e0-4f89-11d3-9a0c-0305e82c3301'; const baseURL = 'https://api.dev.tryvital.io'; const labTests = [ { lab: { id: 24, slug: 'ussl', name: 'USSL', collection_methods: ['testkit'], }, }, { lab: { id: 2, slug: 'spiriplex', name: 'Spiriplex', collection_methods: ['testkit'], }, }, { lab: { id: 27, slug: 'labcorp', name: 'Labcorp', collection_methods: ['at_home_phlebotomy', 'walk_in_test'], }, }, ]; (fetch as any).mockResolvedValue(createFetchResponse(labTests)); const labTestsResponse = await handler(ctx.medplum, { bot: { reference: 'Bot/123' }, input: { endpoint: 'get_lab_tests', payload: { labID: 24, }, }, contentType: 'application/fhir+json', secrets: { VITAL_BASE_URL: { name: 'VITAL_BASE_URL', valueString: baseURL, }, VITAL_API_KEY: { name: 'VITAL_API_KEY', valueString: apiKey, }, }, }); expect(fetch).toHaveBeenCalledWith(`${baseURL}/v3/lab_tests`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-vital-api-key': apiKey, }, }); expect(labTestsResponse).toStrictEqual(labTests.filter((lt) => lt.lab.id === 24)); }); test<Context>('Get Labs', async (ctx) => { const apiKey = '3f2504e0-4f89-11d3-9a0c-0305e82c3301'; const baseURL = 'https://api.dev.tryvital.io'; const labsMock = [ { id: 24, slug: 'ussl', name: 'USSL', collection_methods: ['testkit'], }, { id: 2, slug: 'spiriplex', name: 'Spiriplex', collection_methods: ['testkit'], }, { id: 27, slug: 'labcorp', name: 'Labcorp', collection_methods: ['at_home_phlebotomy', 'walk_in_test'], }, ]; (fetch as any).mockResolvedValue(createFetchResponse(labsMock)); const labs = await handler(ctx.medplum, { bot: { reference: 'Bot/123' }, input: { endpoint: 'get_labs', }, contentType: 'application/fhir+json', secrets: { VITAL_BASE_URL: { name: 'VITAL_BASE_URL', valueString: baseURL, }, VITAL_API_KEY: { name: 'VITAL_API_KEY', valueString: apiKey, }, }, }); expect(fetch).toHaveBeenCalledWith(`${baseURL}/v3/lab_tests/labs`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-vital-api-key': apiKey, }, }); expect(labs).toStrictEqual(labsMock); }); test<Context>('Get Markers', async (ctx) => { const apiKey = '3f2504e0-4f89-11d3-9a0c-0305e82c3301'; const baseURL = 'https://api.dev.tryvital.io'; const labTests = [ { id: '3ffa4b3b-0b3b-4b3b-8b3b-2b3b3b3b3b3b', markers: [ { id: 1, name: 'Hemoglobin A1c', slug: 'hemoglobin-a1c', lab_id: 24, }, { id: 2, name: 'Lipid Panel', slug: 'lipid-panel', lab_id: 24, }, { id: 3, name: 'Complete Blood Count', slug: 'complete-blood-count', lab_id: 24, }, ], }, { id: '42fa4b3b-0b3b-4b3b-8b3b-2b3b3b3b3b3b', markers: [ { id: 3, name: 'Complete Blood Count', slug: 'complete-blood-count', lab_id: 24, }, ], }, ]; (fetch as any).mockResolvedValue(createFetchResponse(labTests)); const markers = await handler(ctx.medplum, { bot: { reference: 'Bot/123' }, input: { endpoint: 'get_markers', payload: { labTestID: '3ffa4b3b-0b3b-4b3b-8b3b-2b3b3b3b3b3b', }, }, contentType: 'application/fhir+json', secrets: { VITAL_BASE_URL: { name: 'VITAL_BASE_URL', valueString: baseURL, }, VITAL_API_KEY: { name: 'VITAL_API_KEY', valueString: apiKey, }, }, }); expect(fetch).toHaveBeenCalledWith(`${baseURL}/v3/lab_tests`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-vital-api-key': apiKey, }, }); expect(markers).toStrictEqual(labTests[0].markers); }); test<Context>('Get AOEs', async (ctx) => { const apiKey = '3f2504e0-4f89-11d3-9a0c-0305e82c3301'; const baseURL = 'https://api.dev.tryvital.io'; const labTests = [ { id: '3ffa4b3b-0b3b-4b3b-8b3b-2b3b3b3b3b3b', markers: [ { id: 1, name: 'Hemoglobin A1c', slug: 'hemoglobin-a1c', aoe: { questions: [ { id: 1, required: true, code: 'HemoglobinA1c', value: 'What is your Hemoglobin A1c?', type: 'numeric', sequence: 1, answers: [], }, ], }, }, ], }, ]; (fetch as any).mockResolvedValue(createFetchResponse(labTests)); const questionnaire = await handler(ctx.medplum, { bot: { reference: 'Bot/123' }, input: { endpoint: 'get_aoe_questionnaire', payload: { labTestID: '3ffa4b3b-0b3b-4b3b-8b3b-2b3b3b3b3b3b', }, }, contentType: 'application/fhir+json', secrets: { VITAL_BASE_URL: { name: 'VITAL_BASE_URL', valueString: baseURL, }, VITAL_API_KEY: { name: 'VITAL_API_KEY', valueString: apiKey, }, }, }); expect(fetch).toHaveBeenCalledWith(`${baseURL}/v3/lab_tests`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-vital-api-key': apiKey, }, }); expect(questionnaire).toStrictEqual(buildQuestionnaire(labTests[0].markers)); }); }); function createFetchResponse(data: any, status = 200): Response { return { status, json: () => new Promise((resolve) => { resolve(data); }), ok: status >= 200 && status < 300, } as Response; } function buildQuestionnaire(markers: Partial<Marker>[]): Questionnaire { return { resourceType: 'Questionnaire', title: 'Ask on Order Entry (AOE)', status: 'active', item: markers.map((marker) => ({ linkId: marker.id?.toString() || '', text: marker.name, type: 'group', item: marker.aoe?.questions.map<QuestionnaireItem>((question) => ({ linkId: question.id.toString(), text: question.value, type: (question.type === 'numeric' ? 'decimal' : question.type) as QuestionnaireItem['type'], required: question.required, answerOption: question.answers?.map<QuestionnaireItemAnswerOption>((answer) => ({ valueString: question.type !== 'numeric' ? answer.value : undefined, valueInteger: question.type === 'numeric' ? Number.parseFloat(answer.value) : undefined, })), })), })), }; }

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