@openmrs/esm-form-engine-lib 2.1.0-pre.1531 → 2.1.0-pre.1540

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,54 @@
1
+ {
2
+ "name": "Js expression validation",
3
+ "uuid": "xxxx",
4
+ "EncounterType": "xxxx",
5
+ "referencedForms": [],
6
+ "processor": "EncounterFormProcessor",
7
+ "pages": [
8
+ {
9
+ "label": "Page 1",
10
+ "sections": [
11
+ {
12
+ "label": "Section 1",
13
+ "questions": [
14
+ {
15
+ "label": "Question 1",
16
+ "type": "obs",
17
+ "required": false,
18
+ "id": "question1",
19
+ "questionOptions": {
20
+ "rendering": "text",
21
+ "concept": "166103AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
22
+ "conceptMappings": [
23
+ {
24
+ "relationship": "SAME-AS",
25
+ "type": "PIH",
26
+ "value": "2724"
27
+ },
28
+ {
29
+ "relationship": "SAME-AS",
30
+ "type": "SNOMED CT",
31
+ "value": "397678008"
32
+ },
33
+ {
34
+ "relationship": "SAME-AS",
35
+ "type": "CIEL",
36
+ "value": "166103"
37
+ }
38
+ ],
39
+ "showDate": true
40
+ },
41
+ "validators": [
42
+ {
43
+ "type": "js_expression",
44
+ "failsWhenExpression": "isEmpty(myValue)",
45
+ "message": "Empty value not allowed!"
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "2.1.0-pre.1531",
3
+ "version": "2.1.0-pre.1540",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -72,7 +72,7 @@ const DateField: React.FC<FormFieldInputProps> = ({ field, value: dateValue, err
72
72
  [field.datePickerFormat, field.label, t],
73
73
  );
74
74
 
75
- return sessionMode == 'view' || sessionMode == 'embedded-view' ? (
75
+ return sessionMode == 'view' || sessionMode == 'embedded-view' || isTrue(field.readonly) ? (
76
76
  <FieldValueView
77
77
  label={t(field.label)}
78
78
  value={dateValue instanceof Date ? formatDateAsDisplayString(field, dateValue) : dateValue}
@@ -8,4 +8,8 @@
8
8
  :global(.cds--label) {
9
9
  font-weight: bolder;
10
10
  }
11
+
12
+ button {
13
+ border-bottom: none !important;
14
+ }
11
15
  }
@@ -12,7 +12,7 @@ import {
12
12
  } from '@openmrs/esm-framework';
13
13
  import { when } from 'jest-when';
14
14
  import * as api from './api';
15
- import { assertFormHasAllFields, findCheckboxGroup, findSelectInput } from './utils/test-utils';
15
+ import { assertFormHasAllFields, findCheckboxGroup, findSelectInput, findTextOrDateInput } from './utils/test-utils';
16
16
  import { evaluatePostSubmissionExpression } from './utils/post-submission-action-helper';
17
17
  import { mockPatient } from '__mocks__/patient.mock';
18
18
  import { mockSessionDataResponse } from '__mocks__/session.mock';
@@ -42,6 +42,7 @@ import monthsOnArtForm from '__mocks__/forms/rfe-forms/months-on-art-form.json';
42
42
  import nextVisitForm from '__mocks__/forms/rfe-forms/next-visit-test-form.json';
43
43
  import viralLoadStatusForm from '__mocks__/forms/rfe-forms/viral-load-status-form.json';
44
44
  import readOnlyValidationForm from '__mocks__/forms/rfe-forms/read-only-validation-form.json';
45
+ import jsExpressionValidationForm from '__mocks__/forms/rfe-forms/js-expression-validation-form.json';
45
46
 
46
47
  import FormEngine from './form-engine.component';
47
48
  import { type SessionMode } from './types';
@@ -262,6 +263,21 @@ describe('Form engine component', () => {
262
263
  });
263
264
  });
264
265
 
266
+ describe('js-expression based validation', () => {
267
+ it('should invoke validation when field value changes', async () => {
268
+ await act(async () => {
269
+ renderForm(null, jsExpressionValidationForm);
270
+ });
271
+
272
+ const textField = await findTextOrDateInput(screen, 'Question 1');
273
+ await user.type(textField, 'Some value');
274
+ // clear value
275
+ await user.clear(textField);
276
+ const errorMessage = await screen.findByText(/Empty value not allowed!/i);
277
+ expect(errorMessage).toBeInTheDocument();
278
+ });
279
+ });
280
+
265
281
  describe('historical expressions', () => {
266
282
  it('should ascertain getPreviousEncounter() returns an encounter and the historical expression displays on the UI', async () => {
267
283
  renderForm(null, historicalExpressionsForm, 'COVID Assessment');
@@ -24,7 +24,7 @@ export function validateForm(context: FormContextProps) {
24
24
  const validator = formFieldValidators[validatorConfig.type];
25
25
  if (validator) {
26
26
  const validationResults = validator.validate(field, values[field.id], {
27
- fields: formFields,
27
+ formFields,
28
28
  values,
29
29
  expressionContext: {
30
30
  patient,
@@ -20,22 +20,22 @@ describe('ExpressionValidator - validate', () => {
20
20
  it('should evaluate js expressions', () => {
21
21
  // setup
22
22
  const field = allFields.find((f) => f.id == 'htsProviderRemarks');
23
- const failsWhenExpression = '!isEmpty(myValue) && isEmpty(`referredToPreventionServices`)';
23
+ const failsWhenExpression = '!isEmpty(myValue) && isEmpty(referredToPreventionServices)';
24
24
 
25
25
  // replay
26
26
  let errors = ExpressionValidator.validate(field, 'Remarks..', {
27
27
  failsWhenExpression,
28
28
  expressionContext,
29
29
  values,
30
- message: 'Atleast one type of Prevention Services must be selected',
31
- fields: allFields,
30
+ message: 'At least one type of Prevention Services must be selected',
31
+ formFields: allFields,
32
32
  });
33
33
 
34
34
  // verify
35
35
  expect(errors).toEqual([
36
36
  {
37
37
  errCode: 'value.invalid',
38
- message: 'Atleast one type of Prevention Services must be selected',
38
+ message: 'At least one type of Prevention Services must be selected',
39
39
  resultType: 'error',
40
40
  },
41
41
  ]);
@@ -49,14 +49,14 @@ describe('ExpressionValidator - validate', () => {
49
49
  expressionContext,
50
50
  values,
51
51
  message: 'Atleast one type of Prevention Services must be selected',
52
- fields: allFields,
52
+ formFields: allFields,
53
53
  });
54
54
 
55
55
  // verify
56
56
  expect(errors).toEqual([]);
57
57
  });
58
58
 
59
- fit('should fail if date value is not within the configured bounds', () => {
59
+ it('should fail if date value is not within the configured bounds', () => {
60
60
  // setup
61
61
  const dateField: FormField = {
62
62
  label: 'Test Date',
@@ -81,7 +81,7 @@ describe('ExpressionValidator - validate', () => {
81
81
  ...dateField.validators[0],
82
82
  expressionContext,
83
83
  values,
84
- fields: allFields,
84
+ formFields: allFields,
85
85
  });
86
86
 
87
87
  // verify
@@ -96,7 +96,7 @@ describe('ExpressionValidator - validate', () => {
96
96
  ...dateField.validators[0],
97
97
  expressionContext,
98
98
  values,
99
- fields: allFields,
99
+ formFields: allFields,
100
100
  });
101
101
 
102
102
  // verify
@@ -109,7 +109,7 @@ describe('ExpressionValidator - validate', () => {
109
109
  ...dateField.validators[0],
110
110
  expressionContext,
111
111
  values,
112
- fields: allFields,
112
+ formFields: allFields,
113
113
  });
114
114
 
115
115
  // verify
@@ -5,7 +5,7 @@ interface ExpressionValidatorConfig {
5
5
  failsWhenExpression?: string;
6
6
  warnsWhenExpression?: string;
7
7
  message: string;
8
- fields: FormField[];
8
+ formFields: FormField[];
9
9
  expressionContext: ExpressionContext;
10
10
  values: Record<string, any>;
11
11
  }
@@ -23,7 +23,7 @@ export const ExpressionValidator: FormFieldValidator = {
23
23
  return evaluateExpression(
24
24
  config[key],
25
25
  { value: field, type: 'field' },
26
- config.fields,
26
+ config.formFields,
27
27
  { ...config.values, [field.id]: value },
28
28
  config.expressionContext,
29
29
  )