Skip to content

Commit

Permalink
Add/fix tests and add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
lmd59 committed Jul 29, 2024
1 parent 4ac8e10 commit fa6c8b1
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 16 deletions.
5 changes: 4 additions & 1 deletion src/util/exportToNDJson.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ const buildSearchParamList = resourceType => {
* If the _type parameter doesn't exist, the function will simply export all resource types included in the supportedResources list.
* If the _typeFilter parameter is defined but the _type parameter is *not* defined, the function will export all resource types
* included in the supportedResources list, but the resource types specified in the _typeFilter query will be filtered.
* @param {string} clientId an id to add to the file name so the client making the request can be tracked
* @param {Object} jobOptions options object allowing for the following members:
* @param {string} clientEntry an id to add to the file name so the client making the request can be tracked
* @param {Array} types Array of types to be queried for, retrieved from request params
* @param {string} typeFilter String of comma separated FHIR REST search queries
* @param {string | Array} patient Patient references from the "patient" param, used to filter results
* @param {boolean} systemLevelExport boolean flag from job that signals whether request is for system-level export (determines filtering)
* @param {Array} patientIds Array of patient ids for patients relevant to this export (undefined if all patients)
* @param {Array} elements Array of elements parameters that indicate how to omit any unlisted, non-mandatory elements
* @param {boolean} byPatient boolean flag from job that signals whether resulting files should be grouped by patient (versus by type)
*/
const exportToNDJson = async jobOptions => {
const { clientEntry, types, typeFilter, patient, systemLevelExport, patientIds, elements, byPatient } = jobOptions;
Expand Down
1 change: 1 addition & 0 deletions src/util/mongo.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const findResourcesWithAggregation = async (query, resourceType, options = {}) =
/**
* Called as a result of export request. Adds a new clientId to db
* which can be queried to get updates on the status of the bulk export
* @param {boolean} byPatient indicated whether this export request groups data by patient (versus by type)
* @returns the id of the inserted client
*/
const addPendingBulkExportRequest = async (byPatient = false) => {
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/testEncounter.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,13 @@
"id": "testEncounter",
"subject": {
"reference": "Patient/testPatient"
},
"type": {
"coding": [
{
"system": "http://example.com",
"code": "example-code-1"
}
]
}
}
10 changes: 9 additions & 1 deletion test/fixtures/testPatient.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"resourceType": "Patient",
"id": "testPatient"
"id": "testPatient",
"maritalStatus": {
"coding": [
{
"system": "http://example.com",
"code": "example-code-1"
}
]
}
}
10 changes: 9 additions & 1 deletion test/fixtures/testServiceRequest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"resourceType": "ServiceRequest",
"id": "testServiceRequest"
"id": "testServiceRequest",
"code": {
"coding": [
{
"system": "http://example.com",
"code": "example-code-1"
}
]
}
}
41 changes: 41 additions & 0 deletions test/services/export.service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,47 @@ describe('Check by subject export logic', () => {
await app.ready();
});

test('check 202 for Patient bySubject', async () => {
const createJobSpy = jest.spyOn(queue, 'createJob');
await supertest(app.server)
.post('/Patient/$export')
.send({
resourceType: 'Parameters',
parameter: [
{
name: '_bySubject',
valueString: 'Patient'
}
]
})
.expect(202)
.then(response => {
expect(response.headers['content-location']).toBeDefined();
expect(createJobSpy).toHaveBeenCalled();
});
});

test('check 202 for Group bySubject', async () => {
await createTestResource(testGroup, 'Group');
const createJobSpy = jest.spyOn(queue, 'createJob');
await supertest(app.server)
.post('/Group/testGroup/$export')
.send({
resourceType: 'Parameters',
parameter: [
{
name: '_bySubject',
valueString: 'Patient'
}
]
})
.expect(202)
.then(response => {
expect(response.headers['content-location']).toBeDefined();
expect(createJobSpy).toHaveBeenCalled();
});
});

