Skip to main content
Glama
bulk.test.ts10.6 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ContentType, created, MedplumClient } from '@medplum/core'; import { main } from '.'; import { createMedplumClient } from './util/client'; import { getUnsupportedExtension } from './utils'; const testLineOutput = [ `{"resourceType":"Patient", "id":"1111111"}`, `{"resourceType":"Patient", "id":"2222222"}`, `{"resourceType":"Patient", "id":"3333333"}`, `{"resourceType":"ExplanationOfBenefit", "id":"1111111", "item":[{"sequence": 1}]}`, // EOB with missing provider and item.productOrService `{"resourceType":"ExplanationOfBenefit", "id":"2222222", "provider": "someprovider", "item":[{"sequence": 1, "productOrService": "someproduct"}]}`, ]; jest.mock('./util/client'); jest.mock('node:child_process'); jest.mock('node:http'); jest.mock('node:readline', () => ({ createInterface: jest.fn().mockReturnValue({ [Symbol.asyncIterator]: jest.fn(function* () { for (const line of testLineOutput) { yield line; } }), }), })); jest.mock('node:fs', () => ({ createReadStream: jest.fn(), existsSync: jest.fn(), readFileSync: jest.fn(), writeFileSync: jest.fn(), writeFile: jest.fn((path, data, callback) => { callback(); }), constants: { O_CREAT: 0, }, promises: { readFile: jest.fn(async () => '{}'), }, })); let medplum: MedplumClient; describe('CLI Bulk Commands', () => { describe('export', () => { let fetch: any; beforeEach(() => { let count = 0; fetch = jest.fn(async (url) => { if (url.includes('/$export?_since=200')) { return { status: 200, headers: { get(name: string): string | undefined { return { 'content-type': ContentType.FHIR_JSON, }[name]; }, }, json: jest.fn(async () => { return { resourceType: 'OperationOutcome', id: 'accepted', issue: [ { severity: 'information', code: 'informational', details: { text: 'Accepted', }, }, ], }; }), }; } if (url.includes('/$export')) { return { status: 202, json: jest.fn(async () => { return { resourceType: 'OperationOutcome', id: 'accepted', issue: [ { severity: 'information', code: 'informational', details: { text: 'Accepted', }, }, ], }; }), headers: { get(name: string): string | undefined { return { 'content-type': ContentType.FHIR_JSON, 'content-location': 'bulkdata/id/status', }[name]; }, }, }; } if (url.includes('bulkdata/id/status')) { if (count < 1) { count++; return { status: 202, headers: { get(name: string): string | undefined { return { 'content-type': ContentType.FHIR_JSON, }[name]; }, }, json: jest.fn(async () => { return {}; }), }; } } return { status: 200, headers: { get(name: string): string | undefined { return { 'content-type': ContentType.FHIR_JSON, }[name]; }, }, json: jest.fn(async () => ({ transactionTime: '2023-05-18T22:55:31.280Z', request: 'https://api.medplum.com/fhir/R4/$export?_type=Observation', requiresAccessToken: false, output: [ { type: 'ProjectMembership', url: 'https://api.medplum.com/storage/20fabdd3-e036-49fc-9260-8a30eaffefb1/498475fe-5eb0-46e5-b9f4-b46943c9719b?Expires=1685749878&Key-Pair-Id=my-key-id&Signature=PWyrVFf', }, { type: 'Project', url: 'https://sandbox.bcda.cms.gov/data/55555/aaaaaa-bbbbb-ccc-ddddd-eeeeee.ndjson', }, ], error: [], })), }; }); jest.resetModules(); jest.clearAllMocks(); medplum = new MedplumClient({ fetch }); (createMedplumClient as unknown as jest.Mock).mockImplementation(async () => medplum); console.log = jest.fn(); console.error = jest.fn(); process.exit = jest.fn() as never; }); test('system', async () => { const medplumDownloadSpy = jest.spyOn(medplum, 'download').mockImplementation((): any => { return { text: jest.fn(), }; }); await main(['node', 'index.js', 'bulk', 'export', '-t', 'Patient']); expect(medplumDownloadSpy).toHaveBeenCalled(); expect(console.log).toHaveBeenCalledWith( expect.stringMatching( 'ProjectMembership_storage_20fabdd3_e036_49fc_9260_8a30eaffefb1_498475fe_5eb0_46e5_b9f4_b46943c9719b.ndjson is created' ) ); expect(console.log).toHaveBeenCalledWith( expect.stringMatching('Project_data_55555_aaaaaa_bbbbb_ccc_ddddd_eeeeee_ndjson.ndjson is created') ); }); test('with --target-directory', async () => { const medplumDownloadSpy = jest.spyOn(medplum, 'download').mockImplementation((): any => { return { text: jest.fn(), }; }); const testDirectory = 'testtargetdirectory'; await main(['node', 'index.js', 'bulk', 'export', '-t', 'Patient', '--target-directory', testDirectory]); expect(medplumDownloadSpy).toHaveBeenCalled(); expect(console.log).toHaveBeenCalledWith(expect.stringMatching(`${testDirectory}`)); }); }); describe('import', () => { let fetch: any; beforeEach(() => { console.log = jest.fn(); console.error = jest.fn(); jest.resetModules(); jest.clearAllMocks(); fetch = jest.fn(async () => { return { status: 200, headers: { get(name: string): string | undefined { return { 'content-type': ContentType.FHIR_JSON, }[name]; }, }, json: jest.fn(async () => ({ resourceType: 'Bundle', type: 'transaction-response', entry: [ { response: { outcome: created, status: '201', }, resource: { resourceType: 'QuestionnaireResponse', }, }, ], })), }; }); medplum = new MedplumClient({ fetch }); (createMedplumClient as unknown as jest.Mock).mockImplementation(async () => medplum); }); test('success', async () => { await main(['node', 'index.js', 'bulk', 'import', 'Patient.json']); testLineOutput.forEach((line) => { const resource = JSON.parse(line); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining( JSON.stringify({ resource: resource, request: { method: 'POST', url: resource.resourceType, }, }) ), }) ); }); expect(console.log).toHaveBeenCalledWith(expect.stringMatching(`"status": "201"`)); expect(console.log).toHaveBeenCalledWith(expect.stringMatching(`"text": "Created"`)); }); test('success with option --num-resources-per-request', async () => { await main(['node', 'index.js', 'bulk', 'import', 'Patient.json', '--num-resources-per-request', '1']); testLineOutput.forEach((line) => { const resource = JSON.parse(line); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining( JSON.stringify({ resource: resource, request: { method: 'POST', url: resource.resourceType, }, }) ), }) ); }); expect(fetch).toHaveBeenCalled(); }); test('success with option --target-directory', async () => { await main(['node', 'index.js', 'bulk', 'import', 'Patient.json', '--target-directory', 'testdirectory']); testLineOutput.forEach((line) => { const resource = JSON.parse(line); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining( JSON.stringify({ resource: resource, request: { method: 'POST', url: resource.resourceType, }, }) ), }) ); }); expect(fetch).toHaveBeenCalled(); }); test('success with option --add-extensions-for-missing-values', async () => { await main(['node', 'index.js', 'bulk', 'import', 'file.json', '--add-extensions-for-missing-values']); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining(`"resourceType":"ExplanationOfBenefit","id":"1111111"`), }) ); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining(`"provider":` + JSON.stringify(getUnsupportedExtension())), }) ); expect(fetch).toHaveBeenCalledWith( expect.stringMatching(`/fhir/R4`), expect.objectContaining({ body: expect.stringContaining(`"productOrService":` + JSON.stringify(getUnsupportedExtension())), }) ); expect(fetch).toHaveBeenCalled(); }); }); });

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