@openmrs/esm-form-engine-lib 2.1.0-pre.1414 → 2.1.0-pre.1422

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.
@@ -0,0 +1,198 @@
1
+ {
2
+ "name": "A Radio Button Test",
3
+ "pages": [
4
+ {
5
+ "label": "Page 1",
6
+ "sections": [
7
+ {
8
+ "label": "1",
9
+ "isExpanded": "true",
10
+ "questions": [
11
+ {
12
+ "label": "Visit type",
13
+ "type": "obs",
14
+ "required": "false",
15
+ "id": "visitType",
16
+ "questionOptions": {
17
+ "rendering": "radio",
18
+ "concept": "164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
19
+ "conceptMappings": [
20
+ {
21
+ "relationship": "SAME-AS",
22
+ "type": "CIEL",
23
+ "value": "164181"
24
+ }
25
+ ],
26
+ "answers": [
27
+ {
28
+ "concept": "164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
29
+ "label": "New visit"
30
+ },
31
+ {
32
+ "concept": "160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
33
+ "label": "Return visit type"
34
+ },
35
+ {
36
+ "concept": "5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
37
+ "label": "Other"
38
+ }
39
+ ]
40
+ },
41
+ "validators": [
42
+ {
43
+ "type": "form_field"
44
+ },
45
+ {
46
+ "type": "default_value"
47
+ }
48
+ ],
49
+ "meta": {
50
+ "submission": null,
51
+ "concept": {
52
+ "uuid": "164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
53
+ "display": "Visit type",
54
+ "conceptClass": {
55
+ "uuid": "8d491e50-c2cc-11de-8d13-0010c6dffd0f",
56
+ "display": "Question"
57
+ },
58
+ "answers": [
59
+ {
60
+ "uuid": "164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
61
+ "display": "New visit"
62
+ },
63
+ {
64
+ "uuid": "160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
65
+ "display": "Return visit type"
66
+ },
67
+ {
68
+ "uuid": "5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
69
+ "display": "Other"
70
+ }
71
+ ],
72
+ "conceptMappings": [
73
+ {
74
+ "conceptReferenceTerm": {
75
+ "conceptSource": {
76
+ "name": "CIEL"
77
+ },
78
+ "code": "164181"
79
+ }
80
+ }
81
+ ]
82
+ }
83
+ },
84
+ "isHidden": false,
85
+ "isRequired": false,
86
+ "isDisabled": false
87
+ },
88
+ {
89
+ "label": "Visit punctuality",
90
+ "type": "obs",
91
+ "required": false,
92
+ "id": "visitPunctuality",
93
+ "questionOptions": {
94
+ "rendering": "radio",
95
+ "concept": "d81d4698-e78c-420d-aac5-cb1f606fb32e",
96
+ "answers": [
97
+ {
98
+ "concept": "5c3ce9c9-75bd-4730-8878-08c03ec02e9d",
99
+ "label": "Early"
100
+ },
101
+ {
102
+ "concept": "90af4b72-442a-4fcc-84c2-2bb1c0361737",
103
+ "label": "Late"
104
+ },
105
+ {
106
+ "concept": "66cdc0a1-aa19-4676-af51-80f66d78d9eb",
107
+ "label": "On time"
108
+ }
109
+ ]
110
+ },
111
+ "validators": [
112
+ {
113
+ "type": "form_field"
114
+ },
115
+ {
116
+ "type": "default_value"
117
+ }
118
+ ],
119
+ "meta": {
120
+ "submission": null,
121
+ "concept": {
122
+ "uuid": "d81d4698-e78c-420d-aac5-cb1f606fb32e",
123
+ "display": "Visit Punctuality",
124
+ "conceptClass": {
125
+ "uuid": "8d491e50-c2cc-11de-8d13-0010c6dffd0f",
126
+ "display": "Question"
127
+ },
128
+ "answers": [
129
+ {
130
+ "uuid": "66cdc0a1-aa19-4676-af51-80f66d78d9eb",
131
+ "display": "On time"
132
+ },
133
+ {
134
+ "uuid": "90af4b72-442a-4fcc-84c2-2bb1c0361737",
135
+ "display": "Late"
136
+ },
137
+ {
138
+ "uuid": "5c3ce9c9-75bd-4730-8878-08c03ec02e9d",
139
+ "display": "Early"
140
+ }
141
+ ],
142
+ "conceptMappings": []
143
+ }
144
+ },
145
+ "isHidden": false,
146
+ "isRequired": false,
147
+ "isDisabled": false
148
+ }
149
+ ],
150
+ "isHidden": false
151
+ }
152
+ ],
153
+ "isHidden": false
154
+ }
155
+ ],
156
+ "processor": "EncounterFormProcessor",
157
+ "encounterType": "0e8230ce-bd1d-43f5-a863-cf44344fa4b0",
158
+ "referencedForms": [],
159
+ "uuid": "fd067f44-99fd-4b07-b238-cea7b278c2b2",
160
+ "description": "A Radio Button Test",
161
+ "version": "1.0",
162
+ "translations": {},
163
+ "conceptReferences": {
164
+ "164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {
165
+ "uuid": "164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
166
+ "display": "Visit type"
167
+ },
168
+ "164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {
169
+ "uuid": "164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
170
+ "display": "New visit"
171
+ },
172
+ "160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {
173
+ "uuid": "160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
174
+ "display": "Return visit type"
175
+ },
176
+ "5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {
177
+ "uuid": "5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
178
+ "display": "Other"
179
+ },
180
+ "d81d4698-e78c-420d-aac5-cb1f606fb32e": {
181
+ "uuid": "d81d4698-e78c-420d-aac5-cb1f606fb32e",
182
+ "display": "Visit Punctuality"
183
+ },
184
+ "5c3ce9c9-75bd-4730-8878-08c03ec02e9d": {
185
+ "uuid": "5c3ce9c9-75bd-4730-8878-08c03ec02e9d",
186
+ "display": "Early"
187
+ },
188
+ "90af4b72-442a-4fcc-84c2-2bb1c0361737": {
189
+ "uuid": "90af4b72-442a-4fcc-84c2-2bb1c0361737",
190
+ "display": "Late"
191
+ },
192
+ "66cdc0a1-aa19-4676-af51-80f66d78d9eb": {
193
+ "uuid": "66cdc0a1-aa19-4676-af51-80f66d78d9eb",
194
+ "display": "On time"
195
+ }
196
+ },
197
+ "encounter": ""
198
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "2.1.0-pre.1414",
3
+ "version": "2.1.0-pre.1422",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -37,7 +37,7 @@ const Radio: React.FC<FormFieldInputProps> = ({ field, value, errors, warnings,
37
37
  legendText={<FieldLabel field={field} />}
38
38
  className={styles.boldedLegend}
39
39
  disabled={field.isDisabled}
40
- invalid={errors.length > 0}>
40
+ invalid={errors?.length > 0}>
41
41
  <RadioButtonGroup
42
42
  name={field.id}
43
43
  valueSelected={value}
@@ -0,0 +1,198 @@
1
+ import React from 'react';
2
+ import { act, render, screen } from '@testing-library/react';
3
+ import { type FetchResponse, openmrsFetch, usePatient, useSession } from '@openmrs/esm-framework';
4
+ import { mockPatient } from '__mocks__/patient.mock';
5
+ import { mockSessionDataResponse } from '__mocks__/session.mock';
6
+ import { mockVisit } from '__mocks__/visit.mock';
7
+ import radioButtonFormSchema from '__mocks__/forms/rfe-forms/radio-button-form.json';
8
+ import Radio from './radio.component';
9
+ import { useFormProviderContext } from 'src/provider/form-provider';
10
+
11
+ const mockOpenmrsFetch = jest.mocked(openmrsFetch);
12
+ const mockUseSession = jest.mocked(useSession);
13
+ const mockUsePatient = jest.mocked(usePatient);
14
+
15
+ jest.mock('../../../api', () => {
16
+ const originalModule = jest.requireActual('../../../api');
17
+
18
+ return {
19
+ ...originalModule,
20
+ getPreviousEncounter: jest.fn().mockImplementation(() => Promise.resolve(null)),
21
+ };
22
+ });
23
+
24
+ jest.mock('src/provider/form-provider', () => ({
25
+ useFormProviderContext: jest.fn(),
26
+ }));
27
+
28
+ const mockUseFormProviderContext = useFormProviderContext as jest.Mock;
29
+
30
+ const addTestValues = {
31
+ field: {
32
+ label: 'Visit type',
33
+ type: 'obs',
34
+ required: false,
35
+ id: 'visitType',
36
+ questionOptions: {
37
+ rendering: 'radio',
38
+ concept: '164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
39
+ conceptMappings: [
40
+ {
41
+ relationship: 'SAME-AS',
42
+ type: 'CIEL',
43
+ value: '164181',
44
+ },
45
+ ],
46
+ answers: [
47
+ {
48
+ concept: '164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
49
+ label: 'New visit',
50
+ },
51
+ {
52
+ concept: '160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
53
+ label: 'Return visit type',
54
+ },
55
+ {
56
+ concept: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
57
+ label: 'Other',
58
+ },
59
+ ],
60
+ },
61
+ validators: [
62
+ {
63
+ type: 'form_field',
64
+ },
65
+ {
66
+ type: 'default_value',
67
+ },
68
+ ],
69
+ meta: {
70
+ submission: null,
71
+ concept: {
72
+ uuid: '164181AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
73
+ display: 'Visit type',
74
+ conceptClass: {
75
+ uuid: '8d491e50-c2cc-11de-8d13-0010c6dffd0f',
76
+ display: 'Question',
77
+ },
78
+ answers: [
79
+ {
80
+ uuid: '164180AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
81
+ display: 'New visit',
82
+ },
83
+ {
84
+ uuid: '160530AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
85
+ display: 'Return visit type',
86
+ },
87
+ {
88
+ uuid: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
89
+ display: 'Other',
90
+ },
91
+ ],
92
+ conceptMappings: [
93
+ {
94
+ conceptReferenceTerm: {
95
+ conceptSource: {
96
+ name: 'CIEL',
97
+ },
98
+ code: '164181',
99
+ },
100
+ },
101
+ ],
102
+ },
103
+ },
104
+ isHidden: false,
105
+ isRequired: false,
106
+ isDisabled: false,
107
+ },
108
+ value: null,
109
+ errors: null,
110
+ warnings: undefined,
111
+ setFieldValue: null,
112
+ };
113
+
114
+ const renderForm = async (props) => {
115
+ await act(() => render(<Radio {...props} />));
116
+ };
117
+
118
+ let formProcessor;
119
+
120
+ const mockProviderValues = {
121
+ layoutType: 'small-desktop',
122
+ sessionMode: 'enter',
123
+ workspaceLayout: 'minimized',
124
+ formFieldAdapters: {},
125
+ patient: mockPatient,
126
+ methods: undefined,
127
+ formJson: radioButtonFormSchema as any,
128
+ visit: mockVisit,
129
+ sessionDate: new Date(),
130
+ location: mockVisit.location,
131
+ currentProvider: mockVisit.encounters[0]?.encounterProvider,
132
+ processor: formProcessor,
133
+ };
134
+
135
+ describe('Radio Component', () => {
136
+ beforeEach(() => {
137
+ formProcessor = {
138
+ getInitialValues: jest.fn(),
139
+ };
140
+ mockOpenmrsFetch.mockResolvedValue({
141
+ data: { results: [{ ...radioButtonFormSchema }] },
142
+ } as unknown as FetchResponse);
143
+
144
+ mockUseSession.mockReturnValue(mockSessionDataResponse.data);
145
+
146
+ mockUsePatient.mockReturnValue({
147
+ isLoading: false,
148
+ patient: mockPatient,
149
+ patientUuid: mockPatient.id,
150
+ error: null,
151
+ });
152
+ });
153
+
154
+ it('renders correctly', async () => {
155
+ mockUseFormProviderContext.mockReturnValue({
156
+ ...mockProviderValues,
157
+ });
158
+
159
+ await renderForm(addTestValues);
160
+ expect(screen.getByText('Visit type')).toBeInTheDocument();
161
+ expect(screen.getByLabelText('New visit')).toBeInTheDocument();
162
+ expect(screen.getByLabelText('Return visit type')).toBeInTheDocument();
163
+ expect(screen.getByLabelText('Other')).toBeInTheDocument();
164
+
165
+ const radioButtons = screen.getAllByRole('radio');
166
+ expect(radioButtons).toHaveLength(3);
167
+ });
168
+
169
+ it('renders correctly on view mode', async () => {
170
+ mockUseFormProviderContext.mockReturnValue({
171
+ ...mockProviderValues,
172
+ sessionMode: 'view',
173
+ });
174
+
175
+ await renderForm(addTestValues);
176
+ expect(screen.getByRole('button', { name: /visit type/i })).toBeInTheDocument();
177
+ const visitTypeElements = screen.getAllByText('Visit type');
178
+ expect(visitTypeElements.length).toBeGreaterThan(0);
179
+ });
180
+
181
+ it('renders radio buttons as disabled when the field is disabled', async () => {
182
+ mockUseFormProviderContext.mockReturnValue({
183
+ ...mockProviderValues,
184
+ });
185
+
186
+ await renderForm({ ...addTestValues, field: { ...addTestValues.field, isDisabled: true } });
187
+ expect(screen.getByText('Visit type')).toBeInTheDocument();
188
+
189
+ const radioButtons = screen.getAllByRole('radio');
190
+ expect(radioButtons).toHaveLength(3);
191
+ radioButtons.forEach((radio) => {
192
+ expect(radio).toBeDisabled();
193
+ });
194
+ expect(screen.getByLabelText('New visit')).toBeDisabled();
195
+ expect(screen.getByLabelText('Return visit type')).toBeDisabled();
196
+ expect(screen.getByLabelText('Other')).toBeDisabled();
197
+ });
198
+ });
@@ -10,7 +10,7 @@ type LabelProps = {
10
10
  const LabelField: React.FC<LabelProps> = ({ value, tooltipText }) => {
11
11
  return (
12
12
  <div className={styles.label}>
13
- <DefinitionTooltip direction="bottom" tabIndex={0} tooltipText={tooltipText}>
13
+ <DefinitionTooltip direction="bottom" tabIndex={0} definition={tooltipText}>
14
14
  <span className="cds--label">{`${value}:`}</span>
15
15
  </DefinitionTooltip>
16
16
  </div>
@@ -17,7 +17,7 @@ export function validateForm(context: FormContextProps) {
17
17
  } = context;
18
18
  const values = getValues();
19
19
  const errors = formFields
20
- .filter((field) => !field.isHidden && !field.isDisabled)
20
+ .filter((field) => !field.isHidden && !field.isParentHidden && !field.isDisabled)
21
21
  .flatMap((field) =>
22
22
  field.validators?.flatMap((validatorConfig) => {
23
23
  const validator = formFieldValidators[validatorConfig.type];