test('returns 400 for a _bySubject call that specifies a subject other than Patient', async () => {
await supertest(app.server)
.get('/Patient/$export?_bySubject=Other')
Expand Down
2 changes: 1 addition & 1 deletion test/services/ndjson.service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('Test ndjson retrieval from specified url', () => {

test('Retrieve ndjson content for valid url', async () => {
await createTestResourceWithConnect(testPatient, 'Patient');
await exportToNDJson(clientId, mockType);
await exportToNDJson({ clientEntry: clientId, types: [mockType] });
await supertest(app.server)
.get(`/${clientId}/Patient.ndjson`)
.expect(200)
Expand Down
35 changes: 23 additions & 12 deletions test/util/exportToNDJson.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const { cleanUpDb, createTestResourceWithConnect } = require('../populateTestDat
const testPatient = require('../fixtures/testPatient.json');
const testEncounter = require('../fixtures/testEncounter.json');
const testCondition = require('../fixtures/testCondition.json');
const testValueSet = require('../fixtures/valuesets/example-vs-1.json');

const testServiceRequest = require('../fixtures/testServiceRequest.json');
const app = build();
Expand All @@ -22,14 +23,14 @@ const mockType = ['Patient'];

const expectedFileName = './tmp/123456/Patient.ndjson';
const clientId = '123456';
const mockTypeFilter = 'Patient?type:in=http://example.com/fhir/ValueSet/test';
const mockTypeFilter = 'Patient?maritalStatus:in=http://example.com/example-valueset-1';

const complexMockTypeFilter =
'Patient?type:in=http://example.com/fhir/ValueSet/test,Encounter?type:in=http://example.com/fhir/ValueSet/test2,ServiceRequest?code:in=http://example.com/fhir/ValueSet/test';
'Patient?maritalStatus:in=http://example.com/example-valueset-1,Encounter?type:in=http://example.com/example-valueset-1,ServiceRequest?code:in=http://example.com/example-valueset-1';
const expectedFileNameEncounter = './tmp/123456/Encounter.ndjson';
const expectedFileNameServiceRequest = './tmp/123456/ServiceRequest.ndjson';
const typeFilterWOValueSet = 'Procedure?type:in=http';
const typeFilterWithInvalidType = 'Dog?type:in=http://example.com/fhir/ValueSet/test';
const typeFilterWithInvalidType = 'Dog?type:in=http://example.com/example-valueset-1';
const expectedFileNameInvalidType = './tmp/123456/Dog.ndjson';
const expectedFileNameWOValueSet = './tmp/123456/Procedure.ndjson';
describe('check export logic', () => {
Expand All @@ -38,6 +39,7 @@ describe('check export logic', () => {
await createTestResourceWithConnect(testEncounter, 'Encounter');
await createTestResourceWithConnect(testCondition, 'Condition');
await createTestResourceWithConnect(testServiceRequest, 'ServiceRequest');
await createTestResourceWithConnect(testValueSet, 'ValueSet');
console.log('created test resource');
});

Expand All @@ -59,33 +61,42 @@ describe('check export logic', () => {
});

describe('exportToNDJson', () => {
beforeEach(async () => {
fs.rmSync('./tmp/123456', { recursive: true, force: true });
});
test('Expect folder created and export successful when _type parameter is retrieved from request', async () => {
await exportToNDJson(clientId, mockType);
await exportToNDJson({ clientEntry: clientId, types: mockType });
expect(fs.existsSync(expectedFileName)).toBe(true);
});
test('Expect folder created and export successful when _type parameter is not present in request', async () => {
await exportToNDJson(clientId);
await exportToNDJson({ clientEntry: clientId });
expect(fs.existsSync(expectedFileName)).toBe(true);
});

test('Expect folder created and export successful when _typeFilter parameter is retrieved from request', async () => {
await exportToNDJson(clientId, mockType, mockTypeFilter);
test('Expect folder created and export successful when _typeFilter parameter is retrieved from request', async () => {
await exportToNDJson({ clientEntry: clientId, type: mockType, typeFilter: mockTypeFilter });
expect(fs.existsSync(expectedFileName)).toBe(true);
});
test('Expect folder created and export successful when _typeFilter parameter is retrieved from request', async () => {
await exportToNDJson(clientId, mockType, complexMockTypeFilter);
test('Expect folder created and export successful when complex _typeFilter parameter is retrieved from request', async () => {
await exportToNDJson({ clientEntry: clientId, type: mockType, typeFilter: complexMockTypeFilter });
expect(fs.existsSync(expectedFileName)).toBe(true);
expect(fs.existsSync(expectedFileNameEncounter)).toBe(true);
expect(fs.existsSync(expectedFileNameServiceRequest)).toBe(true);
});
test('Expect folder created and export to fail when _typeFilter parameter is retrieved from request and contains an invalid param', async () => {
await exportToNDJson(clientId, mockType, typeFilterWithInvalidType);
await exportToNDJson({ clientEntry: clientId, type: mockType, typeFilter: typeFilterWithInvalidType });
expect(fs.existsSync('./tmp/123456')).toBe(true);
expect(fs.existsSync(expectedFileNameInvalidType)).toBe(false);
});
test('Expect folder created and export to fail when _typeFilter parameter is retrieved from request but the value set is invalid', async () => {
await exportToNDJson(clientId, mockType, typeFilterWOValueSet);
test('Expect export to fail when _typeFilter parameter is retrieved from request but the value set is invalid', async () => {
await exportToNDJson({ clientEntry: clientId, type: mockType, typeFilter: typeFilterWOValueSet });
// TODO: this currently fails and does not create a folder (throws error instead). Do we want a more graceful response?
expect(fs.existsSync(expectedFileNameWOValueSet)).toBe(false);
});
test('Expect folder created and export successful when _bySubject parameter is retrieved from request', async () => {
await exportToNDJson({ clientEntry: clientId, types: mockType, typeFilter: mockTypeFilter, byPatient: true });
expect(fs.existsSync('./tmp/123456/testPatient.ndjson')).toBe(true);
});
});

describe('patientsQueryForType', () => {
Expand Down

0 comments on commit fa6c8b1

Please sign in to comment.