@olaboot/esm-patient-registration-app 9.2.1 → 10.0.2

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 (342) hide show
  1. package/dist/1339.js +1 -0
  2. package/dist/1339.js.map +1 -0
  3. package/dist/1480.js +1 -0
  4. package/dist/1480.js.map +1 -0
  5. package/dist/1646.js +1 -0
  6. package/dist/1646.js.map +1 -0
  7. package/dist/1789.js +1 -0
  8. package/dist/1789.js.map +1 -0
  9. package/dist/1869.js +1 -0
  10. package/dist/1869.js.map +1 -0
  11. package/dist/1877.js +1 -0
  12. package/dist/1877.js.map +1 -0
  13. package/dist/2317.js +1 -0
  14. package/dist/2317.js.map +1 -0
  15. package/dist/2416.js +1 -0
  16. package/dist/2416.js.map +1 -0
  17. package/dist/2747.js +1 -0
  18. package/dist/2747.js.map +1 -0
  19. package/dist/282.js +1 -0
  20. package/dist/282.js.map +1 -0
  21. package/dist/2881.js +1 -0
  22. package/dist/2881.js.map +1 -0
  23. package/dist/3378.js +1 -0
  24. package/dist/3378.js.map +1 -0
  25. package/dist/3720.js +1 -0
  26. package/dist/3720.js.map +1 -0
  27. package/dist/3906.js +1 -0
  28. package/dist/3906.js.map +1 -0
  29. package/dist/3963.js +1 -0
  30. package/dist/3963.js.map +1 -0
  31. package/dist/3989.js +1 -0
  32. package/dist/3989.js.map +1 -0
  33. package/dist/4106.js +1 -0
  34. package/dist/4106.js.map +1 -0
  35. package/dist/4111.js +1 -0
  36. package/dist/4111.js.map +1 -0
  37. package/dist/434.js +1 -0
  38. package/dist/434.js.map +1 -0
  39. package/dist/4348.js +1 -0
  40. package/dist/4348.js.map +1 -0
  41. package/dist/4383.js +1 -0
  42. package/dist/4383.js.map +1 -0
  43. package/dist/4658.js +1 -0
  44. package/dist/4658.js.map +1 -0
  45. package/dist/466.js +1 -0
  46. package/dist/466.js.map +1 -0
  47. package/dist/4928.js +1 -0
  48. package/dist/4928.js.map +1 -0
  49. package/dist/5117.js +1 -0
  50. package/dist/5117.js.map +1 -0
  51. package/dist/5132.js +1 -0
  52. package/dist/5132.js.map +1 -0
  53. package/dist/5145.js +1 -0
  54. package/dist/5145.js.map +1 -0
  55. package/dist/5208.js +43 -0
  56. package/dist/5208.js.map +1 -0
  57. package/dist/527.js +1 -0
  58. package/dist/527.js.map +1 -0
  59. package/dist/5280.js +1 -0
  60. package/dist/5280.js.map +1 -0
  61. package/dist/5338.js +6 -0
  62. package/dist/5338.js.map +1 -0
  63. package/dist/5503.js +1 -0
  64. package/dist/5503.js.map +1 -0
  65. package/dist/555.js +1 -0
  66. package/dist/555.js.map +1 -0
  67. package/dist/556.js +1 -0
  68. package/dist/556.js.map +1 -0
  69. package/dist/5644.js +1 -0
  70. package/dist/5644.js.map +1 -0
  71. package/dist/5697.js +1 -0
  72. package/dist/{4024.js.map → 5697.js.map} +1 -1
  73. package/dist/5940.js +1 -0
  74. package/dist/5940.js.map +1 -0
  75. package/dist/6047.js +1 -0
  76. package/dist/6047.js.map +1 -0
  77. package/dist/6371.js +1 -0
  78. package/dist/6371.js.map +1 -0
  79. package/dist/6377.js +1 -0
  80. package/dist/6377.js.map +1 -0
  81. package/dist/6388.js +1 -0
  82. package/dist/6388.js.map +1 -0
  83. package/dist/6444.js +1 -0
  84. package/dist/6444.js.map +1 -0
  85. package/dist/6508.js +1 -0
  86. package/dist/6508.js.map +1 -0
  87. package/dist/6724.js +1 -0
  88. package/dist/6724.js.map +1 -0
  89. package/dist/689.js +1 -0
  90. package/dist/689.js.map +1 -0
  91. package/dist/6904.js +1 -0
  92. package/dist/6904.js.map +1 -0
  93. package/dist/7045.js +1 -0
  94. package/dist/7045.js.map +1 -0
  95. package/dist/7175.js +1 -0
  96. package/dist/7175.js.map +1 -0
  97. package/dist/7182.js +1 -0
  98. package/dist/7182.js.map +1 -0
  99. package/dist/7649.js +1 -0
  100. package/dist/7649.js.map +1 -0
  101. package/dist/7742.js +1 -0
  102. package/dist/7742.js.map +1 -0
  103. package/dist/7912.js +1 -0
  104. package/dist/7912.js.map +1 -0
  105. package/dist/8358.js +1 -0
  106. package/dist/8358.js.map +1 -0
  107. package/dist/8359.js +1 -0
  108. package/dist/8359.js.map +1 -0
  109. package/dist/8695.js +1 -0
  110. package/dist/8695.js.map +1 -0
  111. package/dist/903.js +1 -0
  112. package/dist/903.js.map +1 -0
  113. package/dist/9061.js +1 -0
  114. package/dist/9061.js.map +1 -0
  115. package/dist/9072.js +1 -0
  116. package/dist/9072.js.map +1 -0
  117. package/dist/9397.js +1 -0
  118. package/dist/9397.js.map +1 -0
  119. package/dist/9712.js +1 -0
  120. package/dist/9712.js.map +1 -0
  121. package/dist/9771.js +1 -0
  122. package/dist/9771.js.map +1 -0
  123. package/dist/9806.js +1 -0
  124. package/dist/9806.js.map +1 -0
  125. package/dist/9816.js +1 -0
  126. package/dist/9816.js.map +1 -0
  127. package/dist/main.js +7 -6
  128. package/dist/main.js.map +1 -1
  129. package/dist/openmrs-esm-patient-registration-app.js +6 -0
  130. package/dist/{olaboot-esm-patient-registration-app.js.buildmanifest.json → openmrs-esm-patient-registration-app.js.buildmanifest.json} +540 -455
  131. package/dist/openmrs-esm-patient-registration-app.js.map +1 -0
  132. package/dist/routes.json +1 -1
  133. package/package.json +8 -9
  134. package/src/add-patient-link.extension.tsx +3 -2
  135. package/src/add-patient-link.test.tsx +2 -1
  136. package/src/config-schema.ts +507 -507
  137. package/src/constants.ts +1 -1
  138. package/src/index.ts +2 -24
  139. package/src/nav-link.test.tsx +1 -0
  140. package/src/offline.resources.ts +97 -31
  141. package/src/patient-registration/before-save-prompt.test.tsx +199 -0
  142. package/src/patient-registration/field/__mocks__/field.resource.ts +8 -7
  143. package/src/patient-registration/field/address/address-field.component.tsx +183 -186
  144. package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +6 -1
  145. package/src/patient-registration/field/address/address-hierarchy.test.tsx +289 -296
  146. package/src/patient-registration/field/address/address-search.component.tsx +20 -8
  147. package/src/patient-registration/field/address/address-search.scss +19 -2
  148. package/src/patient-registration/field/address/address-search.test.tsx +333 -141
  149. package/src/patient-registration/field/address/custom-address-field.component.tsx +1 -1
  150. package/src/patient-registration/field/cause-of-death/cause-of-death.component.tsx +1 -1
  151. package/src/patient-registration/field/cause-of-death/cause-of-death.test.tsx +251 -0
  152. package/src/patient-registration/field/custom-field.component.tsx +1 -1
  153. package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.component.tsx +1 -1
  154. package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.test.tsx +144 -0
  155. package/src/patient-registration/field/dob/dob.component.tsx +2 -2
  156. package/src/patient-registration/field/dob/dob.test.tsx +370 -54
  157. package/src/patient-registration/field/field.component.tsx +1 -1
  158. package/src/patient-registration/field/field.resource.ts +2 -2
  159. package/src/patient-registration/field/field.test.tsx +333 -330
  160. package/src/patient-registration/field/gender/gender-field.test.tsx +240 -54
  161. package/src/patient-registration/field/id/id-field.component.tsx +146 -144
  162. package/src/patient-registration/field/id/id-field.test.tsx +177 -121
  163. package/src/patient-registration/field/id/identifier-selection-overlay.component.tsx +200 -200
  164. package/src/patient-registration/field/id/identifier-selection-overlay.test.tsx +346 -0
  165. package/src/patient-registration/field/name/name-field.component.tsx +2 -2
  166. package/src/patient-registration/field/name/name-field.test.tsx +282 -0
  167. package/src/patient-registration/field/obs/obs-field.test.tsx +294 -118
  168. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +172 -108
  169. package/src/patient-registration/field/person-attributes/location-person-attribute-field.component.tsx +3 -3
  170. package/src/patient-registration/field/person-attributes/location-person-attribute-field.resource.tsx +2 -5
  171. package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +2 -2
  172. package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +249 -131
  173. package/src/patient-registration/field/person-attributes/person-attributes.resource.ts +1 -1
  174. package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +98 -70
  175. package/src/patient-registration/field/phone/phone-field.test.tsx +100 -0
  176. package/src/patient-registration/form-manager.test.ts +6 -5
  177. package/src/patient-registration/form-manager.ts +5 -2
  178. package/src/patient-registration/input/basic-input/input/input.component.tsx +3 -121
  179. package/src/patient-registration/input/basic-input/input/input.test.tsx +151 -51
  180. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +113 -33
  181. package/src/patient-registration/input/combo-input/combo-input.component.tsx +60 -24
  182. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.component.tsx +10 -101
  183. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +144 -108
  184. package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +241 -177
  185. package/src/patient-registration/input/custom-input/identifier/utils.test.ts +47 -8
  186. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +12 -12
  187. package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +52 -20
  188. package/src/patient-registration/input/input.scss +1 -2
  189. package/src/patient-registration/patient-registration-context.ts +5 -3
  190. package/src/patient-registration/patient-registration-hooks.ts +4 -12
  191. package/src/patient-registration/patient-registration-utils.test.ts +2 -1
  192. package/src/patient-registration/patient-registration-utils.ts +2 -98
  193. package/src/patient-registration/patient-registration.component.tsx +50 -46
  194. package/src/patient-registration/patient-registration.resource.test.tsx +4 -7
  195. package/src/patient-registration/patient-registration.resource.ts +1 -4
  196. package/src/patient-registration/patient-registration.scss +16 -3
  197. package/src/patient-registration/patient-registration.test.tsx +614 -580
  198. package/src/patient-registration/patient-registration.types.ts +17 -28
  199. package/src/patient-registration/section/death-info/death-info-section.test.tsx +130 -34
  200. package/src/patient-registration/section/demographics/demographics-section.test.tsx +122 -68
  201. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +15 -15
  202. package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +278 -84
  203. package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
  204. package/src/patient-registration/ui-components/overlay/overlay.test.tsx +104 -0
  205. package/src/patient-registration/validation/patient-registration-validation.test.ts +2 -1
  206. package/src/patient-registration/validation/patient-registration-validation.ts +9 -3
  207. package/src/root.component.tsx +2 -5
  208. package/src/widgets/cancel-patient-edit.test.tsx +48 -11
  209. package/src/widgets/delete-identifier-confirmation.test.tsx +77 -24
  210. package/src/widgets/edit-patient-details-button.component.tsx +14 -18
  211. package/src/widgets/edit-patient-details-button.scss +2 -2
  212. package/src/widgets/edit-patient-details-button.test.tsx +11 -13
  213. package/translations/am.json +9 -4
  214. package/translations/ar.json +9 -4
  215. package/translations/ar_SY.json +9 -4
  216. package/translations/bn.json +9 -4
  217. package/translations/cs.json +9 -4
  218. package/translations/de.json +120 -115
  219. package/translations/en.json +10 -4
  220. package/translations/en_US.json +9 -4
  221. package/translations/es.json +9 -4
  222. package/translations/es_MX.json +9 -4
  223. package/translations/fr.json +9 -4
  224. package/translations/he.json +9 -4
  225. package/translations/hi.json +9 -4
  226. package/translations/hi_IN.json +9 -4
  227. package/translations/id.json +9 -4
  228. package/translations/it.json +9 -4
  229. package/translations/ka.json +9 -4
  230. package/translations/km.json +9 -4
  231. package/translations/ku.json +9 -4
  232. package/translations/ky.json +9 -4
  233. package/translations/lg.json +9 -4
  234. package/translations/ne.json +9 -4
  235. package/translations/pl.json +9 -4
  236. package/translations/pt.json +9 -4
  237. package/translations/pt_BR.json +10 -5
  238. package/translations/qu.json +9 -4
  239. package/translations/ro_RO.json +9 -4
  240. package/translations/ru_RU.json +9 -4
  241. package/translations/si.json +9 -4
  242. package/translations/sq.json +9 -4
  243. package/translations/sw.json +9 -4
  244. package/translations/sw_KE.json +9 -4
  245. package/translations/tr.json +9 -4
  246. package/translations/tr_TR.json +9 -4
  247. package/translations/uk.json +9 -4
  248. package/translations/uz.json +9 -4
  249. package/translations/uz@Latn.json +9 -4
  250. package/translations/uz_UZ.json +9 -4
  251. package/translations/vi.json +9 -4
  252. package/translations/zh.json +50 -45
  253. package/translations/zh_CN.json +9 -4
  254. package/translations/zh_TW.json +9 -4
  255. package/vitest.config.ts +4 -0
  256. package/dist/126.js +0 -1
  257. package/dist/15.js +0 -1
  258. package/dist/1564.js +0 -1
  259. package/dist/1567.js +0 -1
  260. package/dist/1845.js +0 -1
  261. package/dist/1953.js +0 -1
  262. package/dist/200.js +0 -1
  263. package/dist/200.js.map +0 -1
  264. package/dist/215.js +0 -1
  265. package/dist/2178.js +0 -1
  266. package/dist/250.js +0 -1
  267. package/dist/250.js.map +0 -1
  268. package/dist/2523.js +0 -1
  269. package/dist/2523.js.map +0 -1
  270. package/dist/2566.js +0 -1
  271. package/dist/2586.js +0 -1
  272. package/dist/2586.js.map +0 -1
  273. package/dist/2716.js +0 -1
  274. package/dist/2716.js.map +0 -1
  275. package/dist/2759.js +0 -1
  276. package/dist/2821.js +0 -6
  277. package/dist/2821.js.map +0 -1
  278. package/dist/3089.js +0 -1
  279. package/dist/3089.js.map +0 -1
  280. package/dist/3230.js +0 -1
  281. package/dist/3441.js +0 -1
  282. package/dist/3565.js +0 -1
  283. package/dist/3571.js +0 -1
  284. package/dist/3571.js.map +0 -1
  285. package/dist/3746.js +0 -1
  286. package/dist/3925.js +0 -1
  287. package/dist/3946.js +0 -1
  288. package/dist/4024.js +0 -1
  289. package/dist/4744.js +0 -1
  290. package/dist/4744.js.map +0 -1
  291. package/dist/4809.js +0 -1
  292. package/dist/4894.js +0 -1
  293. package/dist/4970.js +0 -1
  294. package/dist/4970.js.map +0 -1
  295. package/dist/5130.js +0 -1
  296. package/dist/5187.js +0 -1
  297. package/dist/5491.js +0 -1
  298. package/dist/5491.js.map +0 -1
  299. package/dist/5595.js +0 -1
  300. package/dist/5961.js +0 -1
  301. package/dist/6133.js +0 -1
  302. package/dist/634.js +0 -1
  303. package/dist/634.js.map +0 -1
  304. package/dist/6456.js +0 -1
  305. package/dist/6466.js +0 -1
  306. package/dist/6613.js +0 -1
  307. package/dist/6783.js +0 -1
  308. package/dist/7073.js +0 -38
  309. package/dist/7073.js.map +0 -1
  310. package/dist/7154.js +0 -1
  311. package/dist/7154.js.map +0 -1
  312. package/dist/7348.js +0 -1
  313. package/dist/7439.js +0 -1
  314. package/dist/7439.js.map +0 -1
  315. package/dist/7543.js +0 -1
  316. package/dist/7607.js +0 -1
  317. package/dist/772.js +0 -1
  318. package/dist/7984.js +0 -1
  319. package/dist/7984.js.map +0 -1
  320. package/dist/8538.js +0 -1
  321. package/dist/8538.js.map +0 -1
  322. package/dist/8599.js +0 -1
  323. package/dist/8727.js +0 -1
  324. package/dist/8847.js +0 -1
  325. package/dist/9015.js +0 -1
  326. package/dist/906.js +0 -1
  327. package/dist/9065.js +0 -1
  328. package/dist/9182.js +0 -1
  329. package/dist/9339.js +0 -1
  330. package/dist/9453.js +0 -1
  331. package/dist/9833.js +0 -1
  332. package/dist/9833.js.map +0 -1
  333. package/dist/9856.js +0 -1
  334. package/dist/9856.js.map +0 -1
  335. package/dist/9920.js +0 -1
  336. package/dist/9938.js +0 -1
  337. package/dist/9943.js +0 -1
  338. package/dist/9943.js.map +0 -1
  339. package/dist/olaboot-esm-patient-registration-app.js +0 -5
  340. package/dist/olaboot-esm-patient-registration-app.js.map +0 -1
  341. package/jest.config.js +0 -3
  342. package/src/resource.ts +0 -12
