@openmrs/esm-form-engine-lib 2.1.0-pre.1362

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc +58 -0
  4. package/.husky/pre-commit +6 -0
  5. package/.husky/pre-push +6 -0
  6. package/.prettierignore +4 -0
  7. package/LICENSE.txt +401 -0
  8. package/README.md +136 -0
  9. package/__mocks__/concepts.mock.json +140 -0
  10. package/__mocks__/forms/afe-forms/component_art.json +38 -0
  11. package/__mocks__/forms/afe-forms/component_preclinic-review.json +38 -0
  12. package/__mocks__/forms/afe-forms/demo_hts-form.json +62 -0
  13. package/__mocks__/forms/afe-forms/form-component.json +38 -0
  14. package/__mocks__/forms/afe-forms/mini-form.json +31 -0
  15. package/__mocks__/forms/afe-forms/nested-form1.json +38 -0
  16. package/__mocks__/forms/afe-forms/nested-form2.json +38 -0
  17. package/__mocks__/forms/afe-forms/test-orders.json +72 -0
  18. package/__mocks__/forms/afe-forms/test-schema-transformer-form.json +88 -0
  19. package/__mocks__/forms/rfe-forms/age-validation-form.json +58 -0
  20. package/__mocks__/forms/rfe-forms/bmi-test-form.json +69 -0
  21. package/__mocks__/forms/rfe-forms/bsa-test-form.json +69 -0
  22. package/__mocks__/forms/rfe-forms/component_art.json +1705 -0
  23. package/__mocks__/forms/rfe-forms/component_preclinic-review.json +480 -0
  24. package/__mocks__/forms/rfe-forms/conditional-answered-form.json +97 -0
  25. package/__mocks__/forms/rfe-forms/conditional-required-form.json +281 -0
  26. package/__mocks__/forms/rfe-forms/demo_hts-form.json +346 -0
  27. package/__mocks__/forms/rfe-forms/edd-test-form.json +88 -0
  28. package/__mocks__/forms/rfe-forms/external_data_source_form.json +43 -0
  29. package/__mocks__/forms/rfe-forms/filter-answer-options-test-form.json +87 -0
  30. package/__mocks__/forms/rfe-forms/form-component.json +43 -0
  31. package/__mocks__/forms/rfe-forms/forms-loader.test.schema.ts +209 -0
  32. package/__mocks__/forms/rfe-forms/historical-expressions-form.json +170 -0
  33. package/__mocks__/forms/rfe-forms/labour_and_delivery_test_form.json +374 -0
  34. package/__mocks__/forms/rfe-forms/mini-form.json +29 -0
  35. package/__mocks__/forms/rfe-forms/mockHistoricalvisitsEncounter.json +89 -0
  36. package/__mocks__/forms/rfe-forms/months-on-art-form.json +90 -0
  37. package/__mocks__/forms/rfe-forms/multi-select-form.json +86 -0
  38. package/__mocks__/forms/rfe-forms/nested-form1.json +43 -0
  39. package/__mocks__/forms/rfe-forms/nested-form2.json +43 -0
  40. package/__mocks__/forms/rfe-forms/next-visit-test-form.json +78 -0
  41. package/__mocks__/forms/rfe-forms/obs-group-test_form.json +137 -0
  42. package/__mocks__/forms/rfe-forms/obs-list-data.ts +37 -0
  43. package/__mocks__/forms/rfe-forms/post-submission-test-form.json +116 -0
  44. package/__mocks__/forms/rfe-forms/reference-by-mapping-form.json +54 -0
  45. package/__mocks__/forms/rfe-forms/required-form.json +50 -0
  46. package/__mocks__/forms/rfe-forms/sample_fields.json +36 -0
  47. package/__mocks__/forms/rfe-forms/test-enrolment-form.json +241 -0
  48. package/__mocks__/forms/rfe-forms/treatment-end-date-test-form.json +121 -0
  49. package/__mocks__/forms/rfe-forms/viral-load-status-form.json +75 -0
  50. package/__mocks__/forms/rfe-forms/zscore-bmi-for-age-form.json +79 -0
  51. package/__mocks__/forms/rfe-forms/zscore-height-for-age-form.json +79 -0
  52. package/__mocks__/forms/rfe-forms/zscore-weight-height-form.json +77 -0
  53. package/__mocks__/packages/hiv/forms/hts_poc/1.0.json +8 -0
  54. package/__mocks__/packages/hiv/forms/hts_poc/1.1.json +91 -0
  55. package/__mocks__/packages/test-forms-registry.ts +12 -0
  56. package/__mocks__/patient.mock.ts +173 -0
  57. package/__mocks__/react-i18next.js +49 -0
  58. package/__mocks__/react-markdown.tsx +5 -0
  59. package/__mocks__/session.mock.ts +117 -0
  60. package/__mocks__/single-spa-react.js +11 -0
  61. package/__mocks__/use-initial-values/encounter.mock.json +963 -0
  62. package/__mocks__/use-initial-values/patient.mock.json +73 -0
  63. package/__mocks__/visit.mock.ts +19 -0
  64. package/dist/openmrs-esm-form-engine-lib.js +1 -0
  65. package/jest.config.js +30 -0
  66. package/package.json +104 -0
  67. package/prettier.config.js +8 -0
  68. package/readme/form-engine.jpeg +0 -0
  69. package/src/adapters/control-adapter.ts +29 -0
  70. package/src/adapters/encounter-datetime-adapter.ts +38 -0
  71. package/src/adapters/encounter-location-adapter.ts +39 -0
  72. package/src/adapters/encounter-provider-adapter.ts +48 -0
  73. package/src/adapters/encounter-role-adapter.ts +54 -0
  74. package/src/adapters/inline-date-adapter.ts +58 -0
  75. package/src/adapters/obs-adapter.ts +280 -0
  76. package/src/adapters/obs-comment-adapter.ts +60 -0
  77. package/src/adapters/orders-adapter.ts +75 -0
  78. package/src/adapters/patient-identifier-adapter.ts +40 -0
  79. package/src/adapters/program-state-adapter.ts +52 -0
  80. package/src/api/index.ts +178 -0
  81. package/src/components/error/error-modal.component.tsx +37 -0
  82. package/src/components/error/error.scss +4 -0
  83. package/src/components/extension/extension-parcel.component.tsx +32 -0
  84. package/src/components/field-label/field-label.component.tsx +32 -0
  85. package/src/components/field-label/field-label.scss +11 -0
  86. package/src/components/group/obs-group.component.tsx +29 -0
  87. package/src/components/group/obs-group.scss +12 -0
  88. package/src/components/inputs/content-switcher/content-switcher.component.tsx +71 -0
  89. package/src/components/inputs/content-switcher/content-switcher.scss +55 -0
  90. package/src/components/inputs/date/date.component.tsx +149 -0
  91. package/src/components/inputs/date/date.scss +36 -0
  92. package/src/components/inputs/file/camera/camera.component.tsx +34 -0
  93. package/src/components/inputs/file/camera/camera.scss +3 -0
  94. package/src/components/inputs/file/file.component.tsx +159 -0
  95. package/src/components/inputs/file/file.scss +101 -0
  96. package/src/components/inputs/fixed-value/fixed-value.component.tsx +19 -0
  97. package/src/components/inputs/markdown/markdown-wrapper.component.tsx +14 -0
  98. package/src/components/inputs/markdown/markdown.component.tsx +8 -0
  99. package/src/components/inputs/multi-select/multi-select.component.tsx +151 -0
  100. package/src/components/inputs/multi-select/multi-select.scss +25 -0
  101. package/src/components/inputs/multi-select/multi-select.test.tsx +90 -0
  102. package/src/components/inputs/number/number.component.tsx +69 -0
  103. package/src/components/inputs/number/number.scss +15 -0
  104. package/src/components/inputs/radio/radio.component.tsx +79 -0
  105. package/src/components/inputs/radio/radio.scss +36 -0
  106. package/src/components/inputs/select/dropdown.component.tsx +73 -0
  107. package/src/components/inputs/select/dropdown.scss +11 -0
  108. package/src/components/inputs/select/dropdown.test.tsx +120 -0
  109. package/src/components/inputs/text/text.component.tsx +65 -0
  110. package/src/components/inputs/text/text.scss +15 -0
  111. package/src/components/inputs/text/text.test.tsx +104 -0
  112. package/src/components/inputs/text-area/text-area.component.tsx +63 -0
  113. package/src/components/inputs/text-area/text-area.scss +11 -0
  114. package/src/components/inputs/toggle/toggle.component.tsx +66 -0
  115. package/src/components/inputs/toggle/toggle.scss +12 -0
  116. package/src/components/inputs/tooltip/tooltip.component.tsx +23 -0
  117. package/src/components/inputs/tooltip/tooltip.scss +8 -0
  118. package/src/components/inputs/ui-select-extended/ui-select-extended.component.tsx +187 -0
  119. package/src/components/inputs/ui-select-extended/ui-select-extended.scss +15 -0
  120. package/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx +211 -0
  121. package/src/components/inputs/unspecified/unspecified.component.tsx +74 -0
  122. package/src/components/inputs/unspecified/unspecified.scss +7 -0
  123. package/src/components/inputs/unspecified/unspecified.test.tsx +95 -0
  124. package/src/components/inputs/workspace-launcher/workspace-launcher.component.tsx +35 -0
  125. package/src/components/inputs/workspace-launcher/workspace-launcher.scss +15 -0
  126. package/src/components/label/label.component.tsx +20 -0
  127. package/src/components/label/label.scss +11 -0
  128. package/src/components/loaders/loader.component.tsx +16 -0
  129. package/src/components/loaders/loader.scss +20 -0
  130. package/src/components/patient-banner/patient-banner.component.tsx +20 -0
  131. package/src/components/patient-banner/patient-banner.scss +12 -0
  132. package/src/components/previous-value-review/previous-value-review.component.tsx +49 -0
  133. package/src/components/previous-value-review/previous-value-review.scss +36 -0
  134. package/src/components/processor-factory/form-processor-factory.component.tsx +127 -0
  135. package/src/components/renderer/custom-hooks-renderer.component.tsx +30 -0
  136. package/src/components/renderer/field/fieldLogic.ts +214 -0
  137. package/src/components/renderer/field/form-field-renderer.component.tsx +281 -0
  138. package/src/components/renderer/field/form-field-renderer.scss +5 -0
  139. package/src/components/renderer/form/form-renderer.component.tsx +89 -0
  140. package/src/components/renderer/form/state.ts +54 -0
  141. package/src/components/renderer/page/page.renderer.component.tsx +50 -0
  142. package/src/components/renderer/page/page.renderer.scss +36 -0
  143. package/src/components/renderer/section/section-renderer.component.tsx +21 -0
  144. package/src/components/renderer/section/section-renderer.scss +19 -0
  145. package/src/components/repeat/helpers.test.ts +29 -0
  146. package/src/components/repeat/helpers.ts +68 -0
  147. package/src/components/repeat/repeat-controls.component.tsx +38 -0
  148. package/src/components/repeat/repeat-controls.scss +7 -0
  149. package/src/components/repeat/repeat.component.tsx +201 -0
  150. package/src/components/repeat/repeat.scss +30 -0
  151. package/src/components/repeat/repeat.test.ts +29 -0
  152. package/src/components/sidebar/sidebar.component.tsx +134 -0
  153. package/src/components/sidebar/sidebar.scss +121 -0
  154. package/src/components/value/value.component.tsx +27 -0
  155. package/src/components/value/value.scss +17 -0
  156. package/src/components/value/view/field-value-view.component.tsx +33 -0
  157. package/src/components/value/view/field-value-view.scss +31 -0
  158. package/src/constants.ts +12 -0
  159. package/src/datasources/concept-data-source.ts +42 -0
  160. package/src/datasources/data-source.ts +23 -0
  161. package/src/datasources/encounter-role-datasource.ts +15 -0
  162. package/src/datasources/historical-data-source.ts +11 -0
  163. package/src/datasources/location-data-source.ts +27 -0
  164. package/src/datasources/provider-datasource.ts +15 -0
  165. package/src/datasources/select-concept-answers-datasource.ts +15 -0
  166. package/src/declarations.d.ts +4 -0
  167. package/src/external-function-context.tsx +8 -0
  168. package/src/form-context.tsx +42 -0
  169. package/src/form-engine.component.tsx +178 -0
  170. package/src/form-engine.scss +140 -0
  171. package/src/form-engine.test.tsx +817 -0
  172. package/src/globals.ts +1 -0
  173. package/src/hooks/useClobData.tsx +21 -0
  174. package/src/hooks/useConcepts.tsx +55 -0
  175. package/src/hooks/useDatasourceDependentValue.ts +16 -0
  176. package/src/hooks/useEncounter.tsx +32 -0
  177. package/src/hooks/useEncounterRole.tsx +15 -0
  178. package/src/hooks/useEvaluateFormFieldExpressions.ts +138 -0
  179. package/src/hooks/useFieldValidationResults.ts +18 -0
  180. package/src/hooks/useFormCollapse.tsx +36 -0
  181. package/src/hooks/useFormFieldValidators.ts +22 -0
  182. package/src/hooks/useFormFieldValueAdapters.ts +24 -0
  183. package/src/hooks/useFormFields.ts +37 -0
  184. package/src/hooks/useFormFieldsMeta.ts +48 -0
  185. package/src/hooks/useFormJson.test.tsx +173 -0
  186. package/src/hooks/useFormJson.tsx +237 -0
  187. package/src/hooks/useFormStateHelpers.ts +50 -0
  188. package/src/hooks/useFormsConfig.tsx +27 -0
  189. package/src/hooks/useInitialValues.ts +38 -0
  190. package/src/hooks/usePatientData.tsx +32 -0
  191. package/src/hooks/usePatientPrograms.ts +32 -0
  192. package/src/hooks/usePostSubmissionActions.test.tsx +42 -0
  193. package/src/hooks/usePostSubmissionActions.ts +31 -0
  194. package/src/hooks/useProcessorDependencies.ts +30 -0
  195. package/src/hooks/useRestMaxResultsCount.ts +5 -0
  196. package/src/hooks/useSystemSetting.ts +36 -0
  197. package/src/hooks/useWorkspaceLayout.ts +29 -0
  198. package/src/index.ts +12 -0
  199. package/src/lifecycle.ts +33 -0
  200. package/src/post-submission-actions/program-enrollment-action.ts +138 -0
  201. package/src/processors/encounter/encounter-form-processor.ts +337 -0
  202. package/src/processors/encounter/encounter-processor-helper.ts +320 -0
  203. package/src/processors/form-processor.ts +41 -0
  204. package/src/provider/form-factory-helper.ts +100 -0
  205. package/src/provider/form-factory-provider.tsx +169 -0
  206. package/src/provider/form-provider.tsx +37 -0
  207. package/src/registry/inbuilt-components/InbuiltPostSubmissionActions.ts +9 -0
  208. package/src/registry/inbuilt-components/control-templates.ts +57 -0
  209. package/src/registry/inbuilt-components/inbuiltControls.ts +99 -0
  210. package/src/registry/inbuilt-components/inbuiltDataSources.ts +41 -0
  211. package/src/registry/inbuilt-components/inbuiltFieldValueAdapters.ts +64 -0
  212. package/src/registry/inbuilt-components/inbuiltTransformers.ts +10 -0
  213. package/src/registry/inbuilt-components/inbuiltValidators.ts +33 -0
  214. package/src/registry/inbuilt-components/template-component-map.ts +28 -0
  215. package/src/registry/registry.test.ts +20 -0
  216. package/src/registry/registry.ts +261 -0
  217. package/src/routes.json +1 -0
  218. package/src/setupI18n.ts +16 -0
  219. package/src/setupTests.ts +5 -0
  220. package/src/transformers/default-schema-transformer.test.ts +155 -0
  221. package/src/transformers/default-schema-transformer.ts +239 -0
  222. package/src/types/domain.ts +129 -0
  223. package/src/types/index.ts +130 -0
  224. package/src/types/schema.ts +238 -0
  225. package/src/typings.d.ts +9 -0
  226. package/src/utils/boolean-utils.ts +25 -0
  227. package/src/utils/common-expression-helpers.ts +503 -0
  228. package/src/utils/common-utils.test.ts +136 -0
  229. package/src/utils/common-utils.ts +55 -0
  230. package/src/utils/error-utils.ts +37 -0
  231. package/src/utils/expression-parser.test.ts +308 -0
  232. package/src/utils/expression-parser.ts +158 -0
  233. package/src/utils/expression-runner.test.ts +387 -0
  234. package/src/utils/expression-runner.ts +219 -0
  235. package/src/utils/form-helper.test.ts +482 -0
  236. package/src/utils/form-helper.ts +210 -0
  237. package/src/utils/form-page-utils.ts +13 -0
  238. package/src/utils/forms-loader.test.ts +323 -0
  239. package/src/utils/forms-loader.ts +306 -0
  240. package/src/utils/post-submission-action-helper.ts +71 -0
  241. package/src/utils/test-utils.ts +54 -0
  242. package/src/utils/zscore-service.ts +59 -0
  243. package/src/validators/conditional-answered-validator.test.ts +61 -0
  244. package/src/validators/conditional-answered-validator.ts +17 -0
  245. package/src/validators/date-validator.test.ts +46 -0
  246. package/src/validators/date-validator.ts +19 -0
  247. package/src/validators/default-value-validator.test.ts +90 -0
  248. package/src/validators/default-value-validator.ts +36 -0
  249. package/src/validators/form-validator.test.ts +188 -0
  250. package/src/validators/form-validator.ts +95 -0
  251. package/src/validators/js-expression-validator.test.ts +118 -0
  252. package/src/validators/js-expression-validator.ts +44 -0
  253. package/src/validators/schema.ts +34 -0
  254. package/src/zscore/bfa_boys_5_above.json +2522 -0
  255. package/src/zscore/bfa_girls_5_above.json +2522 -0
  256. package/src/zscore/hfa_boys_5_above.json +2186 -0
  257. package/src/zscore/hfa_boys_below5.json +22286 -0
  258. package/src/zscore/hfa_girls_5_above.json +2186 -0
  259. package/src/zscore/hfa_girls_below5.json +22286 -0
  260. package/src/zscore/wfl_boys_below5.json +7814 -0
  261. package/src/zscore/wfl_girls_below5.json +7814 -0
  262. package/src/zscore-tests/bmi-age.test.tsx +88 -0
  263. package/src/zscore-tests/height-age.test.tsx +96 -0
  264. package/src/zscore-tests/weight-height.test.tsx +87 -0
  265. package/tools/i18next-parser.config.js +93 -0
  266. package/translations/en.json +47 -0
  267. package/translations/es.json +38 -0
  268. package/translations/fr.json +38 -0
  269. package/translations/km.json +38 -0
  270. package/tsconfig.json +19 -0
  271. package/turbo.json +15 -0
  272. package/webpack.config.js +1 -0
