Skip to main content
Glama
profiles.test.ts7.67 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ContentType, MedplumClient } from '@medplum/core'; import { mkdtempSync, rmSync } from 'node:fs'; import os from 'node:os'; import { sep } from 'node:path'; import { main } from '.'; import { FileSystemStorage } from './storage'; import { createMedplumClient } from './util/client'; jest.mock('node:os'); jest.mock('fast-glob', () => ({ sync: jest.fn(() => []), })); jest.mock('./util/client'); jest.mock('node:fs', () => ({ ...jest.requireActual('node:fs'), writeFile: jest.fn((path, data, callback) => { callback(); }), })); const testHomeDir = mkdtempSync(__dirname + sep + 'storage-'); describe('Profiles', () => { beforeEach(async () => { console.log = jest.fn(); }); 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: [], })), }; }); }); beforeAll(async () => { (os.homedir as unknown as jest.Mock).mockReturnValue(testHomeDir); }); afterAll(async () => { rmSync(testHomeDir, { recursive: true, force: true }); }); test('Profiles', async () => { const profileName = 'testProfile'; const obj = { name: profileName, authType: 'basic', baseUrl: 'https://valid.gov', fhirUrlPath: 'api/v2', tokenUrl: 'https://validtoken.gov', }; await main([ 'node', 'index.js', 'profile', 'set', profileName, '--auth-type', obj.authType, '--base-url', obj.baseUrl, '--fhir-url-path', obj.fhirUrlPath, '--token-url', obj.tokenUrl, ]); const storage = new FileSystemStorage(profileName); // Describe profile await main(['node', 'index.js', 'profile', 'describe', profileName]); expect(console.log).toHaveBeenCalledWith(obj); // Replace the previous values const obj2 = { name: profileName, authType: 'jwt-bearer', baseUrl: 'https://valid2.gov', fhirUrlPath: 'api/v2', tokenUrl: 'https://validtoken2.gov', }; await main([ 'node', 'index.js', 'profile', 'set', profileName, '--auth-type', obj2.authType, '--base-url', obj2.baseUrl, '--fhir-url-path', obj2.fhirUrlPath, '--token-url', obj2.tokenUrl, ]); expect(storage.getObject('options')).not.toStrictEqual(obj); expect(storage.getObject('options')).toStrictEqual(obj2); // Add another profile const profileName2 = 'testProfile2'; await main([ 'node', 'index.js', 'profile', 'set', profileName2, '--auth-type', obj.authType, '--base-url', obj.baseUrl, '--fhir-url-path', obj.fhirUrlPath, '--token-url', obj.tokenUrl, ]); const storage2 = new FileSystemStorage(profileName2); expect(storage2.getObject('options')).toStrictEqual({ ...obj, name: profileName2 }); // List the 2 profiles await main(['node', 'index.js', 'profile', 'list']); expect(console.log).toHaveBeenCalledWith([ { profileName, profile: { ...obj2, name: profileName } }, { profileName: profileName2, profile: { ...obj, name: profileName2 } }, ]); // Delete the first profile await main(['node', 'index.js', 'profile', 'remove', profileName]); // ProfileName should be undefined, but profileName2 should still exist await main(['node', 'index.js', 'profile', 'list']); expect(console.log).toHaveBeenCalledWith([{ profileName: profileName2, profile: { ...obj, name: profileName2 } }]); }); test('Basic Auth profile bulk export', async () => { const profileName = 'testProfile'; const obj = { authType: 'basic', baseUrl: 'https://valid.gov', fhirUrlPath: 'api/v2', tokenUrl: 'https://validtoken.gov', clientId: 'validClientId', clientSecret: 'validClientSecret', }; const storage = new FileSystemStorage(profileName); storage.setObject('options', obj); const medplum = new MedplumClient({ fetch }); medplum.setBasicAuth(obj.clientId, obj.clientSecret); (createMedplumClient as unknown as jest.Mock).mockImplementation(async () => medplum); const medplumDownloadSpy = jest.spyOn(medplum, 'download').mockImplementation((): any => { return { text: jest.fn(), }; }); await main(['node', 'index.js', 'bulk', 'export', '-e', 'Patient', '-p', profileName]); expect(medplumDownloadSpy).toHaveBeenCalled(); expect(console.log).toHaveBeenCalledWith( expect.stringMatching( 'ProjectMembership_storage_20fabdd3_e036_49fc_9260_8a30eaffefb1_498475fe_5eb0_46e5_b9f4_b46943c9719b.ndjson is created' ) ); }); });

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