From bd1b879e44f5aa79a45014aea15e138b724953c1 Mon Sep 17 00:00:00 2001 From: Vito Date: Wed, 28 Jul 2021 11:30:40 +0100 Subject: [PATCH] [MNT-22348] - Fixed visibility when complex cases are appling (#7176) * [MNT-22348] - Fixed visibility when complex cases are appling * [MNT-22348] - Fixed lint errrors * [MNT-22461] Unit test for visibility condition behaviour for checkxox expression is added * fixed unit test for visibility condition * [MNT-22348] - Fixed wrong form definition * [MNT-22348] - Fixed wrong quote * [MNT-22348] - Fixed wrong form definition * [MNT-22348] - fixed form definition Co-authored-by: Ketevani Kvirikashvili --- .../forms/multiple-visibility-conditions.ts | 924 +++++++++--------- .../widget-visibility-cloud.service.spec.ts | 48 - .../widget-visibility.service.spec.ts | 109 ++- .../services/widget-visibility.service.ts | 56 +- .../form/widget-visibility.service.mock.ts | 694 +++++++++++++ 5 files changed, 1243 insertions(+), 588 deletions(-) diff --git a/e2e/resources/forms/multiple-visibility-conditions.ts b/e2e/resources/forms/multiple-visibility-conditions.ts index 6223f740f0..cdcf42bbb4 100644 --- a/e2e/resources/forms/multiple-visibility-conditions.ts +++ b/e2e/resources/forms/multiple-visibility-conditions.ts @@ -15,476 +15,476 @@ * limitations under the License. */ - export const multipleVisibilityFormJson = { - formRepresentation: { - id: 'form-417ec60f-59ec-4990-a3b4-674f2c90af8a', - name: 'testtesttest', - description: '', - version: 0, - formDefinition: { - tabs: [], - fields: [ - { - id: '693934b1-fb52-45db-8ec0-f0d0f0accbed', - name: 'Label', - type: 'container', - tab: null, - numberOfColumns: 6, - fields: { - 1: [ - { - id: 'CheckboxReq', - name: 'CheckboxReq', - type: 'boolean', - required: true, - colspan: 1, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxNotReq', - name: 'CheckboxNotReq', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxColspan', - name: 'CheckboxColspan', - type: 'boolean', - required: false, - colspan: 2, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxBasicFieldValue', - name: 'CheckboxBasicFieldValue', - type: 'boolean', - required: false, - colspan: 1, +export const multipleVisibilityFormJson = { + formRepresentation: { + id: 'form-417ec60f-59ec-4990-a3b4-674f2c90af8a', + name: 'testtesttest', + description: '', + version: 0, + formDefinition: { + tabs: [], + fields: [ + { + id: '693934b1-fb52-45db-8ec0-f0d0f0accbed', + name: 'Label', + type: 'container', + tab: null, + numberOfColumns: 6, + fields: { + 1: [ + { + id: 'CheckboxReq', + name: 'CheckboxReq', + type: 'boolean', + required: true, + colspan: 1, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxNotReq', + name: 'CheckboxNotReq', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxColspan', + name: 'CheckboxColspan', + type: 'boolean', + required: false, + colspan: 2, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxBasicFieldValue', + name: 'CheckboxBasicFieldValue', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: { + leftType: 'field', + leftValue: 'textone', + operator: '==', + rightValue: 'aaa', + rightType: 'value', + nextConditionOperator: 'and-not', + nextCondition: { + leftType: 'field', + leftValue: 'texttwo', + operator: '==', + rightValue: 'aaa', + rightType: 'value', + nextConditionOperator: '', + nextCondition: null + } + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxBasicFieldVariable', + name: 'CheckboxBasicFieldVariable', + type: 'boolean', + required: false, + colspan: 1, visibilityCondition: { - leftType: 'field', - leftValue: 'textone', + leftFormFieldId: 'textOne', + leftRestResponseId: '', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + nextConditionOperator: '', + nextCondition: null + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxBasicVariableField', + name: 'CheckboxBasicVariableField', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: { + leftFormFieldId: '', + leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: 'textOne', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'CheckboxMultiple', + name: 'CheckboxMultiple', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: { + leftFormFieldId: 'textOne', + leftRestResponseId: '', operator: '==', rightValue: 'aaa', - rightType: 'value', - nextConditionOperator: 'and-not', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', nextCondition: { - leftType: 'field', - leftValue: 'texttwo', - operator: '==', + leftFormFieldId: 'textTwo', + leftRestResponseId: '', + operator: '!=', rightValue: 'aaa', - rightType: 'value', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', nextConditionOperator: '', nextCondition: null - } - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxBasicFieldVariable', - name: 'CheckboxBasicFieldVariable', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: { - leftFormFieldId: 'textOne', - leftRestResponseId: '', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - nextConditionOperator: '', - nextCondition: null - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxBasicVariableField', - name: 'CheckboxBasicVariableField', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: { - leftFormFieldId: '', - leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: 'textOne', - rightRestResponseId: '', - nextConditionOperator: '', - nextCondition: null - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'CheckboxMultiple', - name: 'CheckboxMultiple', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: { - leftFormFieldId: 'textOne', - leftRestResponseId: '', - operator: '==', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: 'and', - nextCondition: { - leftFormFieldId: 'textTwo', - leftRestResponseId: '', - operator: 'not equal', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: '', - nextCondition: null - } - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'checkboxone', - name: 'CheckboxOne', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: { - leftFormFieldId: 'textOne', - leftRestResponseId: '', - operator: '==', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: 'and', - nextCondition: { - leftFormFieldId: 'textTwo', - leftRestResponseId: '', - operator: 'not equal', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: 'and not', - nextCondition: { - leftFormFieldId: 'textThree', - leftRestResponseId: '', - operator: 'empty', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: 'or', - nextCondition: { - leftFormFieldId: 'textfour', - leftRestResponseId: '', - operator: 'not empty', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: 'or not', - nextCondition: { - leftFormFieldId: 'textfive', - leftRestResponseId: '', - operator: '==', - rightValue: 'aaa', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '', - nextConditionOperator: '', - nextCondition: null - } - } - } - } - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'checkboxtworeq', - name: 'CheckboxTwoReq', - type: 'boolean', - required: true, - colspan: 2, - visibilityCondition: { - leftFormFieldId: '', - leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: 'textTwo', - rightRestResponseId: '', - nextConditionOperator: 'and', - nextCondition: { - leftFormFieldId: '', - leftRestResponseId: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: 'textOne', - rightRestResponseId: '', - nextConditionOperator: 'and not', - nextCondition: { - leftFormFieldId: '', - leftRestResponseId: '888786b1-e948-4e7a-9caa-deb2583d222f', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: 'textThree', - rightRestResponseId: '', - nextConditionOperator: 'or', - nextCondition: { - leftFormFieldId: '', - leftRestResponseId: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: 'textfour', - rightRestResponseId: '', - nextConditionOperator: 'or not', - nextCondition: { - leftFormFieldId: '', - leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: 'textfive', - rightRestResponseId: '', - nextConditionOperator: '', - nextCondition: null - } - } - } - } - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - }, - { - id: 'checkboxthree', - name: 'CheckboxThree', - type: 'boolean', - required: false, - colspan: 1, - visibilityCondition: { - leftFormFieldId: 'textOne', - leftRestResponseId: '', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - nextConditionOperator: 'and', - nextCondition: { - leftFormFieldId: 'textTwo', - leftRestResponseId: '', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', - nextConditionOperator: 'and not', - nextCondition: { - leftFormFieldId: 'textThree', - leftRestResponseId: '', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '888786b1-e948-4e7a-9caa-deb2583d222f', - nextConditionOperator: 'or', - nextCondition: { - leftFormFieldId: 'textfour', - leftRestResponseId: '', - operator: 'not equal', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', - nextConditionOperator: 'or not', - nextCondition: { - leftFormFieldId: 'textfive', - leftRestResponseId: '', - operator: '==', - rightValue: '', - rightType: null, - rightFormFieldId: '', - rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', - nextConditionOperator: '', - nextCondition: null - } - } - } - } - }, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ], - 2: [ - { - id: 'textOne', - name: 'TextOne', - type: 'text', - required: false, - colspan: 1, - placeholder: null, - minLength: 0, - maxLength: 0, - regexPattern: null, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ], - 3: [ - { - id: 'textTwo', - name: 'TextTwo', - type: 'text', - required: false, - colspan: 1, - placeholder: null, - minLength: 0, - maxLength: 0, - regexPattern: null, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ], - 4: [ - { - id: 'textThree', - name: 'TextThree', - type: 'text', - required: false, - colspan: 1, - placeholder: null, - minLength: 0, - maxLength: 0, - regexPattern: null, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ], - 5: [ - { - id: 'textfour', - name: 'TextFour', - type: 'text', - required: false, - colspan: 1, - placeholder: null, - minLength: 0, - maxLength: 0, - regexPattern: null, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ], - 6: [ - { - id: 'textfive', - name: 'TextFive', - type: 'text', - required: false, - colspan: 1, - placeholder: null, - minLength: 0, - maxLength: 0, - regexPattern: null, - visibilityCondition: null, - params: { - existingColspan: 1, - maxColspan: 2 - } - } - ] - } - } - ], - outcomes: [], - metadata: {}, - variables: [ - { - id: '948aa549-5011-423e-b8a2-020e69daae5f', - name: 'vstring', - type: 'string', - value: 'aaa' - }, - { - id: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', - name: 'vint', - type: 'integer', - value: 5 - }, - { - id: '888786b1-e948-4e7a-9caa-deb2583d222f', - name: 'vbool', - type: 'boolean', - value: true - }, - { - id: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', - name: 'vdate', - type: 'date', - value: '2019-05-10' - } - ] - } - } -}; + } + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'checkboxone', + name: 'CheckboxOne', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: { + leftFormFieldId: 'textOne', + leftRestResponseId: '', + operator: '==', + rightValue: 'aaa', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'textTwo', + leftRestResponseId: '', + operator: '!=', + rightValue: 'aaa', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and-not', + nextCondition: { + leftFormFieldId: 'textThree', + leftRestResponseId: '', + operator: 'empty', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: 'textfour', + leftRestResponseId: '', + operator: '!empty', + rightValue: 'aaa', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'or-not', + nextCondition: { + leftFormFieldId: 'textfive', + leftRestResponseId: '', + operator: '==', + rightValue: 'aaa', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + } + } + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'checkboxtworeq', + name: 'CheckboxTwoReq', + type: 'boolean', + required: true, + colspan: 2, + visibilityCondition: { + leftFormFieldId: '', + leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: 'textTwo', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: '', + leftRestResponseId: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: 'textOne', + rightRestResponseId: '', + nextConditionOperator: 'and-not', + nextCondition: { + leftFormFieldId: '', + leftRestResponseId: '888786b1-e948-4e7a-9caa-deb2583d222f', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: 'textThree', + rightRestResponseId: '', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: '', + leftRestResponseId: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: 'textfour', + rightRestResponseId: '', + nextConditionOperator: 'or-not', + nextCondition: { + leftFormFieldId: '', + leftRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: 'textfive', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + } + } + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + }, + { + id: 'checkboxthree', + name: 'CheckboxThree', + type: 'boolean', + required: false, + colspan: 1, + visibilityCondition: { + leftFormFieldId: 'textOne', + leftRestResponseId: '', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'textTwo', + leftRestResponseId: '', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', + nextConditionOperator: 'and-not', + nextCondition: { + leftFormFieldId: 'textThree', + leftRestResponseId: '', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '888786b1-e948-4e7a-9caa-deb2583d222f', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: 'textfour', + leftRestResponseId: '', + operator: '!=', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', + nextConditionOperator: 'or-not', + nextCondition: { + leftFormFieldId: 'textfive', + leftRestResponseId: '', + operator: '==', + rightValue: '', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '948aa549-5011-423e-b8a2-020e69daae5f', + nextConditionOperator: '', + nextCondition: null + } + } + } + } + }, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ], + 2: [ + { + id: 'textOne', + name: 'TextOne', + type: 'text', + required: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + regexPattern: null, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ], + 3: [ + { + id: 'textTwo', + name: 'TextTwo', + type: 'text', + required: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + regexPattern: null, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ], + 4: [ + { + id: 'textThree', + name: 'TextThree', + type: 'text', + required: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + regexPattern: null, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ], + 5: [ + { + id: 'textfour', + name: 'TextFour', + type: 'text', + required: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + regexPattern: null, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ], + 6: [ + { + id: 'textfive', + name: 'TextFive', + type: 'text', + required: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + regexPattern: null, + visibilityCondition: null, + params: { + existingColspan: 1, + maxColspan: 2 + } + } + ] + } + } + ], + outcomes: [], + metadata: {}, + variables: [ + { + id: '948aa549-5011-423e-b8a2-020e69daae5f', + name: 'vstring', + type: 'string', + value: 'aaa' + }, + { + id: '08f66ebb-1e5c-4ae4-a8cc-ec9c674d1e40', + name: 'vint', + type: 'integer', + value: 5 + }, + { + id: '888786b1-e948-4e7a-9caa-deb2583d222f', + name: 'vbool', + type: 'boolean', + value: true + }, + { + id: '5007cf47-aa68-42c0-b1ab-a98f0dff6bdc', + name: 'vdate', + type: 'date', + value: '2019-05-10' + } + ] + } + } + }; - export const multipleTextVisibilityFormJson = { +export const multipleTextVisibilityFormJson = { formRepresentation: { id: 'form-1fc64874-5fa9-4eb0-be06-61abd51abef7', name: 'form2', diff --git a/lib/core/form/services/widget-visibility-cloud.service.spec.ts b/lib/core/form/services/widget-visibility-cloud.service.spec.ts index 6cdda86d78..6a6757888e 100644 --- a/lib/core/form/services/widget-visibility-cloud.service.spec.ts +++ b/lib/core/form/services/widget-visibility-cloud.service.spec.ts @@ -61,54 +61,6 @@ describe('WidgetVisibilityCloudService', () => { jasmine.Ajax.uninstall(); }); - describe('should be able to evaluate logic operations', () => { - - it('using AND and return true', () => { - booleanResult = service.evaluateLogicalOperation('and', true, true); - expect(booleanResult).toBeTruthy(); - }); - - it('using AND and return false', () => { - booleanResult = service.evaluateLogicalOperation('and', true, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using OR and return true', () => { - booleanResult = service.evaluateLogicalOperation('or', true, false); - expect(booleanResult).toBeTruthy(); - }); - - it('using OR and return false', () => { - booleanResult = service.evaluateLogicalOperation('or', false, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using AND NOT and return true', () => { - booleanResult = service.evaluateLogicalOperation('and-not', true, false); - expect(booleanResult).toBeTruthy(); - }); - - it('using AND NOT and return false', () => { - booleanResult = service.evaluateLogicalOperation('and-not', false, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using OR NOT and return true', () => { - booleanResult = service.evaluateLogicalOperation('or-not', true, true); - expect(booleanResult).toBeTruthy(); - }); - - it('using OR NOT and return false', () => { - booleanResult = service.evaluateLogicalOperation('or-not', false, true); - expect(booleanResult).toBeFalsy(); - }); - - it('should fail with invalid operation', () => { - booleanResult = service.evaluateLogicalOperation(undefined, false, true); - expect(booleanResult).toBeUndefined(); - }); - }); - describe('should be able to evaluate next condition operations', () => { it('using == and return true', () => { diff --git a/lib/core/form/services/widget-visibility.service.spec.ts b/lib/core/form/services/widget-visibility.service.spec.ts index 954e8429c0..d969522c75 100644 --- a/lib/core/form/services/widget-visibility.service.spec.ts +++ b/lib/core/form/services/widget-visibility.service.spec.ts @@ -32,7 +32,9 @@ import { fakeFormJson, formTest, formValues, complexVisibilityJsonVisible, complexVisibilityJsonNotVisible, tabVisibilityJsonMock, - tabInvalidFormVisibility + tabInvalidFormVisibility, + fakeFormChainedVisibilityJson, + fakeFormCheckBoxVisibilityJson } from 'core/mock/form/widget-visibility.service.mock'; import { CoreTestingModule } from '../../testing/core.testing.module'; import { TranslateModule } from '@ngx-translate/core'; @@ -63,50 +65,6 @@ describe('WidgetVisibilityService', () => { describe('should be able to evaluate logic operations', () => { - it('using AND and return true', () => { - booleanResult = service.evaluateLogicalOperation('and', true, true); - expect(booleanResult).toBeTruthy(); - }); - - it('using AND and return false', () => { - booleanResult = service.evaluateLogicalOperation('and', true, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using OR and return true', () => { - booleanResult = service.evaluateLogicalOperation('or', true, false); - expect(booleanResult).toBeTruthy(); - }); - - it('using OR and return false', () => { - booleanResult = service.evaluateLogicalOperation('or', false, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using AND NOT and return true', () => { - booleanResult = service.evaluateLogicalOperation('and-not', true, false); - expect(booleanResult).toBeTruthy(); - }); - - it('using AND NOT and return false', () => { - booleanResult = service.evaluateLogicalOperation('and-not', false, false); - expect(booleanResult).toBeFalsy(); - }); - - it('using OR NOT and return true', () => { - booleanResult = service.evaluateLogicalOperation('or-not', true, true); - expect(booleanResult).toBeTruthy(); - }); - - it('using OR NOT and return false', () => { - booleanResult = service.evaluateLogicalOperation('or-not', false, true); - expect(booleanResult).toBeFalsy(); - }); - - it('should fail with invalid operation', () => { - booleanResult = service.evaluateLogicalOperation(undefined, false, true); - expect(booleanResult).toBeUndefined(); - }); }); describe('should be able to evaluate next condition operations', () => { @@ -1122,4 +1080,65 @@ describe('WidgetVisibilityService', () => { expect(invalidTabVisibilityJsonModel.isValid).toBeTruthy(); }); }); + + describe('Visibility calculation in complex forms', () => { + + const fakeFormWithVariables = new FormModel(fakeFormChainedVisibilityJson); + + it('Should be able to validate correctly the visibility for the text field for complex expressions', () => { + const instalmentField = fakeFormWithVariables.getFieldById('installments'); + const scheduleField = fakeFormWithVariables.getFieldById('schedule'); + + instalmentField.value = '6'; + scheduleField.value = scheduleField.options[1].id; + + service.refreshVisibility(fakeFormWithVariables); + + let textField = fakeFormWithVariables.getFieldById('showtext'); + + expect(textField.isVisible).toBe(true); + + instalmentField.value = '5'; + scheduleField.value = scheduleField.options[1].id; + + service.refreshVisibility(fakeFormWithVariables); + + textField = fakeFormWithVariables.getFieldById('showtext'); + + expect(textField.isVisible).toBe(false); + }); + }); + + describe('Visibility calculation in checkbox forms', () => { + + const fakeFormWithValues = new FormModel(fakeFormCheckBoxVisibilityJson); + + it('Should be able to validate correctly the visibility for the checkbox expression', () => { + const fieldA = fakeFormWithValues.getFieldById('a'); + const fieldB = fakeFormWithValues.getFieldById('b'); + const fieldC = fakeFormWithValues.getFieldById('c'); + const fieldD = fakeFormWithValues.getFieldById('d'); + fieldA.value = true; + fieldB.value = true; + fieldC.value = false; + fieldD.value = false; + + service.refreshVisibility(fakeFormWithValues); + const textField = fakeFormWithValues.getFieldById('a_b_c_d'); + + expect(textField.isVisible).toBe(true); + + fieldB.value = false; + + service.refreshVisibility(fakeFormWithValues); + expect(textField.isVisible).toBe(false); + + fieldA.value = false; + fieldC.value = true; + fieldD.value = true; + + service.refreshVisibility(fakeFormWithValues); + expect(textField.isVisible).toBe(true); + }); + }); }); diff --git a/lib/core/form/services/widget-visibility.service.ts b/lib/core/form/services/widget-visibility.service.ts index 494a995294..4991ca116d 100644 --- a/lib/core/form/services/widget-visibility.service.ts +++ b/lib/core/form/services/widget-visibility.service.ts @@ -84,28 +84,38 @@ export class WidgetVisibilityService { const rightValue = this.getRightValue(form, visibilityObj); const actualResult = this.evaluateCondition(leftValue, rightValue, visibilityObj.operator); - if (this.isValidOperator(visibilityObj.nextConditionOperator)) { - accumulator.push({ value: actualResult, operator: visibilityObj.nextConditionOperator }); - } + accumulator.push({ value: actualResult, operator: visibilityObj.nextConditionOperator }); if (this.isValidCondition(visibilityObj.nextCondition)) { result = this.isFieldVisible(form, visibilityObj.nextCondition, accumulator); } else if (accumulator[0] !== undefined) { - result = accumulator[0].value; - for (let i = 1; i < accumulator.length; i++) { - if (accumulator[i] !== undefined) { - result = this.evaluateLogicalOperation( - accumulator[i - 1].operator, - result, - accumulator[i].value - ); - } - } + result = Function('"use strict";return (' + + accumulator.map((expression) => this.transformToLiteralExpression(expression)).join('') + + ')')(); } else { result = actualResult; } return !!result; + } + private transformToLiteralExpression(currentExpression: any): string { + const currentTransformedValue = !!currentExpression.value ? 'true' : 'false'; + return currentTransformedValue.concat(this.transformToLiteralOperator(currentExpression.operator)); + } + + private transformToLiteralOperator(currentOperator): string { + switch (currentOperator) { + case 'and': + return '&&'; + case 'or' : + return '||'; + case 'and-not': + return '&& !'; + case 'or-not': + return '|| !'; + default: + return ''; + } } getLeftValue(form: FormModel, visibilityObj: WidgetVisibilityModel): string { @@ -280,22 +290,6 @@ export class WidgetVisibilityService { return undefined; } - evaluateLogicalOperation(logicOp: string, previousValue: any, newValue: any): boolean | undefined { - switch (logicOp) { - case 'and': - return previousValue && newValue; - case 'or' : - return previousValue || newValue; - case 'and-not': - return previousValue && !newValue; - case 'or-not': - return previousValue || !newValue; - default: - this.logService.error(`Invalid operator: ${logicOp}`); - return undefined; - } - } - evaluateCondition(leftValue: any, rightValue: any, operator: string): boolean | undefined { switch (operator) { case '==': @@ -340,10 +334,6 @@ export class WidgetVisibilityService { return res || {}; } - private isValidOperator(operator: string): boolean { - return operator !== undefined; - } - private isValidCondition(condition: WidgetVisibilityModel): boolean { return !!(condition && condition.operator); } diff --git a/lib/core/mock/form/widget-visibility.service.mock.ts b/lib/core/mock/form/widget-visibility.service.mock.ts index 46fa24d365..4449238c14 100644 --- a/lib/core/mock/form/widget-visibility.service.mock.ts +++ b/lib/core/mock/form/widget-visibility.service.mock.ts @@ -116,6 +116,700 @@ export const fakeFormJson: any = { ] }; +export const fakeFormCheckBoxVisibilityJson: any = { + referenceId: '33033', + name: 'test_condition_form', + description: '', + tabs: [], + fields: [ + { + fieldType: 'ContainerRepresentation', + id: '1623514352532', + name: 'Label', + type: 'container', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + dateDisplayFormat: 'null', + layout: 'null', + sizeX: '2', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null', + numberOfColumns: '2', + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'a', + name: 'A', + type: 'boolean', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + params: { + existingColspan: '1', + maxColspan: '2' + }, + dateDisplayFormat: 'null', + layout: { + row: '-1', + column: '-1', + colspan: '1' + }, + sizeX: '1', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null' + } + ], + 2: [ + { + fieldType: 'FormFieldRepresentation', + id: 'b', + name: 'B', + type: 'boolean', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + params: { + existingColspan: '1', + maxColspan: '1' + }, + dateDisplayFormat: 'null', + layout: { + row: '-1', + column: '-1', + colspan: '1' + }, + sizeX: '1', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null' + } + ] + } + }, + { + fieldType: 'ContainerRepresentation', + id: '1623514356352', + name: 'Label', + type: 'container', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + dateDisplayFormat: 'null', + layout: 'null', + sizeX: '2', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null', + numberOfColumns: '2', + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'c', + name: 'C', + type: 'boolean', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + params: { + existingColspan: '1', + maxColspan: '2' + }, + dateDisplayFormat: 'null', + layout: { + row: '-1', + column: '-1', + colspan: '1' + }, + sizeX: '1', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null' + }], + 2: [ + { + fieldType: 'FormFieldRepresentation', + id: 'd', + name: 'D', + type: 'boolean', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + params: { + existingColspan: '1', + maxColspan: '1' + }, + dateDisplayFormat: 'null', + layout: { + row: '-1', + column: '-1', + colspan: '1' + }, + sizeX: '1', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null' + } + ] + } + }, + { + fieldType: 'ContainerRepresentation', + id: '1623514409166', + name: 'Label', + type: 'container', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'false', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + dateDisplayFormat: 'null', + layout: 'null', + sizeX: '2', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: 'null', + numberOfColumns: '2', + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'a_b_c_d', + name: 'Textfield ( A && B || C && D)', + type: 'text', + value: 'null', + required: 'false', + readOnly: 'false', + overrideId: 'true', + colspan: '1', + placeholder: 'null', + minLength: '0', + maxLength: '0', + minValue: 'null', + maxValue: 'null', + regexPattern: 'null', + optionType: 'null', + hasEmptyValue: 'null', + options: 'null', + restUrl: 'null', + restResponsePath: 'null', + restIdProperty: 'null', + restLabelProperty: 'null', + tab: 'null', + className: 'null', + params: { + existingColspan: '1', + maxColspan: '2' + }, + dateDisplayFormat: 'null', + layout: { + row: '-1', + column: '-1', + colspan: '1' + }, + sizeX: '1', + sizeY: '1', + row: '-1', + col: '-1', + visibilityCondition: { + leftFormFieldId: 'a', + leftRestResponseId: 'null', + operator: '==', + rightValue: 'true', + rightType: 'null', + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'b', + leftRestResponseId: 'null', + operator: '==', + rightValue: 'true', + rightType: 'null', + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: 'c', + leftRestResponseId: 'null', + operator: '==', + rightValue: 'true', + rightType: 'null', + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'd', + leftRestResponseId: 'null', + operator: '==', + rightValue: 'true', + rightType: 'null', + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: 'null' + } + } + } + } + } + ], + 2: [] + } + } + ], + outcomes: [], + javascriptEvents: [], + className: '', + style: '', + customFieldTemplates: {}, + metadata: {}, + variables: [], + customFieldsValueInfo: {}, + gridsterForm: 'false' +}; + +export const fakeFormChainedVisibilityJson: any = { + id: '8800', + name: 'FORM_VISIBILITYl_CHAIN', + processDefinitionId: 'PROCESS_TEST: 9: 9999', + processDefinitionName: 'PROCESS_TEST', + processDefinitionKey: 'PROCESS_TEST', + taskId: '999', + taskName: 'TEST', + fields: [ + { + fieldType: 'ContainerRepresentation', + id: '1615506402205', + name: 'Label', + type: 'container', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'installments', + name: 'Installments', + type: 'integer', + value: null, + required: true, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 2 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null + } + ], + 2: [ + { + fieldType: 'RestFieldRepresentation', + id: 'schedule', + name: 'Schedule', + type: 'dropdown', + value: 'Choose one...', + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: true, + options: [ + { + id: 'empty', + name: 'Choose one...' + }, + { + id: 'ANNUAL', + name: 'Annual' + }, + { + id: 'QUARTERLY', + name: 'Quarterly' + }, + { + id: 'MONTHLY', + name: 'Monthly' + } + ], + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 1 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + endpoint: null, + requestHeaders: null + } + ] + } + }, + { + fieldType: 'ContainerRepresentation', + id: 1615506384790, + name: 'Label', + type: 'container', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'showtext', + name: 'Show text', + type: 'readonly-text', + value: 'This test is shown when the visibility logic is displayed.\nThis should only show under the following conditions:\nAnnual and installment > 5\nQuarterly and installment > 20\nMonthly and installment > 60', + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 2 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: { + leftFormFieldId: 'schedule', + leftRestResponseId: null, + operator: '==', + rightValue: 'ANNUAL', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'installments', + leftRestResponseId: null, + operator: '>', + rightValue: 5, + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: 'schedule', + leftRestResponseId: null, + operator: '==', + rightValue: 'QUARTERLY', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'installments', + leftRestResponseId: null, + operator: '>', + rightValue: 20, + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'or', + nextCondition: { + leftFormFieldId: 'schedule', + leftRestResponseId: null, + operator: '==', + rightValue: 'MONTHLY', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: 'and', + nextCondition: { + leftFormFieldId: 'installments', + leftRestResponseId: null, + operator: '>', + rightValue: 60, + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + } + } + } + } + } + ], + 2: [] + } + } + ], + variables: [ + { + 'id': 'e621e8ff-42a6-499c-8121-33c7c35d8641', + 'name': 'age', + 'type': 'integer', + 'value': 11 + }, + { + 'id': '4f8aa99e-8526-429c-9d99-809978489d96', + 'name': 'name', + 'type': 'string', + 'value': 'abc' + }, + { + 'id': '0207b649-ff07-4f3a-a589-d10afa507b9b', + 'name': 'dob', + 'type': 'date', + 'value': '2019-05-13' + } + ] +}; + export const complexVisibilityJsonVisible: any = { 'id': 47591, 'name': 'Test-visibility',