diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx
index cb547bbe8..ea999d6ab 100644
--- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx
+++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx
@@ -5,6 +5,9 @@ import {
FormFields,
PRACTITIONER_USER_TYPE_CODE,
SUPERVISOR_USER_TYPE_CODE,
+ commonFhirFields,
+ userTypeField,
+ FormFieldsKey,
} from '@opensrp/user-management';
import {
practitionerResourceType,
@@ -356,13 +359,20 @@ export const practitionerUpdater =
* @param props - component props
*/
export function CreateEditUser(props: CreateEditPropTypes) {
- const extraFormFields = getConfig('projectCode') === 'giz' ? renderExtraFields : [];
+ let renderFormFields: FormFieldsKey[] = [...commonFhirFields];
+ const projectCode = getConfig('projectCode');
+ if (projectCode === 'giz') {
+ renderFormFields = [...commonFhirFields, ...renderExtraFields] as FormFieldsKey[];
+ } else if (projectCode === 'eusm') {
+ renderFormFields = renderFormFields.filter((field) => field !== userTypeField);
+ }
+
const baseCompProps = {
...props,
getPractitionerFun: getPractitioner,
getPractitionerRoleFun: getPractitionerRole,
postPutPractitionerFactory: practitionerUpdater,
- extraFormFields: extraFormFields,
+ userFormRenderFields: renderFormFields,
};
return ;
diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx
index dbf7f6c4a..0b6452c25 100644
--- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx
+++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx
@@ -14,7 +14,7 @@ import { Provider } from 'react-redux';
import { store } from '@opensrp/store';
import nock from 'nock';
import { cleanup, fireEvent, render } from '@testing-library/react';
-import { waitFor } from '@testing-library/dom';
+import { waitFor, within } from '@testing-library/dom';
import { createMemoryHistory } from 'history';
import { authenticateUser } from '@onaio/session-reducer';
import fetch from 'jest-fetch-mock';
@@ -35,6 +35,9 @@ import { practitionerResourceType, practitionerRoleResourceType } from '../../..
import { fetchKeycloakUsers } from '@opensrp/user-management';
import { history } from '@onaio/connected-reducer-registry';
import { opensrpI18nInstance } from '@opensrp/i18n';
+import { setConfig } from '@opensrp/pkg-config';
+
+setConfig('projectCode', 'giz');
jest.mock('fhirclient', () => {
return jest.requireActual('fhirclient/lib/entry/browser');
@@ -245,11 +248,11 @@ test('renders correctly for edit user', async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(usernameInput!, 'flopo');
- // change mark as practitioner to tue
- const yesMarkPractitioner = document.querySelectorAll('input[name="active"]')[0];
+ const enabledFieldGroup = document.querySelector('#active') as HTMLElement;
+ const yesMarkPractitioner = within(enabledFieldGroup).getByRole('radio', { name: /yes/i });
userEvent.click(yesMarkPractitioner);
- const markSupervisor = document.querySelectorAll('input[name="userType"]')[1];
+ const markSupervisor = document.querySelector('input[value="supervisor"]') as HTMLElement;
userEvent.click(markSupervisor);
const submitButton = document.querySelector('button[type="submit"]');
diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts
index 1fa379374..44e99d670 100644
--- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts
+++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts
@@ -69,6 +69,7 @@ export const newPractitioner = {
name: [{ use: 'official', family: 'plotus', given: ['flotus', ''] }],
telecom: [{ system: 'email', value: 'flotus@plotus.duck' }],
};
+
export const newPractitionerRole = {
resourceType: 'PractitionerRole',
id: 'acb9d47e-7247-448f-be93-7a193a5312da',
@@ -88,7 +89,11 @@ export const newPractitionerRole = {
code: [
{
coding: [
- { system: 'http://snomed.info/sct', code: '236321002', display: 'Supervisor (occupation)' },
+ {
+ system: 'http://snomed.info/sct',
+ code: '405623001',
+ display: 'Assigned practitioner',
+ },
],
},
],
diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx
index 3338117e7..d534ecf2e 100644
--- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx
+++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx
@@ -230,7 +230,7 @@ test('renders correctly for edit user', async () => {
const yesMarkPractitioner = document.querySelectorAll('input[name="active"]')[0];
userEvent.click(yesMarkPractitioner);
- const markSupervisor = document.querySelectorAll('input[name="userType"]')[1];
+ const markSupervisor = document.querySelector('input[value="supervisor"]') as HTMLElement;
userEvent.click(markSupervisor);
const submitButton = document.querySelector('button[type="submit"]');
diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx
index 76ff2106b..387ffc797 100644
--- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx
+++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx
@@ -234,9 +234,6 @@ test('renders correctly for new user', async () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(usernameInput!, 'flopo');
- const markSupervisor = document.querySelectorAll('input[name="userType"]')[1];
- userEvent.click(markSupervisor);
-
const submitButton = document.querySelector('button[type="submit"]');
// find antd Select with id 'fhirCoreAppId' in the 'Form' component
diff --git a/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx b/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx
index 0becc1939..5e706b171 100644
--- a/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx
+++ b/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx
@@ -51,7 +51,6 @@ export interface CreateEditUserProps {
getPractitionerFun: (baseUrl: string, userId: string) => Promise;
getPractitionerRoleFun?: (baseUrl: string, userId: string) => Promise;
postPutPractitionerFactory: UserFormProps['practitionerUpdaterFactory'];
- extraFormFields: string[];
}
const getOpenSrpPractitioner = (baseUrl: string, userId: string) => {
@@ -95,7 +94,6 @@ const CreateEditUser: React.FC = (props: CreateEditPropType
getPractitionerFun,
postPutPractitionerFactory,
getPractitionerRoleFun,
- extraFormFields,
} = props;
const userId = props.match.params[ROUTE_PARAM_USER_ID];
@@ -215,8 +213,6 @@ const CreateEditUser: React.FC = (props: CreateEditPropType
hiddenFields={userFormHiddenFields}
renderFields={userFormRenderFields}
practitionerUpdaterFactory={postPutPractitionerFactory}
- isFHIRInstance={!!getPractitionerRoleFun}
- extraFormFields={extraFormFields}
/>
diff --git a/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap b/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap
index 5c473d90e..d1eddca9c 100644
--- a/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap
+++ b/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap
@@ -1,5 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`components/CreateEditUser loads edit user page without breaking if user is not a practitioner 1`] = `"Edit User | opensrpFirst NameLast NameEmailUsernameUser TypePractitionerSupervisorEnable userYesNoMark as PractitionerYesNoKeycloak User GroupAdminAdmin 2New GroupĀ Application IDSaveCancel"`;
+
exports[`components/CreateEditUser renders correctly 1`] = `
Object {
"children":
(
+ {children}
+);
+
jest.mock('@opensrp/store', () => {
const actualStore = jest.requireActual('@opensrp/store');
return {
@@ -119,11 +126,13 @@ describe('components/CreateEditUser', () => {
fetch.mockResponseOnce(JSON.stringify(requiredActions));
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
await act(async () => {
@@ -159,11 +168,13 @@ describe('components/CreateEditUser', () => {
.once(JSON.stringify(practitioner1));
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
await act(async () => {
@@ -193,9 +204,11 @@ describe('components/CreateEditUser', () => {
fetch.mockResponseOnce(JSON.stringify(keycloakUser));
const wrapper = mount(
-
-
-
+
+
+
+
+
);
expect(wrapper.exists('.ant-spin')).toBeTruthy();
@@ -239,11 +252,13 @@ describe('components/CreateEditUser', () => {
};
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
// Loader should be displayed
@@ -330,9 +345,11 @@ describe('components/CreateEditUser', () => {
const wrapper = mount(
-
-
-
+
+
+
+
+
);
@@ -345,8 +362,7 @@ describe('components/CreateEditUser', () => {
});
expect(toJson(wrapper.find('.ant-spin'))).toBeFalsy();
// eslint-disable-next-line no-irregular-whitespace
- const newLocal = `"Edit User | opensrpFirst NameLast NameEmailUsernameEnable userYesNoMark as PractitionerYesNoKeycloak User GroupAdminAdmin 2New GroupĀ SaveCancel"`;
- expect(wrapper.text()).toMatchInlineSnapshot(newLocal);
+ expect(wrapper.text()).toMatchSnapshot();
wrapper.unmount();
});
@@ -376,11 +392,13 @@ describe('components/CreateEditUser', () => {
};
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
await act(async () => {
@@ -408,11 +426,13 @@ describe('components/CreateEditUser', () => {
);
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
await act(async () => {
@@ -438,11 +458,13 @@ describe('components/CreateEditUser', () => {
.once(JSON.stringify(requiredActions));
const wrapper = mount(
-
-
-
-
-
+
+
+
+
+
+
+
);
expect(wrapper.exists('.ant-spin')).toBeTruthy();
diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx b/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx
index 891aba897..9f7b4e2a7 100644
--- a/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx
+++ b/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx
@@ -12,21 +12,23 @@ import {
} from './utils';
import { sendErrorNotification } from '@opensrp/notifications';
import '../../../index.css';
-import {
- CONTACT_FORM_FIELD,
- FormFields,
- FormFieldsKey,
- SelectOption,
- UserFormProps,
-} from './types';
+import { FormFields, FormFieldsKey, SelectOption, UserFormProps } from './types';
import { SelectProps } from 'antd/lib/select';
import { useTranslation } from '../../../mls';
import {
compositionResourceType,
+ emailField,
+ enabledField,
+ fhirCoreAppIdField,
+ firstNameField,
+ lastNameField,
NATIONAL_ID_FORM_FIELD,
PHONE_NUMBER_FORM_FIELD,
PRACTITIONER,
SUPERVISOR,
+ userGroupsField,
+ usernameField,
+ userTypeField,
} from '../../../constants';
import { PaginatedAsyncSelect } from '@opensrp/react-utils';
import { IComposition } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IComposition';
@@ -41,10 +43,13 @@ const UserForm: FC = (props: UserFormProps) => {
userGroups,
renderFields,
hiddenFields,
- isFHIRInstance,
- extraFormFields,
} = props;
- const shouldRender = (fieldName: FormFieldsKey) => !!renderFields?.includes(fieldName);
+ const shouldRender = (fieldName: FormFieldsKey) => {
+ if (renderFields === undefined) {
+ return true;
+ }
+ return !!renderFields.includes(fieldName);
+ };
const isHidden = (fieldName: FormFieldsKey) => !!hiddenFields?.includes(fieldName);
const { t } = useTranslation();
@@ -147,26 +152,35 @@ const UserForm: FC = (props: UserFormProps) => {
.finally(() => setSubmitting(false));
}}
>
-
-
-
-
-
-
- {extraFormFields.includes(NATIONAL_ID_FORM_FIELD) && (
+ {shouldRender(firstNameField) ? (
+
+
+
+ ) : null}
+
+ {shouldRender(lastNameField) ? (
+
+
+
+ ) : null}
+
+ {shouldRender(NATIONAL_ID_FORM_FIELD) ? (
= (props: UserFormProps) => {
>
- )}
- {extraFormFields.includes(PHONE_NUMBER_FORM_FIELD) && (
+ ) : null}
+
+ {shouldRender(PHONE_NUMBER_FORM_FIELD) ? (
= (props: UserFormProps) => {
>
- )}
-
-
-
-
-
-
+ ) : null}
- {shouldRender(CONTACT_FORM_FIELD) ? (
+ {shouldRender(emailField) ? (
+
+
+
+ ) : null}
+
+ {shouldRender(usernameField) ? (
-
+
) : null}
- {isFHIRInstance ? (
-
+ {shouldRender(userTypeField) ? (
+
) : null}
-
+
setUserEnabled(e.target.value)}
>
- {initialValues.id && initialValues.id !== extraData.user_id ? (
-
+ {initialValues.id &&
+ initialValues.id !== extraData.user_id &&
+ shouldRender('active') ? (
+
{status.map((e) => (
= (props: UserFormProps) => {
) : null}
-
-
-
+ {shouldRender(userGroupsField) ? (
+
+
+
+ ) : null}
- {isFHIRInstance ? (
+ {shouldRender(fhirCoreAppIdField) ? (
`;
-exports[`components/forms/UserForm form validation works for contact field: contact input 1`] = `
-
-`;
-
-exports[`components/forms/UserForm form validation works for contact field: contact label 1`] = `
-
-`;
-
exports[`components/forms/UserForm renders correctly: email input 1`] = `
,
+ "hidden": false,
"id": "practitionerToggle",
"label": "Mark as Practitioner",
"name": "active",
@@ -230,6 +203,7 @@ Object {
No
,
+ "hidden": false,
"id": "practitionerToggle",
"label": "Mark as Practitioner",
"name": "active",
diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.test.tsx b/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.test.tsx
index a3e06a4fa..124cdbfd6 100644
--- a/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.test.tsx
+++ b/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.test.tsx
@@ -1,4 +1,4 @@
-import { mount, shallow } from 'enzyme';
+import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import flushPromises from 'flush-promises';
import React from 'react';
@@ -6,7 +6,7 @@ import fetch from 'jest-fetch-mock';
import { history } from '@onaio/connected-reducer-registry';
import { store } from '@opensrp/store';
import { authenticateUser } from '@onaio/session-reducer';
-import { defaultUserFormInitialValues, UserForm } from '..';
+import { commonFhirFields, defaultUserFormInitialValues, UserForm } from '..';
import {
keycloakUser,
practitioner1,
@@ -17,14 +17,17 @@ import {
import { act } from 'react-dom/test-utils';
import { OPENSRP_API_BASE_URL } from '@opensrp/server-service';
import { Router } from 'react-router';
-import { Form } from 'antd';
-import { URL_USER } from '../../../../constants';
+import { fhirCoreAppIdField, URL_USER } from '../../../../constants';
import { UserFormProps } from '../types';
import { getFormValues, postPutPractitioner } from '../utils';
+import { QueryClientProvider, QueryClient } from 'react-query';
import { Dictionary } from '@onaio/utils/dist/types/types';
+import { render, waitFor, screen } from '@testing-library/react';
/* eslint-disable @typescript-eslint/naming-convention */
+const client = new QueryClient();
+
const mockId = '0b3a3311-6f5a-40dd-95e5-008001acebe1';
jest.mock('uuid', () => {
@@ -56,7 +59,9 @@ jest.mock('antd', () => {
});
describe('components/forms/UserForm', () => {
+ const nonFhirFields = commonFhirFields.filter((field) => field !== fhirCoreAppIdField);
const props: UserFormProps = {
+ renderFields: nonFhirFields,
initialValues: defaultUserFormInitialValues,
keycloakBaseURL: 'https://keycloak-stage.smartregister.org/auth/admin/realms/opensrp-web-stage',
baseUrl: OPENSRP_API_BASE_URL,
@@ -89,12 +94,12 @@ describe('components/forms/UserForm', () => {
fetch.resetMocks();
});
- it('renders without crashing', () => {
- shallow();
- });
-
it('renders correctly', async () => {
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
await act(async () => {
await flushPromises();
wrapper.update();
@@ -118,14 +123,15 @@ describe('components/forms/UserForm', () => {
expect(toJson(wrapper.find('#userGroups label'))).toMatchSnapshot(`userGroups label`);
expect(toJson(wrapper.find('#userGroups input'))).toMatchSnapshot(`userGroups input`);
- // not found, not rendered in props
- expect(toJson(wrapper.find('#contact label'))).toMatchInlineSnapshot(`null`);
- expect(toJson(wrapper.find('#contact input'))).toMatchInlineSnapshot(`null`);
wrapper.unmount();
});
it('form validation works for required fields', async () => {
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
wrapper.find('form').simulate('submit');
@@ -147,95 +153,14 @@ describe('components/forms/UserForm', () => {
wrapper.unmount();
});
- it('hidden fields', async () => {
+ it('adds user', async () => {
const wrapper = mount(
-
+
+ {' '}
+
+
);
- expect(wrapper.find('FormItemInput#contact').prop('hidden')).toBeTruthy();
- wrapper.unmount();
- });
-
- it('form validation works for contact field', async () => {
- const wrapper1 = mount();
-
- // found
- expect(toJson(wrapper1.find('#contact label'))).toMatchSnapshot('contact label');
- expect(toJson(wrapper1.find('#contact input'))).toMatchSnapshot('contact input');
-
- // empty error message; contact is required
- await act(async () => {
- wrapper1.find('form').simulate('submit');
- await flushPromises();
- });
-
- wrapper1.update();
-
- expect(wrapper1.find('FormItemInput#contact').prop('errors')).toEqual(['Contact is required']);
-
- const wrapper2 = mount();
-
- // regex validation
- wrapper2
- .find('input#contact')
- .simulate('change', { target: { name: 'contact', value: 'Test' } });
-
- await act(async () => {
- wrapper2.find('form').simulate('submit');
- await flushPromises();
- });
-
- wrapper2.update();
-
- expect(wrapper2.find('FormItemInput#contact').prop('errors')).toEqual([
- 'Contact should be 10 digits and start with 0',
- ]);
-
- const wrapper3 = mount();
-
- // regex validation more than 10 alphanumerics
- wrapper3
- .find('input#contact')
- .simulate('change', { target: { name: 'contact', value: '012345678910' } });
-
- await act(async () => {
- wrapper3.find('form').simulate('submit');
- await flushPromises();
- });
-
- wrapper3.update();
-
- expect(wrapper3.find('FormItemInput#contact').prop('errors')).toEqual([
- 'Contact should be 10 digits and start with 0',
- ]);
-
- const wrapper4 = mount();
-
- // should now not have an error.
- wrapper4
- .find('input#contact')
- .simulate('change', { target: { name: 'contact', value: '0123456789' } });
-
- await act(async () => {
- wrapper4.find('form').simulate('submit');
- await flushPromises();
- });
-
- wrapper4.update();
-
- await act(async () => {
- expect(wrapper4.find('FormItemInput#contact').prop('errors')).toEqual([]);
- });
-
- wrapper1.unmount();
- wrapper2.unmount();
- wrapper3.unmount();
- wrapper4.unmount();
- });
-
- it('adds user', async () => {
- const wrapper = mount();
-
await act(async () => {
await flushPromises();
wrapper.update();
@@ -261,9 +186,10 @@ describe('components/forms/UserForm', () => {
target: { value: ['UPDATE_PASSWORD'] },
});
- wrapper
- .find('input#contact')
- .simulate('change', { target: { name: 'contact', value: '0123456789' } });
+ await act(async () => {
+ await flushPromises();
+ wrapper.update();
+ });
wrapper.find('form').simulate('submit');
@@ -279,9 +205,6 @@ describe('components/forms/UserForm', () => {
username: 'TestOne',
email: 'testone@gmail.com',
enabled: true,
- attributes: {
- contact: ['0123456789'],
- },
});
expect(fetch.mock.calls[0]).toMatchObject([
'https://keycloak-stage.smartregister.org/auth/admin/realms/opensrp-web-stage/users',
@@ -304,7 +227,11 @@ describe('components/forms/UserForm', () => {
...props,
initialValues: getFormValues(keycloakUser),
};
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
await act(async () => {
await flushPromises();
@@ -343,65 +270,13 @@ describe('components/forms/UserForm', () => {
]);
});
- it('render correct value for enabled when set to true', async () => {
- const wrapper = mount();
-
- await act(async () => {
- await flushPromises();
- wrapper.update();
- });
-
- await act(async () => {
- wrapper
- .find('input[name="enabled"]')
- .first()
- .simulate('change', { target: { name: 'enabled', checked: true } });
- });
- wrapper.update();
- wrapper.find('form').simulate('submit');
-
- await act(async () => {
- wrapper.update();
- });
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const formInstance = (wrapper.find(Form).props() as any).form;
-
- expect(formInstance.getFieldsValue().enabled).toEqual(true);
- wrapper.unmount();
- });
-
- it('render correct value for enabled when set to false', async () => {
- const wrapper = mount();
-
- await act(async () => {
- await flushPromises();
- wrapper.update();
- });
-
- await act(async () => {
- wrapper
- .find('input[name="enabled"]')
- .last()
- .simulate('change', { target: { name: 'enabled', checked: false } });
- });
- wrapper.update();
- wrapper.find('form').simulate('submit');
-
- await act(async () => {
- wrapper.update();
- });
-
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const formInstance = (wrapper.find(Form).props() as any).form;
-
- expect(formInstance.getFieldsValue().enabled).toEqual(false);
- wrapper.unmount();
- });
-
it('user is not created if api is down', async () => {
fetch.mockReject(new Error('API is down'));
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
await act(async () => {
await flushPromises();
@@ -440,7 +315,11 @@ describe('components/forms/UserForm', () => {
...props,
initialValues: getFormValues(keycloakUser),
};
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
await act(async () => {
await flushPromises();
@@ -466,7 +345,9 @@ describe('components/forms/UserForm', () => {
it('cancel button returns user to admin page', async () => {
const wrapper = mount(
-
+
+
+
);
@@ -488,7 +369,11 @@ describe('components/forms/UserForm', () => {
...props,
initialValues: keycloakUser,
};
- const wrapper = mount();
+ const wrapper = mount(
+
+
+
+ );
await act(async () => {
await flushPromises();
@@ -508,7 +393,9 @@ describe('components/forms/UserForm', () => {
const wrapper = mount(
-
+
+
+
);
@@ -531,7 +418,9 @@ describe('components/forms/UserForm', () => {
const wrapper = mount(
-
+
+
+
);
@@ -554,7 +443,9 @@ describe('components/forms/UserForm', () => {
const wrapper = mount(
-
+
+
+
);
@@ -566,90 +457,42 @@ describe('components/forms/UserForm', () => {
});
it('updates form data when user to edit changes', async () => {
- // start with first user
+ // Start with first user
const propsFirstUser = {
...props,
initialValues: getFormValues(FirstUser),
};
- const wrapper = mount();
+ const { rerender } = render(
+
+
+
+ );
- await act(async () => {
- await flushPromises();
- wrapper.update();
+ // Wait for initial render and check initial values
+ await waitFor(() => {
+ expect(screen.getByLabelText(/first name/i)).toHaveValue(FirstUser.firstName);
+ expect(screen.getByLabelText(/email/i)).toHaveValue(FirstUser.email);
+ expect(screen.getByLabelText(/username/i)).toHaveValue(FirstUser.username);
});
- expect(wrapper.find('input#firstName').props().value).toEqual(FirstUser.firstName);
- expect(wrapper.find('input#email').props().value).toEqual(FirstUser.email);
- expect(wrapper.find('input#username').props().value).toEqual(FirstUser.username);
-
- // update user
- wrapper.setProps({ initialValues: keycloakUser });
- // re-render
- wrapper.update();
-
- expect(wrapper.find('input#firstName').props().value).toEqual(keycloakUser.firstName);
- expect(wrapper.find('input#email').props().value).toEqual(keycloakUser.email);
- expect(wrapper.find('input#username').props().value).toEqual(keycloakUser.username);
- });
-
- it('disables and toggles practitioner off when toggling active user off', async () => {
- const propsOwn = {
+ // Update props with the new user data and rerender
+ const propsUpdatedUser = {
...props,
- practitioner: practitioner1,
- // mount with both user and practitioner enabled
- initialValues: getFormValues(
- { ...keycloakUser, enabled: true },
- { ...practitioner1, active: true }
- ),
+ initialValues: getFormValues(keycloakUser),
};
- const wrapper = mount(
-
-
-
+ rerender(
+
+
+
);
- await act(async () => {
- await flushPromises();
- wrapper.update();
- });
-
- // user enabled checkbox
- const userEnabled = wrapper.find('input[name="enabled"]');
- // expect 'yes' and 'no' options
- expect(userEnabled).toHaveLength(2);
- // 'yes' to be checked and 'no' to be unchecked (active user)
- expect(userEnabled.at(0).props().checked).toEqual(true);
- expect(userEnabled.at(1).props().checked).toEqual(false);
-
- // practitioner active checkbox
- const practitionerActive = wrapper.find('input[name="active"]');
- // 'yes' and 'no' options
- expect(practitionerActive).toHaveLength(2);
- // 'yes' to be checked and 'no' to be unchecked (practitioner active)
- expect(practitionerActive.at(0).props().checked).toEqual(true);
- expect(practitionerActive.at(1).props().checked).toEqual(false);
- // practitioner not disabled
- wrapper.find('Radio[name="active"]').forEach((node) => {
- expect(node.props().disabled).toBe(false);
- });
-
- // simulate toggle user off
- userEnabled.at(1).simulate('change', { target: { checked: true } });
-
- // re-select
- const userEnabled2 = wrapper.find('input[name="enabled"]');
- const practitionerActive2 = wrapper.find('input[name="active"]');
-
- // expect user toggled off
- expect(userEnabled2.at(0).props().checked).toEqual(false);
- expect(userEnabled2.at(1).props().checked).toEqual(true);
- // expect practitioner toggle off and disabled
- expect(practitionerActive2.at(0).props().checked).toEqual(false);
- expect(practitionerActive2.at(1).props().checked).toEqual(true);
- wrapper.find('Radio[name="active"]').forEach((node) => {
- expect(node.props().disabled).toBe(true);
+ // Wait for the form to update with the new values
+ await waitFor(() => {
+ expect(screen.getByLabelText(/first name/i)).toHaveValue(keycloakUser.firstName);
+ expect(screen.getByLabelText(/email/i)).toHaveValue(keycloakUser.email);
+ expect(screen.getByLabelText(/username/i)).toHaveValue(keycloakUser.username);
});
});
});
diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.unmocked.test.tsx b/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.unmocked.test.tsx
index 62c5eca07..f06539411 100644
--- a/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.unmocked.test.tsx
+++ b/packages/keycloak-user-management/src/components/forms/UserForm/tests/index.unmocked.test.tsx
@@ -2,7 +2,7 @@ import { mount } from 'enzyme';
import flushPromises from 'flush-promises';
import React from 'react';
import { history } from '@onaio/connected-reducer-registry';
-import { defaultUserFormInitialValues, UserForm } from '..';
+import { commonFhirFields, defaultUserFormInitialValues, UserForm } from '..';
import { compositionPage1, createdUser, keycloakUser, practitioner1, userGroup } from './fixtures';
import { act } from 'react-dom/test-utils';
import { OPENSRP_API_BASE_URL } from '@opensrp/server-service';
@@ -20,11 +20,13 @@ import {
render,
waitFor,
waitForElementToBeRemoved,
+ within,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { compositionUrlFilter } from '../utils';
import { CreateEditUser } from '../../../CreateEditUser';
import * as notifications from '@opensrp/notifications';
+import { createMemoryHistory } from 'history';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fetch = require('node-fetch');
@@ -102,9 +104,11 @@ describe('forms/userForm', () => {
};
const wrapper = mount(
-
-
-
+
+
+
+
+
);
await act(async () => {
@@ -147,6 +151,7 @@ describe('forms/userForm', () => {
// mount with both user and practitioner enabled
initialValues: getFormValues(),
isFHIRInstance: true,
+ renderFields: commonFhirFields,
};
nock(propsOwn.baseUrl)
@@ -221,4 +226,70 @@ describe('forms/userForm', () => {
expect(nock.pendingMocks()).toHaveLength(0);
});
+
+ it('disables and toggles practitioner off when toggling active user off', async () => {
+ const history = createMemoryHistory();
+ const propsOwn = {
+ ...props,
+ practitioner: practitioner1,
+ // mount with both user and practitioner enabled
+ initialValues: getFormValues(
+ { ...keycloakUser, enabled: true },
+ { ...practitioner1, active: true }
+ ),
+ };
+
+ render(
+
+
+
+
+
+ );
+
+ await waitFor(() => {
+ const enabledFieldGroup = document.querySelector('#enabled') as HTMLElement;
+
+ const enabledYesRadio = within(enabledFieldGroup).getByRole('radio', { name: /yes/i });
+ const enabledNoRadio = within(enabledFieldGroup).getByRole('radio', { name: /no/i });
+
+ expect(enabledYesRadio).toBeChecked();
+ expect(enabledNoRadio).not.toBeChecked();
+
+ const activeFieldGroup = document.querySelector('#active') as HTMLElement;
+
+ const activeYesRadio = within(activeFieldGroup).getByRole('radio', { name: /yes/i });
+ const activeNoRadio = within(activeFieldGroup).getByRole('radio', { name: /no/i });
+
+ expect(activeYesRadio).toBeChecked();
+ expect(activeNoRadio).not.toBeChecked();
+ expect(activeNoRadio).not.toBeDisabled();
+ expect(activeYesRadio).not.toBeDisabled();
+ });
+
+ const enabledFieldGroup = document.querySelector('#enabled') as HTMLElement;
+ const enabledNoRadio = within(enabledFieldGroup).getByRole('radio', { name: /no/i });
+
+ userEvent.click(enabledNoRadio);
+
+ await waitFor(() => {
+ const enabledFieldGroup = document.querySelector('#enabled') as HTMLElement;
+
+ const enabledYesRadio = within(enabledFieldGroup).getByRole('radio', { name: /yes/i });
+ const enabledNoRadio = within(enabledFieldGroup).getByRole('radio', { name: /no/i });
+
+ expect(enabledYesRadio).not.toBeChecked();
+ expect(enabledNoRadio).toBeChecked();
+
+ const activeFieldGroup = document.querySelector('#active') as HTMLElement;
+
+ const activeYesRadio = within(activeFieldGroup).getByRole('radio', { name: /yes/i });
+ const activeNoRadio = within(activeFieldGroup).getByRole('radio', { name: /no/i });
+
+ expect(activeYesRadio).not.toBeChecked();
+ expect(activeNoRadio).toBeChecked();
+ expect(activeNoRadio).toBeDisabled();
+ expect(activeYesRadio).toBeDisabled();
+ });
+ });
});
diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/types.ts b/packages/keycloak-user-management/src/components/forms/UserForm/types.ts
index 1d35e460f..75f16bab1 100644
--- a/packages/keycloak-user-management/src/components/forms/UserForm/types.ts
+++ b/packages/keycloak-user-management/src/components/forms/UserForm/types.ts
@@ -3,7 +3,13 @@ import { Dictionary } from '@onaio/utils';
import { IPractitioner } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IPractitioner';
import { TFunction } from '@opensrp/i18n';
import { IPractitionerRole } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IPractitionerRole';
-import { PRACTITIONER, SUPERVISOR } from '../../../constants';
+import {
+ fhirCoreAppIdField,
+ PRACTITIONER,
+ SUPERVISOR,
+ userGroupsField,
+ userTypeField,
+} from '../../../constants';
export interface FormFields
extends Pick<
@@ -18,13 +24,12 @@ export interface FormFields
| 'enabled'
> {
active?: boolean;
- userType?: typeof PRACTITIONER | typeof SUPERVISOR;
- userGroups?: string[];
+ [userTypeField]?: typeof PRACTITIONER | typeof SUPERVISOR;
+ [userGroupsField]?: string[];
practitioner?: Practitioner | IPractitioner;
keycloakUser?: KeycloakUser;
- contact?: string;
practitionerRole?: IPractitionerRole;
- fhirCoreAppId?: string;
+ [fhirCoreAppIdField]?: string;
}
export type FormFieldsKey = keyof FormFields | keyof UserAttributes;
@@ -45,8 +50,6 @@ export interface UserFormProps {
hiddenFields?: FormFieldsKey[];
renderFields?: FormFieldsKey[];
practitionerUpdaterFactory: PractitionerUpdaterFactory;
- isFHIRInstance: boolean;
- extraFormFields: string[];
}
/** descibes antd select component options */
diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/utils.tsx b/packages/keycloak-user-management/src/components/forms/UserForm/utils.tsx
index de2811be1..8d3dd3675 100644
--- a/packages/keycloak-user-management/src/components/forms/UserForm/utils.tsx
+++ b/packages/keycloak-user-management/src/components/forms/UserForm/utils.tsx
@@ -254,7 +254,6 @@ export const getFormValues = (
}
const { id, username, firstName, lastName, email, enabled } = keycloakUser;
const {
- contact: contacts,
fhir_core_app_id: fhirCoreAppId,
nationalId = '',
phoneNumber = '',
@@ -285,7 +284,6 @@ export const getFormValues = (
email,
username,
enabled,
- contact: contacts?.[0],
active,
userType,
practitioner,
@@ -315,11 +313,9 @@ export const getUserAndGroupsPayload = (values: FormFields) => {
phoneNumber,
email,
enabled,
- contact,
fhirCoreAppId,
} = values;
const preUserAttributes = {
- ...(contact ? { contact: [contact] } : {}),
...(fhirCoreAppId ? { fhir_core_app_id: [fhirCoreAppId] } : {}),
...(nationalId ? { nationalId: [nationalId] } : {}),
...(phoneNumber ? { phoneNumber: [phoneNumber] } : {}),
diff --git a/packages/keycloak-user-management/src/constants.ts b/packages/keycloak-user-management/src/constants.ts
index f2f517279..1fbe311a1 100644
--- a/packages/keycloak-user-management/src/constants.ts
+++ b/packages/keycloak-user-management/src/constants.ts
@@ -46,5 +46,13 @@ export const SNOMED_CODEABLE_SYSTEM = 'http://snomed.info/sct';
export const DEVICE_SETTING_CODEABLE_CODE = '1156600005';
// Form field name
-export const NATIONAL_ID_FORM_FIELD = 'nationalId';
-export const PHONE_NUMBER_FORM_FIELD = 'phoneNumber';
+export const NATIONAL_ID_FORM_FIELD = 'nationalId' as const;
+export const PHONE_NUMBER_FORM_FIELD = 'phoneNumber' as const;
+export const firstNameField = 'firstName' as const;
+export const lastNameField = 'lastName' as const;
+export const emailField = 'email' as const;
+export const usernameField = 'username' as const;
+export const userTypeField = 'userType' as const;
+export const enabledField = 'enabled' as const;
+export const userGroupsField = 'userGroups' as const;
+export const fhirCoreAppIdField = 'fhirCoreAppId' as const;
diff --git a/packages/keycloak-user-management/src/index.tsx b/packages/keycloak-user-management/src/index.tsx
index bfc05645c..c50932fb1 100644
--- a/packages/keycloak-user-management/src/index.tsx
+++ b/packages/keycloak-user-management/src/index.tsx
@@ -6,6 +6,7 @@ export * from './components/CreateEditUser';
export * from './components/Credentials';
export * from './constants';
export * from './components/forms/UserForm/types';
+export * from './components/forms/UserForm';
export { getUserTypeCode, getUserType } from './components/forms/UserForm/utils';
export * from './ducks/user';
export * as UserGroupDucks from './ducks/userGroups';