@@ -1,7 +1,7 @@
1
- /* eslint-disable testing-library/no-node-access */
2
1
  import React from 'react';
2
+ import { vi, describe, it, expect, beforeEach } from 'vitest';
3
3
  import userEvent from '@testing-library/user-event';
4
- import { screen } from '@testing-library/react';
4
+ import { screen, waitFor } from '@testing-library/react';
5
5
  import { Form, Formik } from 'formik';
6
6
  import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
7
7
  import { esmPatientRegistrationSchema, type RegistrationConfig } from '../../../../config-schema';
@@ -69,7 +69,7 @@ const mockResourcesContextValue: Resources = {
69
69
  sessionId: 'JSESSION',
70
70
  currentProvider: { uuid: 'provider-uuid', identifier: 'PRO-123' },
71
71
  },
72
- relationshipTypes: [],
72
+ relationshipTypes: { results: [] },
73
73
  identifierTypes: [...mockIdentifierTypes],
74
74
  };
75
75
 
@@ -96,19 +96,42 @@ const mockContextValues: PatientRegistrationContextProps = {
96
96
  identifierTypes: [],
97
97
  initialFormValues: mockInitialFormValues,
98
98
  isOffline: false,
99
- setCapturePhotoProps: jest.fn(),
100
- setFieldValue: jest.fn(),
101
- setInitialFormValues: jest.fn(),
102
- setFieldTouched: jest.fn(),
99
+ setCapturePhotoProps: vi.fn(),
100
+ setFieldValue: vi.fn(),
101
+ setInitialFormValues: vi.fn(),
102
+ setFieldTouched: vi.fn(),
103
103
  validationSchema: null,
104
104
  values: mockInitialFormValues,
105
105
  };
