@openmrs/esm-form-engine-lib 3.1.3-pre.1757 → 3.1.3-pre.1762

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,91 @@
1
+ {
2
+ "encounterType": "",
3
+ "name": "Sample Default Values Form",
4
+ "processor": "EncounterFormProcessor",
5
+ "referencedForms": [],
6
+ "uuid": "3620c971-58e5-4e70-83ce-98d0dcf4bb7b",
7
+ "version": "1.0",
8
+ "pages": [
9
+ {
10
+ "label": "First Page",
11
+ "sections": [
12
+ {
13
+ "label": "A Section",
14
+ "isExpanded": "true",
15
+ "questions": [
16
+ {
17
+ "id": "sampleQuestion",
18
+ "label": "Text field with Default Value",
19
+ "type": "obs",
20
+ "questionOptions": {
21
+ "rendering": "text",
22
+ "defaultValue": "Value text",
23
+ "concept": "f82ba2b7-3849-4ad0-b867-36881e59f5c8"
24
+ }
25
+ }
26
+ ]
27
+ },
28
+ {
29
+ "label": "Another Section",
30
+ "isExpanded": "true",
31
+ "questions": [
32
+ {
33
+ "id": "codedQuestion",
34
+ "label": "Dropdown with Default Value",
35
+ "type": "obs",
36
+ "questionOptions": {
37
+ "rendering": "select",
38
+ "concept": "8cdea80a-d167-431c-8278-246c7a1f913b",
39
+ "defaultValue": "6b4e859c-86ca-41e5-b1c4-017889653b59",
40
+ "answers": [
41
+ {
42
+ "concept": "2b4e859c-86ca-41e5-b1c4-017889653b50",
43
+ "label": "Choice 1",
44
+ "conceptMappings": []
45
+ },
46
+ {
47
+ "concept": "6b4e859c-86ca-41e5-b1c4-017889653b59",
48
+ "label": "Choice 2",
49
+ "conceptMappings": []
50
+ },
51
+ {
52
+ "concept": "5b4e859c-c6ca-41e5-b1c4-017889653b5k",
53
+ "label": "Choice 3",
54
+ "conceptMappings": []
55
+ }
56
+ ]
57
+ }
58
+ },
59
+ {
60
+ "id": "codedQuestionWithInvalidDefaultValue",
61
+ "label": "Dropdown with an invalid Default Value",
62
+ "type": "obs",
63
+ "questionOptions": {
64
+ "rendering": "select",
65
+ "concept": "8cdea80a-d167-431c-8278-246c7a1f913b",
66
+ "defaultValue": "invalid-value",
67
+ "answers": [
68
+ {
69
+ "concept": "2b4e859c-86ca-41e5-b1c4-017889653b50",
70
+ "label": "Choice 1",
71
+ "conceptMappings": []
72
+ },
73
+ {
74
+ "concept": "6b4e859c-86ca-41e5-b1c4-017889653b59",
75
+ "label": "Choice 2",
76
+ "conceptMappings": []
77
+ },
78
+ {
79
+ "concept": "5b4e859c-c6ca-41e5-b1c4-017889653b5k",
80
+ "label": "Choice 3",
81
+ "conceptMappings": []
82
+ }
83
+ ]
84
+ }
85
+ }
86
+ ]
87
+ }
88
+ ]
89
+ }
90
+ ]
91
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "3.1.3-pre.1757",
3
+ "version": "3.1.3-pre.1762",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -46,6 +46,7 @@ import readOnlyValidationForm from '__mocks__/forms/rfe-forms/read-only-validati
46
46
  import jsExpressionValidationForm from '__mocks__/forms/rfe-forms/js-expression-validation-form.json';
47
47
  import hidePagesAndSectionsForm from '__mocks__/forms/rfe-forms/hide-pages-and-sections-form.json';
48
48
  import diagnosisForm from '__mocks__/forms/rfe-forms/diagnosis-test-form.json';
49
+ import defaultValuesForm from '__mocks__/forms/rfe-forms/default-values-form.json';
49
50
 
50
51
  import FormEngine from './form-engine.component';
51
52
  import { type FormSchema, type OpenmrsEncounter, type SessionMode } from './types';
@@ -358,7 +359,7 @@ describe('Form engine component', () => {
358
359
  await act(async () => {
359
360
  renderForm(null, requiredTestForm);
360
361
  });
361
-
362
+
362
363
  await user.click(screen.getByRole('button', { name: /save/i }));
363
364
 
364
365
  const labels = screen.getAllByText(/Text question/i);
@@ -457,7 +458,9 @@ describe('Form engine component', () => {
457
458
  expect(selectErrorMessage).toBeInTheDocument();
458
459
 
459
460
  // Validate multi-select field
460
- const multiSelectInputField = screen.getByText('If Unscheduled, actual scheduled reason multi-select', { exact: true });
461
+ const multiSelectInputField = screen.getByText('If Unscheduled, actual scheduled reason multi-select', {
462
+ exact: true,
463
+ });
461
464
  expect(multiSelectInputField).toBeInTheDocument();
462
465
  const multiSelectErrorMessage = screen.getByText(
463
466
  'Patient visit marked as unscheduled. Please provide the scheduled multi-select reason.',
@@ -699,6 +702,44 @@ describe('Form engine component', () => {
699
702
  });
700
703
  });
701
704
 
705
+ describe('Default values', () => {
706
+ it('should initialize fields with default values', async () => {
707
+ const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
708
+
709
+ await act(async () => renderForm(null, defaultValuesForm));
710
+
711
+ // text field
712
+ const textField = await findTextOrDateInput(screen, 'Text field with Default Value');
713
+ expect(textField).toHaveValue('Value text');
714
+
715
+ // dropdown field
716
+ const dropdownField = await findSelectInput(screen, 'Dropdown with Default Value');
717
+ expect(dropdownField.title).toBe('Choice 2');
718
+
719
+ // dropdown with an invalid default value
720
+ const invalidDropdownField = await findSelectInput(screen, 'Dropdown with an invalid Default Value');
721
+ expect(invalidDropdownField.title).toBe('Choose an option');
722
+
723
+ await user.click(screen.getByRole('button', { name: /save/i }));
724
+
725
+ const encounter = saveEncounterMock.mock.calls[0][1];
726
+ expect(encounter.obs).toEqual([
727
+ {
728
+ value: 'Value text',
729
+ concept: 'f82ba2b7-3849-4ad0-b867-36881e59f5c8',
730
+ formFieldNamespace: 'rfe-forms',
731
+ formFieldPath: 'rfe-forms-sampleQuestion',
732
+ },
733
+ {
734
+ value: '6b4e859c-86ca-41e5-b1c4-017889653b59',
735
+ concept: '8cdea80a-d167-431c-8278-246c7a1f913b',
736
+ formFieldNamespace: 'rfe-forms',
737
+ formFieldPath: 'rfe-forms-codedQuestion',
738
+ },
739
+ ]);
740
+ });
741
+ });
742
+
702
743
  describe('Calculated values', () => {
703
744
  it('should evaluate BMI', async () => {
704
745
  const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
@@ -285,6 +285,9 @@ export class EncounterFormProcessor extends FormProcessor {
285
285
  console.error(error);
286
286
  }
287
287
  }
288
+ if (field.questionOptions.defaultValue) {
289
+ initialValues[field.id] = inferInitialValueFromDefaultFieldValue(field);
290
+ }
288
291
  if (field.questionOptions.calculate?.calculateExpression) {
289
292
  fieldsWithCalculateExpressions.push(field);
290
293
  }
@@ -280,10 +280,17 @@ export function inferInitialValueFromDefaultFieldValue(field: FormField) {
280
280
  if (field.questionOptions.rendering == 'toggle' && typeof field.questionOptions.defaultValue != 'boolean') {
281
281
  return field.questionOptions.defaultValue == ConceptTrue;
282
282
  }
283
+
283
284
  // validate default value
284
- if (!DefaultValueValidator.validate(field, field.questionOptions.defaultValue).length) {
285
- return field.questionOptions.defaultValue;
285
+ const errors = DefaultValueValidator.validate(field, field.questionOptions.defaultValue);
286
+ if (errors.length) {
287
+ console.error(
288
+ `Default value validation errors for field "${field.id}" with value "${field.questionOptions.defaultValue}":`,
289
+ errors,
290
+ );
291
+ return null;
286
292
  }
293
+ return field.questionOptions.defaultValue;
287
294
  }
288
295
 
289
296
  export async function hydrateRepeatField(