@@ -0,0 +1,88 @@
1
+ import React from 'react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { act, render, screen } from '@testing-library/react';
4
+ import { type FetchResponse, openmrsFetch, usePatient, useSession } from '@openmrs/esm-framework';
5
+ import { mockPatientAge8 } from '__mocks__/patient.mock';
6
+ import { mockSessionDataResponse } from '__mocks__/session.mock';
7
+ import { mockVisit } from '__mocks__/visit.mock';
8
+ import bmiForAgeScoreTestSchema from '__mocks__/forms/rfe-forms/zscore-bmi-for-age-form.json';
9
+ import demoHtsForm from '__mocks__/forms/rfe-forms/demo_hts-form.json';
10
+ import demoHtsOpenmrsForm from '__mocks__/forms/afe-forms/demo_hts-form.json';
11
+ import FormEngine from '../form-engine.component';
12
+
13
+ global.ResizeObserver = require('resize-observer-polyfill');
14
+
15
+ const patientUUID = 'e13a8696-dc58-4b8c-ae40-2a1e7dd843e7';
16
+ const visit = mockVisit;
17
+
18
+ const mockOpenmrsFetch = jest.mocked(openmrsFetch);
19
+ const mockUsePatient = jest.mocked(usePatient);
20
+ const mockUseSession = jest.mocked(useSession);
21
+
22
+ jest.mock('../../src/api', () => {
23
+ const originalModule = jest.requireActual('../../src/api');
24
+
25
+ return {
26
+ ...originalModule,
27
+ getPreviousEncounter: jest.fn().mockImplementation(() => Promise.resolve(null)),
28
+ getConcept: jest.fn().mockImplementation(() => Promise.resolve(null)),
29
+ getLatestObs: jest.fn().mockImplementation(() => Promise.resolve({ valueNumeric: 60 })),
30
+ saveEncounter: jest.fn(),
31
+ };
32
+ });
33
+
34
+ describe.skip('bmiForAge z-score', () => {
35
+ beforeEach(() => {
36
+ mockUseSession.mockReturnValue(mockSessionDataResponse.data);
37
+
38
+ mockUsePatient.mockReturnValue({
39
+ isLoading: false,
40
+ patient: mockPatientAge8,
41
+ patientUuid: mockPatientAge8.id,
42
+ error: null,
43
+ });
44
+
45
+ mockOpenmrsFetch.mockResolvedValue({
46
+ data: {
47
+ results: [{ ...demoHtsOpenmrsForm }],
48
+ },
49
+ } as unknown as FetchResponse);
50
+
51
+ mockOpenmrsFetch.mockResolvedValue({
52
+ data: {
53
+ results: [{ ...demoHtsForm }],
54
+ },
55
+ } as unknown as FetchResponse);
56
+ });
57
+
58
+ it('should compute bmiForAge z-score from the provided height and weight values', async () => {
59
+ const user = userEvent.setup();
60
+
61
+ await act(async () => renderForm(null, bmiForAgeScoreTestSchema));
62
+
63
+ const bmiForAge = screen.getByRole('spinbutton', { name: /bmi for age zscore result/i });
64
+ const height = screen.getByRole('spinbutton', { name: /height/i });
65
+ const weight = screen.getByRole('spinbutton', { name: /weight/i });
66
+
67
+ await user.type(height, '100');
68
+ await user.type(weight, '45');
69
+ await user.tab();
70
+
71
+ expect(height).toHaveValue(100);
72
+ expect(weight).toHaveValue(45);
73
+ expect(bmiForAge).toHaveValue(4);
74
+ });
75
+ function renderForm(formUUID, formJson, intent?: string) {
76
+ return act(() => {
77
+ render(
78
+ <FormEngine
79
+ formJson={formJson}
80
+ formUUID={formUUID}
81
+ patientUUID={patientUUID}
82
+ formSessionIntent={intent}
83
+ visit={visit}
84
+ />,
85
+ );
86
+ });
87
+ }
88
+ });
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen, act } from '@testing-library/react';
4
+ import { type FetchResponse, openmrsFetch, usePatient, useSession } from '@openmrs/esm-framework';
5
+ import { mockPatientAge8 } from '__mocks__/patient.mock';
6
+ import { mockSessionDataResponse } from '__mocks__/session.mock';
7
+ import { mockVisit } from '__mocks__/visit.mock';
8
+ import demoHtsOpenmrsForm from '__mocks__/forms/afe-forms/demo_hts-form.json';
9
+ import demoHtsForm from '__mocks__/forms/rfe-forms/demo_hts-form.json';
10
+ import heightForAgeZscoreTestSchema from '__mocks__/forms/rfe-forms/zscore-height-for-age-form.json';
11
+ import FormEngine from '../form-engine.component';
12
+
13
+ global.ResizeObserver = require('resize-observer-polyfill');
14
+
15
+ const patientUUID = 'e13a8696-dc58-4b8c-ae40-2a1e7dd843e7';
16
+ const visit = mockVisit;
17
+
18
+ const mockOpenmrsFetch = jest.mocked(openmrsFetch);
19
+ const mockUsePatient = jest.mocked(usePatient);
20
+ const mockUseSession = jest.mocked(useSession);
21
+
22
+ jest.mock('../../src/api', () => {
23
+ const originalModule = jest.requireActual('../../src/api');
24
+
25
+ return {
26
+ ...originalModule,
27
+ getPreviousEncounter: jest.fn().mockImplementation(() => Promise.resolve(null)),
28
+ getConcept: jest.fn().mockImplementation(() => Promise.resolve(null)),
29
+ getLatestObs: jest.fn().mockImplementation(() => Promise.resolve({ valueNumeric: 60 })),
30
+ saveEncounter: jest.fn(),
31
+ };
32
+ });
33
+
34
+ describe.skip('heightForAge z-score', () => {
35
+ let globalSpy;
36
+
37
+ beforeEach(() => {
38
+ const mockedDate = new Date(2024, 4, 10);
39
+ globalSpy = jest.spyOn(global, 'Date').mockImplementation(() => mockedDate);
40
+
41
+ mockUseSession.mockReturnValue(mockSessionDataResponse.data);
42
+
43
+ mockUsePatient.mockReturnValue({
44
+ isLoading: false,
45
+ patient: mockPatientAge8,
46
+ patientUuid: mockPatientAge8.id,
47
+ error: null,
48
+ });
49
+
50
+ mockOpenmrsFetch.mockResolvedValue({
51
+ data: {
52
+ results: [{ ...demoHtsOpenmrsForm }],
53
+ },
54
+ } as unknown as FetchResponse);
55
+
56
+ mockOpenmrsFetch.mockResolvedValue({
57
+ data: {
58
+ results: [{ ...demoHtsForm }],
59
+ },
60
+ } as unknown as FetchResponse);
61
+ });
62
+
63
+ afterEach(() => {
64
+ globalSpy.mockRestore();
65
+ });
66
+
67
+ it('should compute heightForAge z-score from the provided height and weight values', async () => {
68
+ const user = userEvent.setup();
69
+
70
+ await act(async () => renderForm(null, heightForAgeZscoreTestSchema));
71
+
72
+ const heightForAgeZscore = screen.getByRole('spinbutton', { name: /height for age zscore result/i });
73
+ const height = screen.getByRole('spinbutton', { name: /^height \*$/i });
74
+ const weight = screen.getByRole('spinbutton', { name: /weight/i });
75
+
76
+ await user.type(height, '150');
77
+ await user.type(weight, '45');
78
+ await user.tab();
79
+
80
+ expect(height).toHaveValue(150);
81
+ expect(weight).toHaveValue(45);
82
+ expect(heightForAgeZscore).toHaveValue(4);
83
+ });
84
+
85
+ function renderForm(formUUID, formJson, intent?: string) {
86
+ render(
87
+ <FormEngine
88
+ formJson={formJson as any}
89
+ formUUID={formUUID}
90
+ patientUUID={patientUUID}
91
+ formSessionIntent={intent}
92
+ visit={visit}
93
+ />,
94
+ );
95
+ }
96
+ });
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { act, render, screen } from '@testing-library/react';
4
+ import { type FetchResponse, openmrsFetch, usePatient, useSession } from '@openmrs/esm-framework';
5
+ import { mockVisit } from '__mocks__/visit.mock';
6
+ import { mockPatientAge4 } from '__mocks__/patient.mock';
7
+ import { mockSessionDataResponse } from '__mocks__/session.mock';
8
+ import demoHtsOpenmrsForm from '__mocks__/forms/afe-forms/demo_hts-form.json';
9
+ import demoHtsForm from '__mocks__/forms/rfe-forms/demo_hts-form.json';
10
+ import weightForHeightZscoreTestSchema from '__mocks__/forms/rfe-forms/zscore-weight-height-form.json';
11
+ import FormEngine from '../form-engine.component';
12
+
13
+ global.ResizeObserver = require('resize-observer-polyfill');
14
+
15
+ const patientUUID = '8673ee4f-e2ab-4077-ba55-4980f408773e';
16
+ const visit = mockVisit;
17
+
18
+ const mockOpenmrsFetch = jest.mocked(openmrsFetch);
19
+ const mockUsePatient = jest.mocked(usePatient);
20
+ const mockUseSession = jest.mocked(useSession);
21
+
22
+ jest.mock('../../src/api', () => {
23
+ const originalModule = jest.requireActual('../../src/api');
24
+
25
+ return {
26
+ ...originalModule,
27
+ getPreviousEncounter: jest.fn().mockImplementation(() => Promise.resolve(null)),
28
+ getConcept: jest.fn().mockImplementation(() => Promise.resolve(null)),
29
+ getLatestObs: jest.fn().mockImplementation(() => Promise.resolve({ valueNumeric: 60 })),
30
+ saveEncounter: jest.fn(),
31
+ };
32
+ });
33
+
34
+ describe.skip('weightForHeight z-score', () => {
35
+ beforeEach(() => {
36
+ mockUseSession.mockReturnValue(mockSessionDataResponse.data);
37
+
38
+ mockUsePatient.mockReturnValue({
39
+ isLoading: false,
40
+ patient: mockPatientAge4,
41
+ patientUuid: mockPatientAge4.id,
42
+ error: null,
43
+ });
44
+
45
+ mockOpenmrsFetch.mockResolvedValue({
46
+ data: {
47
+ results: [{ ...demoHtsOpenmrsForm }],
48
+ },
49
+ } as unknown as FetchResponse);
50
+
51
+ mockOpenmrsFetch.mockResolvedValue({
52
+ data: {
53
+ results: [{ ...demoHtsForm }],
54
+ },
55
+ } as unknown as FetchResponse);
56
+ });
57
+
58
+ it('should compute weightForHeight z-score from the provided height and weight values', async () => {
59
+ const user = userEvent.setup();
60
+
61
+ await act(async () => renderForm(null, weightForHeightZscoreTestSchema));
62
+
63
+ const weightForHeightZscore = screen.getByRole('textbox', { name: /weight for height zscore result/i });
64
+ const height = screen.getByRole('spinbutton', { name: /height/i });
65
+ const weight = screen.getByRole('spinbutton', { name: /weight/i });
66
+
67
+ await user.type(height, '110');
68
+ await user.type(weight, '45');
69
+ await user.tab();
70
+
71
+ expect(weight).toHaveValue(45);
72
+ expect(height).toHaveValue(110);
73
+ expect(weightForHeightZscore).toHaveValue('4');
74
+ });
75
+
76
+ function renderForm(formUUID, formJson, intent?: string) {
77
+ render(
78
+ <FormEngine
79
+ formJson={formJson}
80
+ formUUID={formUUID}
81
+ patientUUID={patientUUID}
82
+ formSessionIntent={intent}
83
+ visit={visit}
84
+ />,
85
+ );
86
+ }
87
+ });
@@ -0,0 +1,93 @@
1
+ module.exports = {
2
+ contextSeparator: false,
3
+ // Key separator used in your translation keys
4
+
5
+ createOldCatalogs: false,
6
+ // Save the \_old files
7
+
8
+ defaultNamespace: 'translations',
9
+ // Default namespace used in your i18next config
10
+
11
+ defaultValue: (_, __, ___, key) => key,
12
+ // Default value to give to empty keys
13
+ // You may also specify a function accepting the locale, namespace, and key as arguments
14
+
15
+ indentation: 2,
16
+ // Indentation of the catalog files
17
+
18
+ keepRemoved: false,
19
+ // Keep keys from the catalog that are no longer in code
20
+
21
+ keySeparator: '.',
22
+ // Key separator used in your translation keys
23
+ // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
24
+
25
+ // see below for more details
26
+ lexers: {
27
+ hbs: ['HandlebarsLexer'],
28
+ handlebars: ['HandlebarsLexer'],
29
+
30
+ htm: ['HTMLLexer'],
31
+ html: ['HTMLLexer'],
32
+
33
+ mjs: ['JavascriptLexer'],
34
+ js: ['JavascriptLexer'], // if you're writing jsx inside .js files, change this to JsxLexer
35
+ ts: ['JavascriptLexer'],
36
+ jsx: ['JsxLexer'],
37
+ tsx: ['JsxLexer'],
38
+
39
+ default: ['JavascriptLexer'],
40
+ },
41
+
42
+ lineEnding: 'lf',
43
+ // Control the line ending. See options at https://github.com/ryanve/eol
44
+
45
+ locales: ['en'],
46
+ // An array of the locales in your applications
47
+
48
+ namespaceSeparator: ':',
49
+ // Namespace separator used in your translation keys
50
+ // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
51
+
52
+ output: '$NAMESPACE/$LOCALE.json',
53
+ // Supports $LOCALE and $NAMESPACE injection
54
+ // Supports JSON (.json) and YAML (.yml) file formats
55
+ // Where to write the locale files relative to process.cwd()
56
+
57
+ pluralSeparator: '_',
58
+ // Plural separator used in your translation keys
59
+ // If you want to use plain english keys, separators such as `_` might conflict. You might want to set `pluralSeparator` to a different string that does not occur in your keys.
60
+
61
+ input: undefined,
62
+ // An array of globs that describe where to look for source files
63
+ // relative to the location of the configuration file
64
+
65
+ sort: true,
66
+ // Whether or not to sort the catalog
67
+
68
+ skipDefaultValues: false,
69
+ // Whether to ignore default values
70
+ // You may also specify a function accepting the locale and namespace as arguments
71
+
72
+ useKeysAsDefaultValue: false,
73
+ // Whether to use the keys as the default value; ex. "Hello": "Hello", "World": "World"
74
+ // This option takes precedence over the `defaultValue` and `skipDefaultValues` options
75
+ // You may also specify a function accepting the locale and namespace as arguments
76
+
77
+ verbose: false,
78
+ // Display info about the parsing including some stats
79
+
80
+ failOnWarnings: false,
81
+ // Exit with an exit code of 1 on warnings
82
+
83
+ customValueTemplate: null,
84
+ // If you wish to customize the value output the value as an object, you can set your own format.
85
+ // ${defaultValue} is the default value you set in your translation function.
86
+ // Any other custom property will be automatically extracted.
87
+ //
88
+ // Example:
89
+ // {
90
+ // message: "${defaultValue}",
91
+ // description: "${maxLength}", // t('my-key', {maxLength: 150})
92
+ // }
93
+ };
@@ -0,0 +1,47 @@
1
+ {
2
+ "add": "Add",
3
+ "addCameraImage": "Add camera image",
4
+ "addFile": "Add files",
5
+ "attachmentsSaved": "Attachment(s) saved successfully",
6
+ "cameraCapture": "Camera capture",
7
+ "cancel": "Cancel",
8
+ "chooseAnOption": "Choose an option",
9
+ "close": "Close",
10
+ "closeCamera": "Close camera",
11
+ "closesNotification": "Closes notification",
12
+ "createdRecord": "Record created",
13
+ "createdRecordDescription": "A new encounter was created",
14
+ "errorDescription": "{{errors}}",
15
+ "errorDescriptionTitle": "Error on saving form",
16
+ "errorRenderingField": "Error rendering field",
17
+ "errorSavingAttachments": "Error saving attachment(s)",
18
+ "errorSavingEncounter": "Error saving encounter",
19
+ "errorSavingPatientIdentifiers": "Error saving patient identifiers",
20
+ "errorSavingPatientPrograms": "Error saving patient program(s)",
21
+ "fileUploadDescription": "",
22
+ "fileUploadDescriptionAny": "Upload any file type",
23
+ "invalidWorkspaceName": "Invalid workspace name.",
24
+ "invalidWorkspaceNameSubtitle": "Please provide a valid workspace name.",
25
+ "launchWorkspace": "",
26
+ "loading": "Loading",
27
+ "notification": "Notification",
28
+ "ordersSaved": "Order(s) saved sucessfully",
29
+ "patientIdentifiersSaved": "Patient identifier(s) saved sucessfully",
30
+ "patientProgramsSaved": "Patient program(s) saved successfully",
31
+ "preview": "Preview",
32
+ "previousValue": "Previous value:",
33
+ "remove": "Remove",
34
+ "required": "Required",
35
+ "revert": "Revert",
36
+ "save": "Save",
37
+ "search": "Search",
38
+ "submitting": "Submitting",
39
+ "time": "Time",
40
+ "unspecified": "Unspecified",
41
+ "unspecifyAll": "Unspecify All",
42
+ "updatedRecord": "Record updated",
43
+ "updatedRecordDescription": "The patient encounter was updated",
44
+ "upload": "Upload",
45
+ "uploadedPhoto": "Uploaded photo",
46
+ "uploadImage": "Upload image"
47
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "activeLoadingIndicator": "Indicador de carga activo",
3
+ "add": "Agregar",
4
+ "addCameraImage": "Agregar imagen de cámara",
5
+ "addFile": "Agregar archivos",
6
+ "cameraCapture": "Captura de cámara",
7
+ "cancel": "Cancelar",
8
+ "chooseAnOption": "Elegir una opción",
9
+ "close": "Cerrar",
10
+ "closeCamera": "Cerrar cámara",
11
+ "closesNotification": "Cerrar notificación",
12
+ "collapseAll": "Contraer todo",
13
+ "createdRecord": "Registro creado",
14
+ "createdRecordDescription": "Se creó un nuevo encuentro",
15
+ "errorDescriptionTitle": "Error al guardar el formulario",
16
+ "errorRenderingField": "Error al renderizar el campo",
17
+ "expandAll": "Expandir todo",
18
+ "fileUploadDescription": "",
19
+ "fileUploadDescriptionAny": "Subir cualquier tipo de archivo",
20
+ "loading": "Cargando",
21
+ "notification": "Notificación",
22
+ "preview": "Vista previa",
23
+ "previousValue": "Valor anterior:",
24
+ "removeGroup": "Eliminar grupo",
25
+ "revert": "Revertir",
26
+ "save": "Guardar",
27
+ "search": "Buscar",
28
+ "submitting": "Enviando",
29
+ "time": "Tiempo",
30
+ "toggleCollapseOrExpand": "Alternar entre contraer o expandir",
31
+ "unspecified": "No especificado",
32
+ "unspecifyAll": "No especificar todo",
33
+ "updatedRecord": "Registro actualizado",
34
+ "updatedRecordDescription": "Se actualizó el encuentro del paciente",
35
+ "upload": "Subir",
36
+ "uploadedPhoto": "Foto subida",
37
+ "uploadImage": "Subir imagen"
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "activeLoadingIndicator": "Indicateur de chargement actif",
3
+ "add": "Ajouter",
4
+ "addCameraImage": "Ajouter une image de la caméra",
5
+ "addFile": "Ajouter des fichiers",
6
+ "cameraCapture": "Capture de la caméra",
7
+ "cancel": "Annuler",
8
+ "chooseAnOption": "Choisissez une option",
9
+ "close": "Fermer",
10
+ "closeCamera": "Fermer la caméra",
11
+ "closesNotification": "Ferme la notification",
12
+ "collapseAll": "Réduire tout",
13
+ "createdRecord": "Enregistrement créé",
14
+ "createdRecordDescription": "Une nouvelle rencontre a été créée",
15
+ "errorDescriptionTitle": "Erreur lors de l'enregistrement du formulaire",
16
+ "errorRenderingField": "Erreur lors du rendu du champ",
17
+ "expandAll": "Développer tout",
18
+ "fileUploadDescription": "",
19
+ "fileUploadDescriptionAny": "Télécharger n'importe quel type de fichier",
20
+ "loading": "Chargement",
21
+ "notification": "Notification",
22
+ "preview": "Aperçu",
23
+ "previousValue": "Valeur précédente :",
24
+ "removeGroup": "Supprimer le groupe",
25
+ "revert": "Revenir",
26
+ "save": "Enregistrer",
27
+ "search": "Recherche",
28
+ "submitting": "Soumission",
29
+ "time": "Temps",
30
+ "toggleCollapseOrExpand": "Basculer réduire ou développer",
31
+ "unspecified": "Non spécifié",
32
+ "unspecifyAll": "Tout non spécifié",
33
+ "updatedRecord": "Enregistrement mis à jour",
34
+ "updatedRecordDescription": "La rencontre du patient a été mise à jour",
35
+ "upload": "Télécharger",
36
+ "uploadedPhoto": "Photo téléchargée",
37
+ "uploadImage": "Télécharger une image"
38
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "activeLoadingIndicator": "សិទ្ធិដំណើរការអត្ថបទកំពុងស្រលាញ់",
3
+ "add": "បន្ថែម",
4
+ "addCameraImage": "បន្ថែមរូបភាពសាកល្បង",
5
+ "addFile": "បន្ថែមឯកសារ",
6
+ "cameraCapture": "ការថតរូបភាពតាមកាមេរ៉ា",
7
+ "cancel": "បោះបង់",
8
+ "chooseAnOption": "ជ្រើសរើសជម្រើស",
9
+ "close": "បិទ",
10
+ "closeCamera": "បិទកាមេរ៉ា",
11
+ "closesNotification": "បិទការជូនដំណឹង",
12
+ "collapseAll": "លាក់ទាំងអស់",
13
+ "createdRecord": "បានបង្កើតកំណត់ហេតុ",
14
+ "createdRecordDescription": "បានបង្កើតការចូលទិន្ន័រថ្មី",
15
+ "errorDescriptionTitle": "កំហុសព័ត៌មានលទ្ធផល",
16
+ "errorRenderingField": "កំហុសការបង្ហាញវាល",
17
+ "expandAll": "ពង្រីកទាំងអស់",
18
+ "fileUploadDescription": "",
19
+ "fileUploadDescriptionAny": "ផ្ទុកឡើងឯកសារប្រភេទណាមួយ",
20
+ "loading": "កំពុងដំណើរការ",
21
+ "notification": "ការជូនដំណឹង",
22
+ "preview": "មើលជាមុន",
23
+ "previousValue": "តម្លៃមុន:",
24
+ "removeGroup": "យកក្រុមចេញ",
25
+ "revert": "ត្រឡប់ទៅកាន់ដំណើរការដូចដើម",
26
+ "save": "រក្សាទុក",
27
+ "search": "ស្វែងរក",
28
+ "submitting": "កំពុងដាក់ស្នើ",
29
+ "time": "ពេលវេលា",
30
+ "toggleCollapseOrExpand": "បិទឬពង្រីកជាមួយគ្រាប់គ្នា",
31
+ "unspecified": "មិនបានបញ្ជាក់",
32
+ "unspecifyAll": "មិនបានបញ្ជាក់ទាំងអស់",
33
+ "updatedRecord": "កំណត់ហេតុដែលបានធ្វើបច្ចុប្បន្នភាព",
34
+ "updatedRecordDescription": "ការស៊ើបអ្នកជម្រើសបានធ្វើបច្ចុប្បន្នភាព",
35
+ "upload": "ផ្ទុកឡើង",
36
+ "uploadedPhoto": "រូបភាពដែលបានផ្ទុកឡើង",
37
+ "uploadImage": "ផ្ទុករូបភាពឡើង"
38
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "esModuleInterop": true,
4
+ "module": "esnext",
5
+ "allowSyntheticDefaultImports": true,
6
+ "jsx": "react",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "node",
9
+ "lib": ["dom", "es5", "scripthost", "es2015", "es2015.promise", "es2016.array.include", "es2018", "es2020"],
10
+ "resolveJsonModule": true,
11
+ "noEmit": true,
12
+ "target": "esnext",
13
+ "baseUrl": "./",
14
+ "paths": {
15
+ "__mocks__": ["./__mocks__"]
16
+ }
17
+ },
18
+ "include": ["src/**/*", "./setupTests.ts"]
19
+ }
package/turbo.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://turborepo.org/schema.json",
3
+ "tasks": {
4
+ "build": {
5
+ "outputs": ["dist/**"]
6
+ },
7
+ "test": {},
8
+ "test:watch": {
9
+ "cache": false,
10
+ "persistent": true
11
+ },
12
+ "lint": {},
13
+ "typescript": {}
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ module.exports = require('openmrs/default-webpack-config');