106
106
 
107
- const mockUseConfig = jest.mocked(useConfig<RegistrationConfig>);
107
+ const mockUseConfig = vi.mocked(useConfig<RegistrationConfig>);
108
108
 
109
- describe('identifier input', () => {
110
- mockUseConfig.mockReturnValue({
111
- ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
109
+ /**
110
+ * Helper to render IdentifierInput component with Formik.
111
+ */
112
+ function renderIdentifierInput(
113
+ patientIdentifier: PatientIdentifierValue,
114
+ fieldName: string = 'openMrsId',
115
+ initialValues: Record<string, any> = {},
116
+ ) {
117
+ return renderWithContext(
118
+ <Formik initialValues={initialValues} onSubmit={vi.fn()}>
119
+ <Form>
120
+ <PatientRegistrationContextProvider value={mockContextValues}>
121
+ <IdentifierInput patientIdentifier={patientIdentifier} fieldName={fieldName} />
122
+ </PatientRegistrationContextProvider>
123
+ </Form>
124
+ </Formik>,
125
+ ResourcesContextProvider,
126
+ mockResourcesContextValue,
127
+ );
128
+ }
129
+
130
+ describe('IdentifierInput component', () => {
131
+ beforeEach(() => {
132
+ mockUseConfig.mockReturnValue({
133
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
134
+ });
112
135
  });
113
136
 
114
137
  const fieldName = 'openMrsId';
@@ -129,207 +152,248 @@ describe('identifier input', () => {
129
152
  required: true,
130
153
  } as PatientIdentifierValue;
131
154
 
132
- const setupIdentifierInput = (patientIdentifier: PatientIdentifierValue, initialValues = {}) => {
133
- renderWithContext(
134
- <Formik initialValues={initialValues} onSubmit={jest.fn()}>
135
- <Form>
136
- <PatientRegistrationContextProvider value={mockContextValues}>
137
- <IdentifierInput patientIdentifier={patientIdentifier} fieldName={fieldName} />
138
- </PatientRegistrationContextProvider>
139
- </Form>
140
- </Formik>,
141
- ResourcesContextProvider,
142
- mockResourcesContextValue,
143
- );
144
- };
145
-
146
- it('shows the identifier input', () => {
147
- openmrsID.autoGeneration = false;
148
- setupIdentifierInput(openmrsID as PatientIdentifierValue);
149
- expect(screen.getByLabelText(openmrsID.identifierName)).toBeInTheDocument();
150
- });
155
+ describe('Rendering', () => {
156
+ it('shows the identifier input', () => {
157
+ renderIdentifierInput({ ...openmrsID, autoGeneration: false });
158
+ expect(screen.getByLabelText(openmrsID.identifierName)).toBeInTheDocument();
159
+ });
151
160
 
152
- it('displays an edit button when there is an initial value', async () => {
153
- // setup
154
- openmrsID.autoGeneration = false;
155
- openmrsID.required = false;
156
- openmrsID.initialValue = '1002UU9';
157
- openmrsID.identifierValue = '1002UU9';
158
- // replay
159
- setupIdentifierInput(openmrsID as PatientIdentifierValue);
160
- expect(screen.getByText('Edit')).toBeInTheDocument();
161
- });
161
+ it('displays an edit button when there is an initial value and field is not required', () => {
162
+ renderIdentifierInput({
163
+ ...openmrsID,
164
+ autoGeneration: false,
165
+ required: false,
166
+ initialValue: '1002UU9',
167
+ identifierValue: '1002UU9',
168
+ });
169
+ expect(screen.getByText('Edit')).toBeInTheDocument();
170
+ });
162
171
 
163
- it('hides the edit button when the identifier is required', async () => {
164
- // setup
165
- openmrsID.autoGeneration = false;
166
- openmrsID.required = true;
167
- openmrsID.initialValue = '1002UU9';
168
- openmrsID.identifierValue = '1002UU9';
169
- // replay
170
- setupIdentifierInput(openmrsID);
171
- expect(screen.queryByText('Edit')).not.toBeInTheDocument();
172
- });
172
+ it('hides the edit button when the identifier is required', () => {
173
+ renderIdentifierInput({
174
+ ...openmrsID,
175
+ autoGeneration: false,
176
+ required: true,
177
+ initialValue: '1002UU9',
178
+ identifierValue: '1002UU9',
179
+ });
180
+ expect(screen.queryByText('Edit')).not.toBeInTheDocument();
181
+ });
173
182
 
174
- it('displays a delete button when the identifier is not a default type', () => {
175
- // setup
176
- openmrsID.required = false;
177
- // replay
178
- setupIdentifierInput(openmrsID);
179
- expect(screen.getByText('Delete')).toBeInTheDocument();
183
+ it('displays a delete button when the identifier is not a default type', () => {
184
+ renderIdentifierInput({
185
+ ...openmrsID,
186
+ required: false,
187
+ });
188
+ expect(screen.getByText('Delete')).toBeInTheDocument();
189
+ });
180
190
  });
181
191
 
182
- describe('auto-generated identifier', () => {
192
+ describe('Auto-generated identifier', () => {
183
193
  it('hides the input when the identifier is auto-generated', () => {
184
- openmrsID.autoGeneration = true;
185
- setupIdentifierInput(openmrsID);
194
+ renderIdentifierInput({
195
+ ...openmrsID,
196
+ autoGeneration: true,
197
+ });
186
198
  expect(screen.getByTestId('identifier-input')).toHaveAttribute('type', 'hidden');
187
199
  });
188
200
 
189
- it("displays 'Auto-Generated' when the indentifier has auto generation", () => {
190
- openmrsID.autoGeneration = true;
191
- setupIdentifierInput(openmrsID);
192
- expect(screen.getByTestId('identifier-placeholder').innerHTML).toBe('Auto-generated');
201
+ it("displays 'Auto-Generated' when the identifier has auto generation", () => {
202
+ renderIdentifierInput({
203
+ ...openmrsID,
204
+ autoGeneration: true,
205
+ });
206
+ const placeholder = screen.getByTestId('identifier-placeholder');
207
+ expect(placeholder).toHaveTextContent('Auto-generated');
193
208
  expect(screen.getByTestId('identifier-input')).toBeDisabled();
194
209
  });
195
210
 
196
- describe('manual entry allowed', () => {
197
- openmrsID.selectedSource = {
198
- autoGenerationOption: {
199
- manualEntryEnabled: true,
200
- },
201
- } as IdentifierSource;
202
-
203
- it('shows the edit button', () => {
204
- openmrsID.autoGeneration = true;
205
- setupIdentifierInput(openmrsID);
211
+ describe('Manual entry allowed', () => {
212
+ it('shows the edit button when manual entry is enabled', () => {
213
+ renderIdentifierInput({
214
+ ...openmrsID,
215
+ autoGeneration: true,
216
+ required: false,
217
+ selectedSource: {
218
+ uuid: '01af8526-cea4-4175-aa90-340acb411771',
219
+ name: 'Generator 2 for OpenMRS ID',
220
+ autoGenerationOption: {
221
+ manualEntryEnabled: true,
222
+ automaticGenerationEnabled: true,
223
+ },
224
+ } as IdentifierSource,
225
+ });
206
226
  expect(screen.getByText('Edit')).toBeInTheDocument();
207
227
  });
208
228
 
209
- describe('edit button clicked', () => {
210
- it('displays an empty input field', async () => {
229
+ describe('Edit button interaction', () => {
230
+ it('displays an empty input field when edit button is clicked', async () => {
211
231
  const user = userEvent.setup();
212
- openmrsID.autoGeneration = true;
213
- openmrsID.required = false;
214
- openmrsID.selectedSource = {
215
- autoGenerationOption: {
216
- manualEntryEnabled: true,
232
+ renderIdentifierInput(
233
+ {
234
+ ...openmrsID,
235
+ autoGeneration: true,
236
+ required: false,
237
+ selectedSource: {
238
+ ...openmrsID.selectedSource,
239
+ autoGenerationOption: {
240
+ manualEntryEnabled: true,
241
+ automaticGenerationEnabled: true,
242
+ },
243
+ } as IdentifierSource,
217
244
  },
218
- } as IdentifierSource;
219
- setupIdentifierInput(openmrsID);
245
+ fieldName,
246
+ );
247
+
220
248
  const editButton = screen.getByTestId('edit-button');
221
249
  await user.click(editButton);
222
- expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('');
250
+
251
+ await waitFor(() => {
252
+ expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('');
253
+ });
223
254
  });
224
255
 
225
256
  it('displays an input field with the identifier value if it exists', async () => {
226
257
  const user = userEvent.setup();
227
- openmrsID.autoGeneration = true;
228
- openmrsID.required = false;
229
- openmrsID.selectedSource = {
230
- autoGenerationOption: {
231
- manualEntryEnabled: true,
258
+ renderIdentifierInput(
259
+ {
260
+ ...openmrsID,
261
+ autoGeneration: true,
262
+ required: false,
263
+ selectedSource: {
264
+ ...openmrsID.selectedSource,
265
+ autoGenerationOption: {
266
+ manualEntryEnabled: true,
267
+ automaticGenerationEnabled: true,
268
+ },
269
+ } as IdentifierSource,
232
270
  },
233
- } as IdentifierSource;
234
- setupIdentifierInput(openmrsID, { identifiers: { [fieldName]: { identifierValue: '10001V' } } });
271
+ fieldName,
272
+ { identifiers: { [fieldName]: { identifierValue: '10001V' } } },
273
+ );
274
+
235
275
  const editButton = screen.getByTestId('edit-button');
236
276
  await user.click(editButton);
237
- expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('10001V');
277
+
278
+ await waitFor(() => {
279
+ expect(screen.getByLabelText(new RegExp(`${openmrsID.identifierName}`))).toHaveValue('10001V');
280
+ });
238
281
  });
239
282
  });
240
283
  });
241
284
  });
242
285
 
243
- it('validates identifier format correctly for identifier types with regex formats', async () => {
244
- const user = userEvent.setup();
245
-
246
- const ssnIdentifier = {
247
- ...openmrsID,
248
- autoGeneration: false,
249
- format: '^[A-Z]{1}-[0-9]{7}$',
250
- identifierName: 'SSN',
251
- identifierTypeUuid: 'a71403f3-8584-4289-ab41-2b4e5570bd45',
252
- identifierValue: undefined,
253
- initialValue: '',
254
- required: true,
255
- selectedSource: {
256
- uuid: '01af8526-cea4-4175-aa90-340acb411771',
257
- name: 'Generator 2 for SSN',
258
- autoGenerationOption: {
259
- manualEntryEnabled: true,
260
- automaticGenerationEnabled: false,
286
+ describe('Format validation', () => {
287
+ it('validates identifier format correctly for identifier types with regex formats', async () => {
288
+ const user = userEvent.setup();
289
+
290
+ const ssnIdentifier = {
291
+ ...openmrsID,
292
+ autoGeneration: false,
293
+ format: '^[A-Z]{1}-[0-9]{7}$',
294
+ identifierName: 'SSN',
295
+ identifierTypeUuid: 'a71403f3-8584-4289-ab41-2b4e5570bd45',
296
+ identifierValue: undefined,
297
+ initialValue: '',
298
+ required: true,
299
+ selectedSource: {
300
+ uuid: '01af8526-cea4-4175-aa90-340acb411771',
301
+ name: 'Generator 2 for SSN',
302
+ autoGenerationOption: {
303
+ manualEntryEnabled: true,
304
+ automaticGenerationEnabled: false,
305
+ },
306
+ } as IdentifierSource,
307
+ };
308
+
309
+ const mockSetFieldTouched = vi.fn();
310
+ const mockSetFieldValue = vi.fn();
311
+ const testContextValues = {
312
+ ...mockContextValues,
313
+ setFieldTouched: mockSetFieldTouched,
314
+ setFieldValue: mockSetFieldValue,
315
+ values: {
316
+ ...mockInitialFormValues,
317
+ identifiers: {
318
+ [fieldName]: ssnIdentifier,
319
+ },
261
320
  },
262
- } as IdentifierSource,
263
- };
264
-
265
- const mockSetFieldTouched = jest.fn();
266
- const mockSetFieldValue = jest.fn();
267
- const testContextValues = {
268
- ...mockContextValues,
269
- setFieldTouched: mockSetFieldTouched,
270
- setFieldValue: mockSetFieldValue,
271
- values: {
272
- ...mockInitialFormValues,
321
+ };
322
+
323
+ const initialValues = {
273
324
  identifiers: {
274
- [fieldName]: ssnIdentifier,
325
+ [fieldName]: {
326
+ identifierValue: '',
327
+ },
275
328
  },
276
- },
277
- };
329
+ };
278
330
 
279
- const initialValues = {
280
- identifiers: {
281
- [fieldName]: {
282
- identifierValue: '',
283
- },
284
- },
285
- };
286
-
287
- renderWithContext(
288
- <Formik initialValues={initialValues} onSubmit={jest.fn()}>
289
- <Form>
290
- <PatientRegistrationContextProvider value={testContextValues}>
291
- <IdentifierInput patientIdentifier={ssnIdentifier} fieldName={fieldName} />
292
- </PatientRegistrationContextProvider>
293
- </Form>
294
- </Formik>,
295
- ResourcesContextProvider,
296
- mockResourcesContextValue,
297
- );
298
-
299
- const input = screen.getByRole('textbox', {
300
- name: /ssn/i,
301
- });
331
+ renderWithContext(
332
+ <Formik initialValues={initialValues} onSubmit={vi.fn()}>
333
+ <Form>
334
+ <PatientRegistrationContextProvider value={testContextValues}>
335
+ <IdentifierInput patientIdentifier={ssnIdentifier} fieldName={fieldName} />
336
+ </PatientRegistrationContextProvider>
337
+ </Form>
338
+ </Formik>,
339
+ ResourcesContextProvider,
340
+ mockResourcesContextValue,
341
+ );
342
+
343
+ const input = screen.getByRole('textbox', {
344
+ name: /ssn/i,
345
+ });
346
+
347
+ // Valid case
348
+ await user.type(input, 'A-1234567');
349
+ await user.tab();
350
+
351
+ await waitFor(() => {
352
+ expect(input).toHaveValue('A-1234567');
353
+ });
354
+
355
+ await waitFor(() => {
356
+ expect(input).not.toHaveClass('cds--text-input--invalid');
357
+ });
358
+
359
+ expect(screen.queryByText(/identifier should be/i)).not.toBeInTheDocument();
360
+
361
+ // Invalid cases
362
+ await user.clear(input);
363
+ await user.type(input, 'A-0010902aaa'); // Extra characters
364
+ await user.tab();
365
+
366
+ await waitFor(() => {
367
+ expect(input).toHaveClass('cds--text-input--invalid');
368
+ });
369
+
370
+ await waitFor(() => {
371
+ expect(screen.getByText(/identifier should be/i)).toBeInTheDocument();
372
+ });
373
+
374
+ await user.clear(input);
375
+ await user.type(input, 'a-1234567'); // Lowercase letter
376
+ await user.tab();
302
377
 
303
- // Valid cases
304
- await user.type(input, 'A-1234567');
305
- await user.tab();
306
- expect(input).toHaveValue('A-1234567');
307
- expect(input).not.toHaveClass('cds--text-input--invalid');
308
- expect(screen.queryByText(/identifier should be/i)).not.toBeInTheDocument();
309
-
310
- // Invalid cases
311
- await user.clear(input);
312
- await user.type(input, 'A-0010902aaa'); // Extra characters
313
- await user.tab();
314
- expect(input).toHaveClass('cds--text-input--invalid');
315
- expect(screen.getByText(/identifier should be/i)).toBeInTheDocument();
316
-
317
- await user.clear(input);
318
- await user.type(input, 'a-1234567'); // Lowercase letter
319
- await user.tab();
320
- expect(input).toHaveClass('cds--text-input--invalid');
321
- expect(screen.getByText(/identifier should be/i)).toBeInTheDocument();
322
-
323
- await user.clear(input);
324
- await user.type(input, 'AB-1234567'); // Two letters
325
- await user.tab();
326
- expect(input).toHaveClass('cds--text-input--invalid');
327
- expect(screen.getByText(/identifier should be/i)).toBeInTheDocument();
328
-
329
- await user.clear(input);
330
- await user.type(input, 'A-123456'); // Only 6 digits
331
- await user.tab();
332
- expect(input).toHaveClass('cds--text-input--invalid');
333
- expect(screen.getByText(/identifier should be/i)).toBeInTheDocument();
378
+ await waitFor(() => {
379
+ expect(input).toHaveClass('cds--text-input--invalid');
380
+ });
381
+
382
+ await user.clear(input);
383
+ await user.type(input, 'AB-1234567'); // Two letters
384
+ await user.tab();
385
+
386
+ await waitFor(() => {
387
+ expect(input).toHaveClass('cds--text-input--invalid');
388
+ });
389
+
390
+ await user.clear(input);
391
+ await user.type(input, 'A-123456'); // Only 6 digits
392
+ await user.tab();
393
+
394
+ await waitFor(() => {
395
+ expect(input).toHaveClass('cds--text-input--invalid');
396
+ });
397
+ });
334
398
  });
335
399
  });
@@ -1,4 +1,5 @@
1
1
  import { isUniqueIdentifierTypeForOffline, shouldBlockPatientIdentifierInOfflineMode } from './utils';
2
+ import { vi, describe, it, expect } from 'vitest';
2
3
 
3
4
  interface IdentifierTypeOptions {
4
5
  uniquenessBehavior?: 'UNIQUE' | 'LOCATION' | 'NON_UNIQUE';
@@ -31,23 +32,57 @@ function createIdentifierType(options: IdentifierTypeOptions) {
31
32
  describe('shouldBlockPatientIdentifierInOfflineMode function', () => {
32
33
  it('should return false if identifierType is not unique', () => {
33
34
  const identifierType = createIdentifierType({ uniquenessBehavior: null });
34
-
35
35
  const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
36
36
 
37
37
  expect(result).toBe(false);
38
38
  });
39
39
 
40
- it('should return false if identifierType is unique and no manual entry is enabled', () => {
41
- const identifierType = createIdentifierType({ uniquenessBehavior: null });
40
+ it('should return false if identifierType is NON_UNIQUE', () => {
41
+ const identifierType = createIdentifierType({ uniquenessBehavior: 'NON_UNIQUE' });
42
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
43
+
44
+ expect(result).toBe(false);
45
+ });
42
46
 
47
+ it('should return false if identifierType is unique but has automatic generation only (no manual entry)', () => {
48
+ const identifierType = createIdentifierType({
49
+ uniquenessBehavior: 'UNIQUE',
50
+ manualEntryEnabled: false,
51
+ automaticGenerationEnabled: true,
52
+ });
43
53
  const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
44
54
 
45
55
  expect(result).toBe(false);
46
56
  });
47
57
 
48
58
  it('should return true if identifierType is unique and manual entry is enabled', () => {
49
- const identifierType = createIdentifierType({ manualEntryEnabled: true, uniquenessBehavior: 'UNIQUE' });
59
+ const identifierType = createIdentifierType({
60
+ uniquenessBehavior: 'UNIQUE',
61
+ manualEntryEnabled: true,
62
+ automaticGenerationEnabled: false,
63
+ });
64
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
65
+
66
+ expect(result).toBe(true);
67
+ });
50
68
 
69
+ it('should return true if identifierType is unique and both manual entry and auto generation are enabled', () => {
70
+ const identifierType = createIdentifierType({
71
+ uniquenessBehavior: 'UNIQUE',
72
+ manualEntryEnabled: true,
73
+ automaticGenerationEnabled: true,
74
+ });
75
+ const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
76
+
77
+ expect(result).toBe(true);
78
+ });
79
+
80
+ it('should return true if identifierType is unique with LOCATION behavior and manual entry enabled', () => {
81
+ const identifierType = createIdentifierType({
82
+ uniquenessBehavior: 'LOCATION',
83
+ manualEntryEnabled: true,
84
+ automaticGenerationEnabled: false,
85
+ });
51
86
  const result = shouldBlockPatientIdentifierInOfflineMode(identifierType);
52
87
 
53
88
  expect(result).toBe(true);
@@ -57,7 +92,6 @@ describe('shouldBlockPatientIdentifierInOfflineMode function', () => {
57
92
  describe('isUniqueIdentifierTypeForOffline function', () => {
58
93
  it('should return true if uniquenessBehavior is UNIQUE', () => {
59
94
  const identifierType = createIdentifierType({ uniquenessBehavior: 'UNIQUE' });
60
-
61
95
  const result = isUniqueIdentifierTypeForOffline(identifierType);
62
96
 
63
97
  expect(result).toBe(true);
@@ -65,15 +99,20 @@ describe('isUniqueIdentifierTypeForOffline function', () => {
65
99
 
66
100
  it('should return true if uniquenessBehavior is LOCATION', () => {
67
101
  const identifierType = createIdentifierType({ uniquenessBehavior: 'LOCATION' });
68
-
69
102
  const result = isUniqueIdentifierTypeForOffline(identifierType);
70
103
 
71
104
  expect(result).toBe(true);
72
105
  });
73
106
 
74
- it('should return false for other uniqueness behaviors', () => {
75
- const identifierType = createIdentifierType({ uniquenessBehavior: null });
107
+ it('should return false if uniquenessBehavior is NON_UNIQUE', () => {
108
+ const identifierType = createIdentifierType({ uniquenessBehavior: 'NON_UNIQUE' });
109
+ const result = isUniqueIdentifierTypeForOffline(identifierType);
76
110
 
111
+ expect(result).toBe(false);
112
+ });
113
+
114
+ it('should return false if uniquenessBehavior is null or undefined', () => {
115
+ const identifierType = createIdentifierType({ uniquenessBehavior: null });
77
116
  const result = isUniqueIdentifierTypeForOffline(identifierType);
78
117
 
79
118
  expect(result).toBe(false);
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import classNames from 'classnames';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button } from '@carbon/react';
3
4
  import { v4 } from 'uuid';
4
5
  import { type FormValues } from '../../patient-registration.types';
5
6
  import styles from './../input.scss';
@@ -17,8 +18,8 @@ export const dummyFormValues: FormValues = {
17
18
  additionalMiddleName: '',
18
19
  additionalFamilyName: 'Smitty',
19
20
  addNameInLocalLanguage: true,
20
- gender: 'Male',
21
- birthdate: new Date(2020, 1, 1) as any,
21
+ gender: 'male',
22
+ birthdate: new Date(2020, 1, 1),
22
23
  yearsEstimated: 1,
23
24
  monthsEstimated: 2,
24
25
  birthdateEstimated: true,
@@ -42,15 +43,14 @@ export const dummyFormValues: FormValues = {
42
43
  };
43
44
 
44
45
  export const DummyDataInput: React.FC<DummyDataInputProps> = ({ setValues }) => {
46
+ const { t } = useTranslation();
45
47
  return (
46
- <main>
47
- <button
48
- className={classNames('omrs-btn omrs-filled-neutral', styles.dummyData)}
49
- onClick={() => setValues(dummyFormValues)}
50
- type="button"
51
- aria-label="Dummy Data Input">
52
- Input Dummy Data
53
- </button>
54
- </main>
48
+ <Button
49
+ kind="tertiary"
50
+ onClick={() => setValues(dummyFormValues)}
51
+ className={styles.dummyData}
52
+ aria-label={t('inputDummyData', 'Input Dummy Data')}>
53
+ {t('inputDummyData', 'Input Dummy Data')}
54
+ </Button>
55
55
  );
56
56
  };