diff --git a/bus-gateway/package.json b/bus-gateway/package.json index 3ed3f59..3694a3f 100644 --- a/bus-gateway/package.json +++ b/bus-gateway/package.json @@ -20,5 +20,9 @@ }, "devDependencies": { "jest": "^30.3.0" + }, + "jest": { + "testEnvironment": "node", + "setupFiles": ["./tests/setup.js"] } } diff --git a/bus-gateway/tests/services/documentReference.test.js b/bus-gateway/tests/services/documentReference.test.js index d8a53b9..8e97ff2 100644 --- a/bus-gateway/tests/services/documentReference.test.js +++ b/bus-gateway/tests/services/documentReference.test.js @@ -3,16 +3,14 @@ const axios = require('axios'); const { getBusToken } = require('../../utils/busAuth'); const { createDocumentReference, - postDocumentReference, - searchDocumentReferenceBySubject, - searchDocumentReferenceByPatient, + findDocumentReferenceBySubject, + findDocumentReferenceByPatient, searchDocumentReference, } = require('../../services/documentReference'); jest.mock('axios'); const BUS_URL = process.env.BUS_URL; -const REGISTRY_URL = process.env.DOCUMENT_REGISTRY_URL || process.env.BUS_URL; const BUS_JWT_SECRET = process.env.BUS_JWT_SECRET; const BUS_ISSUER = process.env.BUS_ISSUER; const BUS_SCOPE = process.env.DOCUMENT_REGISTRY_SCOPE; @@ -29,128 +27,66 @@ async function acquireToken() { return getBusToken(BUS_URL, BUS_JWT_SECRET, BUS_ISSUER, BUS_SCOPE); } -const CUSTODIAN_ID = 'efector-001'; -const BUNDLE_URL = 'http://hapi-fhir-host:8080/fhir/Bundle/abc123'; +// Internal URL used by the document registry (replaced by maskPrivateURL) +const INTERNAL_REGISTRY_BASE = 'https://federador.qa-bus-interoperabilidad.svc.cluster.local:8080/fhir/DocumentReference'; -const IPS_BUNDLE = { - resourceType: 'Bundle', - id: 'bundle-001', - entry: [ - { - resource: { - resourceType: 'Patient', - identifier: [ - { system: 'https://federador.msal.gob.ar/patient-id', value: '5037097' }, - ], - }, - }, - ], +const DOCUMENT_REFERENCE = { + resourceType: 'DocumentReference', + status: 'current', + subject: { + identifier: { system: 'https://federador.msal.gob.ar/patient-id', value: '5037097' }, + }, }; describe('createDocumentReference', () => { - it('builds a DocumentReference from IPS bundle using the first patient identifier', () => { - const dr = createDocumentReference(IPS_BUNDLE, CUSTODIAN_ID, BUNDLE_URL); - - expect(dr.resourceType).toBe('DocumentReference'); - expect(dr.status).toBe('current'); - expect(dr.type.coding[0].code).toBe('60591-5'); - expect(dr.subject.identifier).toEqual({ - system: 'https://federador.msal.gob.ar/patient-id', - value: '5037097', - }); - expect(dr.custodian.identifier).toEqual({ - system: 'https://federador.msal.gob.ar/uri', - value: CUSTODIAN_ID, - }); - expect(dr.content[0].attachment.url).toBe(BUNDLE_URL); - }); - - it('uses subjectIdentifier when provided instead of patient identifier', () => { - const subjectIdentifier = { system: 'http://www.renaper.gob.ar/dni', value: '30945027' }; - const dr = createDocumentReference(IPS_BUNDLE, CUSTODIAN_ID, BUNDLE_URL, subjectIdentifier); - - expect(dr.subject.identifier).toEqual(subjectIdentifier); - }); - - it('falls back to Bundle/{id} when bundleUrl is not provided', () => { - const dr = createDocumentReference(IPS_BUNDLE, CUSTODIAN_ID); - - expect(dr.content[0].attachment.url).toBe(`Bundle/${IPS_BUNDLE.id}`); - }); - - it('throws when the bundle has no Patient entry', () => { - const bundleWithoutPatient = { ...IPS_BUNDLE, entry: [] }; - - expect(() => createDocumentReference(bundleWithoutPatient, CUSTODIAN_ID)).toThrow( - 'IPS Bundle does not contain a Patient resource' - ); - }); - - it('throws when the patient has no identifier', () => { - const bundleNoIdentifier = { - ...IPS_BUNDLE, - entry: [{ resource: { resourceType: 'Patient', identifier: [] } }], - }; - - expect(() => createDocumentReference(bundleNoIdentifier, CUSTODIAN_ID)).toThrow( - 'Patient resource has no identifier' - ); - }); -}); - -describe('postDocumentReference', () => { - it('POSTs a DocumentReference to /fhir/DocumentReference and returns response data', async () => { + it('POSTs a DocumentReference to the registry and returns the created resource', async () => { const token = await acquireToken(); const responseData = { resourceType: 'DocumentReference', id: 'dr-001' }; - mockRequest.post.mockResolvedValue({ data: responseData }); - - const result = await postDocumentReference(REGISTRY_URL, token, IPS_BUNDLE, CUSTODIAN_ID, BUNDLE_URL); - - expect(axios.create).toHaveBeenCalledWith({ - baseURL: REGISTRY_URL, - headers: { - 'Content-Type': 'application/fhir+json', - 'Authorization': `Bearer ${token}`, - }, + mockRequest.post.mockResolvedValue({ + data: {}, + headers: { location: `${INTERNAL_REGISTRY_BASE}/dr-001` }, }); - expect(mockRequest.post).toHaveBeenCalledWith( - '/fhir/DocumentReference', - expect.objectContaining({ resourceType: 'DocumentReference' }) - ); + mockRequest.get.mockResolvedValue({ data: responseData }); + + const result = await createDocumentReference(token, DOCUMENT_REFERENCE); + + expect(mockRequest.post).toHaveBeenCalledWith(expect.anything(), DOCUMENT_REFERENCE); expect(result).toEqual(responseData); }); }); -describe('searchDocumentReferenceBySubject', () => { +describe('findDocumentReferenceBySubject', () => { it('GETs /fhir/DocumentReference with subject param as system|value', async () => { const token = await acquireToken(); const bundle = { resourceType: 'Bundle', entry: [] }; mockRequest.get.mockResolvedValue({ data: bundle }); - const result = await searchDocumentReferenceBySubject( - REGISTRY_URL, token, + const result = await findDocumentReferenceBySubject( + token, 'https://federador.msal.gob.ar/patient-id', '5037097' ); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/DocumentReference', { - params: { subject: 'https://federador.msal.gob.ar/patient-id|5037097' }, - }); + expect(mockRequest.get).toHaveBeenCalledWith( + expect.anything(), + { params: { subject: 'https://federador.msal.gob.ar/patient-id|5037097' } } + ); expect(result).toEqual(bundle); }); }); -describe('searchDocumentReferenceByPatient', () => { - it('GETs /fhir/DocumentReference with patient param', async () => { +describe('findDocumentReferenceByPatient', () => { + it('GETs /fhir/DocumentReference with patient ID as subject param', async () => { const token = await acquireToken(); const bundle = { resourceType: 'Bundle', entry: [] }; mockRequest.get.mockResolvedValue({ data: bundle }); - const result = await searchDocumentReferenceByPatient(REGISTRY_URL, token, '5037097'); + const result = await findDocumentReferenceByPatient(token, 'http://mpi/fhir/Patient/123'); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/DocumentReference', { - params: { patient: '5037097' }, - }); + expect(mockRequest.get).toHaveBeenCalledWith( + expect.anything(), + { params: { subject: 'http://mpi/fhir/Patient/123' } } + ); expect(result).toEqual(bundle); }); }); @@ -165,15 +101,18 @@ describe('searchDocumentReference', () => { const custodian = { system: 'https://federador.msal.gob.ar/uri', value: 'efector-001' }; const type = { system: 'http://loinc.org', value: '60591-5' }; - const result = await searchDocumentReference(REGISTRY_URL, token, subject, custodian, type); + const result = await searchDocumentReference(token, subject, custodian, type); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/DocumentReference', { - params: { - subject: 'https://federador.msal.gob.ar/patient-id|5037097', - custodian: 'https://federador.msal.gob.ar/uri|efector-001', - type: 'http://loinc.org|60591-5', - }, - }); + expect(mockRequest.get).toHaveBeenCalledWith( + expect.anything(), + { + params: { + subject: 'https://federador.msal.gob.ar/patient-id|5037097', + custodian: 'https://federador.msal.gob.ar/uri|efector-001', + type: 'http://loinc.org|60591-5', + }, + } + ); expect(result).toEqual(bundle); }); }); diff --git a/bus-gateway/tests/services/patient.test.js b/bus-gateway/tests/services/patient.test.js index 06c4151..5fe9fec 100644 --- a/bus-gateway/tests/services/patient.test.js +++ b/bus-gateway/tests/services/patient.test.js @@ -1,17 +1,16 @@ require('dotenv').config(); const axios = require('axios'); const { getBusToken } = require('../../utils/busAuth'); -const { postPatient, getPatientById, searchPatient, matchPatient } = require('../../services/patient'); +const { createPatient, findPatientById, findPatient, findPatientByMatch } = require('../../services/patient'); jest.mock('axios'); const BUS_URL = process.env.BUS_URL; -const MPI_URL = process.env.MPI_URL || process.env.BUS_URL; const BUS_JWT_SECRET = process.env.BUS_JWT_SECRET; const BUS_ISSUER = process.env.BUS_ISSUER; const BUS_SCOPE = process.env.MPI_SCOPE; -const mockRequest = { get: jest.fn(), post: jest.fn() }; +const mockRequest = { get: jest.fn(), post: jest.fn(), put: jest.fn() }; beforeEach(() => { jest.clearAllMocks(); @@ -23,49 +22,49 @@ async function acquireToken() { return getBusToken(BUS_URL, BUS_JWT_SECRET, BUS_ISSUER, BUS_SCOPE); } -describe('postPatient', () => { - it('POSTs the patient to /fhir/Patient and returns response data', async () => { +// Internal URL used by the MPI service (replaced by maskPrivateURL) +const INTERNAL_MPI_BASE = 'https://federador.qa-bus-interoperabilidad.svc.cluster.local:8080/masterfile-federacion-service/fhir/Patient'; + +describe('createPatient', () => { + it('POSTs the patient to the MPI and returns the created resource', async () => { const token = await acquireToken(); const patient = { resourceType: 'Patient', id: '1' }; const responseData = { resourceType: 'Patient', id: '1', meta: {} }; - mockRequest.post.mockResolvedValue({ data: responseData }); - - const result = await postPatient(MPI_URL, token, patient); - - expect(axios.create).toHaveBeenCalledWith({ - baseURL: MPI_URL, - headers: { - 'Content-Type': 'application/fhir+json', - 'Authorization': `Bearer ${token}`, - }, + mockRequest.post.mockResolvedValue({ + data: {}, + headers: { location: `${INTERNAL_MPI_BASE}/1` }, }); - expect(mockRequest.post).toHaveBeenCalledWith('/fhir/Patient', patient); + mockRequest.get.mockResolvedValue({ data: responseData }); + + const result = await createPatient(token, patient); + + expect(mockRequest.post).toHaveBeenCalledWith(expect.anything(), patient); expect(result).toEqual(responseData); }); }); -describe('getPatientById', () => { - it('GETs /fhir/Patient/:id and returns response data', async () => { +describe('findPatientById', () => { + it('GETs the patient by ID and returns response data', async () => { const token = await acquireToken(); const responseData = { resourceType: 'Patient', id: '42' }; mockRequest.get.mockResolvedValue({ data: responseData }); - const result = await getPatientById(MPI_URL, token, '42'); + const result = await findPatientById(token, '42'); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/Patient/42'); + expect(mockRequest.get).toHaveBeenCalledWith(expect.anything()); expect(result).toEqual(responseData); }); }); -describe('searchPatient', () => { +describe('findPatient', () => { it('GETs /fhir/Patient with no params when criteria is empty', async () => { const token = await acquireToken(); const bundle = { resourceType: 'Bundle', entry: [] }; mockRequest.get.mockResolvedValue({ data: bundle }); - const result = await searchPatient(MPI_URL, token, {}); + const result = await findPatient(token, {}); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/Patient', { params: {} }); + expect(mockRequest.get).toHaveBeenCalledWith(expect.anything(), { params: {} }); expect(result).toEqual(bundle); }); @@ -73,7 +72,7 @@ describe('searchPatient', () => { const token = await acquireToken(); mockRequest.get.mockResolvedValue({ data: {} }); - await searchPatient(MPI_URL, token, { + await findPatient(token, { name: 'Juan', family: 'Perez', birthdate: '1983-04-17', @@ -81,7 +80,7 @@ describe('searchPatient', () => { phone: '1141233100', }); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/Patient', { + expect(mockRequest.get).toHaveBeenCalledWith(expect.anything(), { params: { name: 'Juan', family: 'Perez', @@ -92,42 +91,28 @@ describe('searchPatient', () => { }); }); - it('combines identifierSystem and identifierValue into identifier param', async () => { + it('passes the identifier param directly when provided as system|value string', async () => { const token = await acquireToken(); mockRequest.get.mockResolvedValue({ data: {} }); - await searchPatient(MPI_URL, token, { - identifierSystem: 'http://www.renaper.gob.ar/dni', - identifierValue: '30945027', - }); + await findPatient(token, { identifier: 'http://www.renaper.gob.ar/dni|30945027' }); - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/Patient', { + expect(mockRequest.get).toHaveBeenCalledWith(expect.anything(), { params: { identifier: 'http://www.renaper.gob.ar/dni|30945027' }, }); }); - - it('uses identifierValue alone when identifierSystem is not provided', async () => { - const token = await acquireToken(); - mockRequest.get.mockResolvedValue({ data: {} }); - - await searchPatient(MPI_URL, token, { identifierValue: '30945027' }); - - expect(mockRequest.get).toHaveBeenCalledWith('/fhir/Patient', { - params: { identifier: '30945027' }, - }); - }); }); -describe('matchPatient', () => { - it('POSTs a Parameters resource to /fhir/Patient/$match', async () => { +describe('findPatientByMatch', () => { + it('POSTs a Parameters resource to $match', async () => { const token = await acquireToken(); const patient = { resourceType: 'Patient', id: '1' }; const bundle = { resourceType: 'Bundle', entry: [] }; mockRequest.post.mockResolvedValue({ data: bundle }); - const result = await matchPatient(MPI_URL, token, patient); + const result = await findPatientByMatch(token, patient); - expect(mockRequest.post).toHaveBeenCalledWith('/fhir/Patient/$match', { + expect(mockRequest.post).toHaveBeenCalledWith(expect.anything(), { resourceType: 'Parameters', parameter: [{ name: 'resource', resource: patient }], }); @@ -139,9 +124,9 @@ describe('matchPatient', () => { const patient = { resourceType: 'Patient' }; mockRequest.post.mockResolvedValue({ data: {} }); - await matchPatient(MPI_URL, token, patient, 3); + await findPatientByMatch(token, patient, 3); - expect(mockRequest.post).toHaveBeenCalledWith('/fhir/Patient/$match', { + expect(mockRequest.post).toHaveBeenCalledWith(expect.anything(), { resourceType: 'Parameters', parameter: [ { name: 'resource', resource: patient }, @@ -155,7 +140,7 @@ describe('matchPatient', () => { const patient = { resourceType: 'Patient' }; mockRequest.post.mockResolvedValue({ data: {} }); - await matchPatient(MPI_URL, token, patient); + await findPatientByMatch(token, patient); const call = mockRequest.post.mock.calls[0]; const parameters = call[1]; diff --git a/bus-gateway/tests/setup.js b/bus-gateway/tests/setup.js new file mode 100644 index 0000000..b856378 --- /dev/null +++ b/bus-gateway/tests/setup.js @@ -0,0 +1,8 @@ +process.env.BUS_URL = 'http://bus-host:8080'; +process.env.BUS_JWT_SECRET = 'test-secret'; +process.env.BUS_ISSUER = 'https://test-repositorio-url'; +process.env.MPI_SCOPE = 'Patient/*.read,Patient/*.write'; +process.env.DOCUMENT_REGISTRY_SCOPE = 'DocumentReference/*.read,DocumentReference/*.write'; +process.env.FHIR_URL = 'http://hapi-fhir-host:8080/fhir'; +process.env.MPI_URL = 'http://mpi-host:8080'; +process.env.DOCUMENT_REGISTRY_URL = 'http://document-registry-host:8080'; diff --git a/bus-gateway/tests/utils/busAuth.test.js b/bus-gateway/tests/utils/busAuth.test.js index bd85174..3a9618e 100644 --- a/bus-gateway/tests/utils/busAuth.test.js +++ b/bus-gateway/tests/utils/busAuth.test.js @@ -89,19 +89,20 @@ describe('getBusToken', () => { }); describe('createBusRequest', () => { - it('creates an axios instance with the correct baseURL and headers', () => { + it('creates an axios instance with Authorization and Content-Type headers', () => { const mockInstance = { get: jest.fn(), post: jest.fn() }; axios.create.mockReturnValue(mockInstance); const token = 'my-token'; - createBusRequest(BUS_URL, token); + createBusRequest(token); - expect(axios.create).toHaveBeenCalledWith({ - baseURL: BUS_URL, - headers: { - 'Content-Type': 'application/fhir+json', - 'Authorization': `Bearer ${token}`, - }, - }); + expect(axios.create).toHaveBeenCalledWith( + expect.objectContaining({ + headers: { + 'Content-Type': 'application/fhir+json', + 'Authorization': `Bearer ${token}`, + }, + }) + ); }); });