diff --git a/__mocks__/forms/rfe-forms/diagnosis-test-form.json b/__mocks__/forms/rfe-forms/diagnosis-test-form.json
new file mode 100644
index 00000000..c60ffdb9
--- /dev/null
+++ b/__mocks__/forms/rfe-forms/diagnosis-test-form.json
@@ -0,0 +1,60 @@
+{
+ "name": "Diagnosis test",
+ "pages": [
+ {
+ "label": "1",
+ "sections": [
+ {
+ "label": "Select diagnosis",
+ "isExpanded": "true",
+ "questions": [
+ {
+ "label": "Test Diagnosis 1",
+ "id": "diagnosis1",
+ "type": "diagnosis",
+ "questionOptions": {
+ "rendering": "repeating",
+ "dataSource": "diagnoses",
+ "isSearchable": "false",
+ "diagnosis": {
+ "isConfirmed": "true",
+ "rank": 1,
+ "conceptClasses": [
+ "8d4918b0-c2cc-11de-8d13-0010c6dffd0f",
+ "8d492954-c2cc-11de-8d13-0010c6dffd0f",
+ "8d492b2a-c2cc-11de-8d13-0010c6dffd0f"
+ ]
+ }
+ }
+ },
+ {
+ "label": "Test Diagnosis 2",
+ "id": "diagnosis2",
+ "type": "diagnosis",
+ "questionOptions": {
+ "rendering": "repeating",
+ "dataSource": "diagnoses",
+ "isSearchable": "false",
+ "diagnosis": {
+ "isConfirmed": "true",
+ "rank": 1,
+ "conceptClasses": [
+ "8d4918b0-c2cc-11de-8d13-0010c6dffd0f",
+ "8d492954-c2cc-11de-8d13-0010c6dffd0f",
+ "8d492b2a-c2cc-11de-8d13-0010c6dffd0f"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "processor": "EncounterFormProcessor",
+ "encounterType": "e22e39fd-7db2-45e7-80f1-60fa0d5a4378",
+ "referencedForms": [],
+ "uuid": "29ce67d1-892b-45be-84ce-8e36aa9ca37f",
+ "description": "re",
+ "version": "1.0"
+}
diff --git a/src/adapters/encounter-diagnosis-adapter.ts b/src/adapters/encounter-diagnosis-adapter.ts
index af3af17e..b218bb0b 100644
--- a/src/adapters/encounter-diagnosis-adapter.ts
+++ b/src/adapters/encounter-diagnosis-adapter.ts
@@ -4,7 +4,6 @@ import { type FormContextProps } from '../provider/form-provider';
import { type OpenmrsEncounter, type FormField } from '../types';
import { gracefullySetSubmission } from '../utils/common-utils';
import { isEmpty } from '../validators/form-validator';
-import { voidObs } from './obs-adapter';
import { isTrue } from '../utils/boolean-utils';
export let assignedDiagnosesIds: string[] = [];
@@ -12,7 +11,7 @@ export let assignedDiagnosesIds: string[] = [];
export const EncounterDiagnosisAdapter: FormFieldValueAdapter = {
transformFieldValue: function (field: FormField, value: any, context: FormContextProps) {
if (field.meta.initialValue?.omrsObject && isEmpty(value)) {
- return gracefullySetSubmission(field, undefined, voidObs(field.meta.initialValue.omrsObject as OpenmrsObs));
+ return gracefullySetSubmission(field, undefined, voidDiagnosis(field.meta.initialValue.omrsObject as OpenmrsObs));
}
if (!isEmpty(value)) {
const previousDiagnosis = field.meta.initialValue?.omrsObject as OpenmrsResource;
@@ -68,7 +67,7 @@ export const EncounterDiagnosisAdapter: FormFieldValueAdapter = {
},
};
-const constructNewDiagnosis = (value: any, field: FormField, patientUuid: string) => {
+const constructNewDiagnosis = (value: string, field: FormField, patientUuid: string) => {
if (!value) {
return null;
}
@@ -86,7 +85,7 @@ const constructNewDiagnosis = (value: any, field: FormField, patientUuid: string
};
function editDiagnosis(
- newEncounterDiagnosis: any,
+ newEncounterDiagnosis: string,
field: FormField,
previousDiagnosis: OpenmrsResource,
patientUuid: string,
@@ -105,9 +104,13 @@ function editDiagnosis(
};
}
-export function hasPreviousDiagnosisValueChanged(previousDiagnosis: OpenmrsResource, newValue: any) {
+export function hasPreviousDiagnosisValueChanged(previousDiagnosis: OpenmrsResource, newValue: string) {
if (isEmpty(previousDiagnosis)) {
return false;
}
return previousDiagnosis.value !== newValue;
}
+
+export function voidDiagnosis(obs: OpenmrsObs) {
+ return { uuid: obs.uuid, voided: true };
+}
diff --git a/src/form-engine.test.tsx b/src/form-engine.test.tsx
index 2af05c5a..a5e2b44c 100644
--- a/src/form-engine.test.tsx
+++ b/src/form-engine.test.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import dayjs from 'dayjs';
import userEvent from '@testing-library/user-event';
-import { act, cleanup, render, screen, within } from '@testing-library/react';
+import { act, cleanup, render, screen, waitFor, within } from '@testing-library/react';
import {
ExtensionSlot,
OpenmrsDatePicker,
@@ -44,14 +44,18 @@ import viralLoadStatusForm from '__mocks__/forms/rfe-forms/viral-load-status-for
import readOnlyValidationForm from '__mocks__/forms/rfe-forms/read-only-validation-form.json';
import jsExpressionValidationForm from '__mocks__/forms/rfe-forms/js-expression-validation-form.json';
import hidePagesAndSectionsForm from '__mocks__/forms/rfe-forms/hide-pages-and-sections-form.json';
+import diagnosisForm from '__mocks__/forms/rfe-forms/diagnosis-test-form.json';
import FormEngine from './form-engine.component';
import { type SessionMode } from './types';
+import { use } from 'i18next';
const patientUUID = '8673ee4f-e2ab-4077-ba55-4980f408773e';
const visit = mockVisit;
const formsResourcePath = when((url: string) => url.includes(`${restBaseUrl}/form/`));
const clobDataResourcePath = when((url: string) => url.includes(`${restBaseUrl}/clobdata/`));
+const conceptResourcePath = when((url: string) => url.includes(`${restBaseUrl}/concept/`));
+
global.ResizeObserver = require('resize-observer-polyfill');
const mockOpenmrsFetch = jest.mocked(openmrsFetch);
@@ -60,25 +64,56 @@ const mockUsePatient = jest.mocked(usePatient);
const mockUseSession = jest.mocked(useSession);
const mockOpenmrsDatePicker = jest.mocked(OpenmrsDatePicker);
-mockOpenmrsDatePicker.mockImplementation(({ id, labelText, value, onChange, isInvalid, invalidText }) => {
- return (
- <>
-
- {
- onChange(dayjs(evt.target.value).toDate());
- }}
- />
- {isInvalid && {invalidText}}
- >
- );
-});
+// mockOpenmrsDatePicker.mockImplementation(({ id, labelText, value, onChange, isInvalid, invalidText }) => {
+// return (
+// <>
+//
+// {
+// onChange(dayjs(evt.target.value).toDate());
+// }}
+// />
+// {isInvalid && {invalidText}}
+// >
+// );
+// });
when(mockOpenmrsFetch).calledWith(formsResourcePath).mockReturnValue({ data: demoHtsOpenmrsForm });
when(mockOpenmrsFetch).calledWith(clobDataResourcePath).mockReturnValue({ data: demoHtsForm });
+jest.mock('./registry/registry', () => {
+ const originalModule = jest.requireActual('./registry/registry');
+ return {
+ ...originalModule,
+ getRegisteredDataSource: jest.fn().mockResolvedValue({
+ fetchData: jest.fn().mockImplementation((...args) => {
+ if (args[1].class?.length && !args[1].referencedValue.key) {
+ // concept DS
+ return Promise.resolve([
+ {
+ uuid: 'stage-1-uuid',
+ display: 'stage 1',
+ },
+ {
+ uuid: 'stage-2-uuid',
+ display: 'stage 2',
+ },
+ ]);
+ }
+ }),
+ fetchSingleItem: jest.fn().mockImplementation((uuid: string) => {
+ return Promise.resolve({
+ uuid,
+ display: 'stage 1',
+ });
+ }),
+ toUuidAndDisplay: (data) => data,
+ }),
+ };
+});
+
jest.mock('../src/api', () => {
const originalModule = jest.requireActual('../src/api');
@@ -1047,6 +1082,77 @@ describe('Form engine component', () => {
});
});
+ describe('Diagnisis field', () => {
+ it('should test addition of a diagnosis', async () => {
+ await act(async () => {
+ renderForm(null, diagnosisForm);
+ });
+ const addButtons = screen.getAllByRole('button', { name: 'Add' });
+ expect(addButtons.length).toBeGreaterThan(0);
+ await user.click(addButtons[0]);
+ expect(screen.getByRole('button', { name: /Remove/i })).toBeInTheDocument();
+ expect(screen.getAllByRole('combobox', { name: /^test diagnosis 1$/i }).length).toEqual(2);
+ });
+
+ it('should render diagnosis field', async () => {
+ await act(async () => {
+ renderForm(null, diagnosisForm);
+ });
+ const initialDiagnosis = screen.getAllByRole('combobox', { name: /test diagnosis 1|test diagnosis 2/i });
+ expect(initialDiagnosis.length).toBe(2);
+ });
+
+ it('should save diagnosis field on form submission', async () => {
+ await act(async () => {
+ renderForm(null, diagnosisForm);
+ });
+ const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
+
+ const combobox = await screen.findByRole('combobox', { name: /test diagnosis 1/i });
+ expect(combobox).toBeInTheDocument();
+
+ await userEvent.click(combobox);
+ await waitFor(() => {
+ expect(screen.getByText('stage 1')).toBeInTheDocument();
+ expect(screen.getByText('stage 2')).toBeInTheDocument();
+ });
+ await user.click(screen.getByText('stage 1'));
+ await user.click(screen.getByRole('button', { name: /save/i }));
+ expect(saveEncounterMock).toHaveBeenCalledTimes(1);
+ const [_, encounter] = saveEncounterMock.mock.calls[0];
+ expect(encounter.diagnoses.length).toBe(1);
+ expect(encounter.diagnoses[0]).toEqual({
+ patient: '8673ee4f-e2ab-4077-ba55-4980f408773e',
+ condition: null,
+ diagnosis: {
+ coded: 'stage-1-uuid',
+ },
+ certainty: 'CONFIRMED',
+ rank: 1,
+ formFieldPath: `rfe-forms-diagnosis1`,
+ formFieldNamespace: 'rfe-forms',
+ });
+ });
+
+ it('should test removing of a diagnosis field', async () => {
+ await act(async () => {
+ renderForm(null, diagnosisForm);
+ });
+
+ const addButtons = screen.getAllByRole('button', { name: 'Add' });
+ expect(addButtons.length).toBeGreaterThan(0);
+ await user.click(addButtons[0]);
+ expect(screen.getByRole('button', { name: /Remove/i })).toBeInTheDocument();
+ expect(screen.getAllByRole('combobox', { name: /^test diagnosis 1$/i }).length).toEqual(2);
+
+ const removeButton = screen.getByRole('button', { name: /Remove/i });
+
+ await user.click(removeButton);
+
+ expect(removeButton).not.toBeInTheDocument();
+ });
+ });
+
function renderForm(formUUID, formJson, intent?: string, mode?: SessionMode) {
render(