From 6da489a7ff7115ef120092d0f94f6b6d733d4234 Mon Sep 17 00:00:00 2001 From: siva kumar Date: Wed, 13 May 2020 14:56:12 +0530 Subject: [PATCH] [ACA-3235] FE - Should not include invisible fields in payload on Start/Save adf-form. (#5681) * [ACA-3235] FE - Should not include invisible fields in payload on Start/Save adf-form. * * Added unit test to the recent changes --- .../form-field/form-field.component.spec.ts | 73 +++ .../form-field/form-field.component.ts | 1 + .../mock/form-renderer.component.mock.ts | 438 ++++++++++++++++++ .../widget-visibility.service.spec.ts | 52 +++ .../services/widget-visibility.service.ts | 18 +- 5 files changed, 581 insertions(+), 1 deletion(-) diff --git a/lib/core/form/components/form-field/form-field.component.spec.ts b/lib/core/form/components/form-field/form-field.component.spec.ts index 55ebc1019c..a960b02441 100644 --- a/lib/core/form/components/form-field/form-field.component.spec.ts +++ b/lib/core/form/components/form-field/form-field.component.spec.ts @@ -26,6 +26,7 @@ import { FormBaseModule } from '../../form-base.module'; import { TranslationService } from '../../../services/translation.service'; import { TranslationMock } from '../../../mock/translation.service.mock'; import { TranslateStore } from '@ngx-translate/core'; +import { formWithOneVisibleAndOneInvisibleFieldMock, formWithOneVisibleAndOneInvisibleTabMock } from '../mock/form-renderer.component.mock'; describe('FormFieldComponent', () => { @@ -152,6 +153,78 @@ describe('FormFieldComponent', () => { expect(fixture.nativeElement.querySelector('#field-FAKE-TXT-WIDGET-container').hidden).toBeTruthy(); }); + it('Should remove invisible field value from the form values', (done) => { + const fakeFormWithField = new FormModel(formWithOneVisibleAndOneInvisibleFieldMock); + const mockNameFiled = fakeFormWithField.getFormFields().find((field) => field.id === 'mockname'); + const mockMobileFiled = fakeFormWithField.getFormFields().find((field) => field.id === 'mockmobilenumber'); + + expect(mockNameFiled.name).toBe('Mock Name', 'Visibile field'); + expect(mockMobileFiled.name).toBe('Mock Mobile Number', 'Invisible field'); + + component.field = mockNameFiled; + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(component.field.form.values).toEqual({ mockname: 'Mock value' }); + expect(component.field.form.values[mockNameFiled.id]).toBeDefined(); + expect(component.field.form.values[mockMobileFiled.id]).not.toBeDefined(); + done(); + }); + }); + + it('Should remove invisible tab fields value from the form values', (done) => { + const fakeFormWithTab = new FormModel(formWithOneVisibleAndOneInvisibleTabMock); + + const tabOneNameField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockname'); + const tabOneMobileField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockmobilenumber'); + + const tabTwoAddressField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockaddress'); + const tabTwoEmailField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockemail'); + + expect(tabOneNameField.name).toBe('Mock Name', 'Visibile field'); + expect(tabOneMobileField.name).toBe('Mock Mobile Number', 'Invisible field'); + + expect(tabTwoEmailField.name).toBe('Mock Email', 'Invisible field'); + expect(tabTwoAddressField.name).toBe('Mock Address', 'Invisible field'); + + component.field = tabOneNameField; + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(component.field.form.values).toEqual({ mockname: null }); + expect(component.field.form.values[tabOneNameField.id]).toBeDefined(); + expect(component.field.form.values[tabOneMobileField.id]).not.toBeDefined(); + expect(component.field.form.values[tabTwoAddressField.id]).not.toBeDefined(); + expect(component.field.form.values[tabTwoEmailField.id]).not.toBeDefined(); + done(); + }); + }); + + it('Should add tab invisible fields value to the form values if the tab get visible', (done) => { + const fakeFormWithTab = new FormModel(formWithOneVisibleAndOneInvisibleTabMock); + + const tabOneNameField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockname'); + const tabOneMobileField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockmobilenumber'); + + const tabTwoAddressField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockaddress'); + const tabTwoEmailField = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockemail'); + + expect(tabOneNameField.name).toBe('Mock Name', 'Visibile field'); + expect(tabOneMobileField.name).toBe('Mock Mobile Number', 'Invisible field'); + + expect(tabTwoEmailField.name).toBe('Mock Email', 'Invisible field'); + expect(tabTwoAddressField.name).toBe('Mock Address', 'Invisible field'); + + component.field = tabOneNameField; + component.field.value = 'test'; + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(component.field.form.values).toEqual({ mockname: 'test', mockmobilenumber: null, mockemail: null, mockaddress: null }); + done(); + }); + }); + it('[C213878] - Should fields be correctly rendered when filled with process variables', async () => { const field = new FormFieldModel(form, { fieldType: 'HyperlinkRepresentation', diff --git a/lib/core/form/components/form-field/form-field.component.ts b/lib/core/form/components/form-field/form-field.component.ts index 4108359560..0b0c9eecb1 100644 --- a/lib/core/form/components/form-field/form-field.component.ts +++ b/lib/core/form/components/form-field/form-field.component.ts @@ -98,6 +98,7 @@ export class FormFieldComponent implements OnInit, OnDestroy { instance.fieldChanged.subscribe((field) => { if (field && this.field.form) { this.visibilityService.refreshVisibility(field.form); + this.visibilityService.removeInvisibleFormValues(field.form); field.form.onFormFieldChanged(field); } }); diff --git a/lib/core/form/components/mock/form-renderer.component.mock.ts b/lib/core/form/components/mock/form-renderer.component.mock.ts index 6191bf385b..d0c712499c 100644 --- a/lib/core/form/components/mock/form-renderer.component.mock.ts +++ b/lib/core/form/components/mock/form-renderer.component.mock.ts @@ -1334,3 +1334,441 @@ export const radioWidgetVisibiltyForm = { } } }; + +export const formWithOneVisibleAndOneInvisibleFieldMock = { + tabs: [], + fields: [ + { + fieldType: 'ContainerRepresentation', + id: '1588915084743', + 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: 'mockname', + name: 'Mock Name', + type: 'text', + value: 'Mock value', + 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: 'mockmobilenumber', + name: 'Mock Mobile Number', + type: 'text', + value: 'Mock invisible value', + required: false, + readOnly: false, + overrideId: false, + isVisible: 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: { + leftFormFieldId: 'mockname', + leftRestResponseId: null, + operator: '==', + rightValue: 'test', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + ] + } + } + ], + outcomes: [], + javascriptEvents: [], + className: '', + style: '', + customFieldTemplates: {}, + metadata: {}, + variables: [], + customFieldsValueInfo: {}, + gridsterForm: false +}; + +export const formWithOneVisibleAndOneInvisibleTabMock = { + tabs: [ + { + id: 'tab1', + title: 'TabOne', + visibilityCondition: null + }, + { + id: 'tab2', + title: 'TabTwo', + visibilityCondition: { + leftFormFieldId: 'mockname', + leftRestResponseId: null, + operator: '==', + rightValue: 'test', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + ], + fields: [ + { + fieldType: 'ContainerRepresentation', + id: '1588931207573', + 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: 'tab2', + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + '1': [ + { + fieldType: 'FormFieldRepresentation', + id: 'mockaddress', + name: 'Mock Address', + type: 'text', + 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: 'tab2', + 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: 'mockemail', + name: 'Mock Email', + type: 'text', + 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: 'tab2', + 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: '1588915084743', + 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: 'tab1', + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + '1': [ + { + fieldType: 'FormFieldRepresentation', + id: 'mockname', + name: 'Mock Name', + type: 'text', + 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: 'tab1', + 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: 'mockmobilenumber', + name: 'Mock Mobile Number', + type: 'text', + 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: 'tab1', + 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: { + leftFormFieldId: 'mockname', + leftRestResponseId: null, + operator: '==', + rightValue: 'test', + rightType: null, + rightFormFieldId: '', + rightRestResponseId: '', + nextConditionOperator: '', + nextCondition: null + } + } + ] + } + } + ], + outcomes: [], + javascriptEvents: [], + className: '', + style: '', + customFieldTemplates: {}, + metadata: {}, + variables: [], + customFieldsValueInfo: {}, + gridsterForm: false +}; diff --git a/lib/core/form/services/widget-visibility.service.spec.ts b/lib/core/form/services/widget-visibility.service.spec.ts index 59daa792ca..18304160b0 100644 --- a/lib/core/form/services/widget-visibility.service.spec.ts +++ b/lib/core/form/services/widget-visibility.service.spec.ts @@ -36,6 +36,7 @@ import { fakeTaskProcessVariableModels, formValues, complexVisibilityJsonVisible, complexVisibilityJsonNotVisible, tabVisibilityJsonMock, tabInvalidFormVisibility } from 'core/mock/form/widget-visibility.service.mock'; +import { formWithOneVisibleAndOneInvisibleFieldMock, formWithOneVisibleAndOneInvisibleTabMock } from '../components/mock/form-renderer.component.mock'; declare let jasmine: any; @@ -1056,4 +1057,55 @@ describe('WidgetVisibilityService', () => { expect(invalidTabVisibilityJsonModel.isValid).toBeTruthy(); }); }); + + describe('Remove invisible field values', () => { + + let fakeFormWithField: FormModel; + let fakeFormWithTab: FormModel; + + beforeEach(() => { + fakeFormWithField = new FormModel(formWithOneVisibleAndOneInvisibleFieldMock); + fakeFormWithTab = new FormModel(formWithOneVisibleAndOneInvisibleTabMock); + }); + + it('Should remove invisible field value from the form values', () => { + service.refreshVisibility(fakeFormWithField); + service.removeInvisibleFormValues(fakeFormWithField); + expect(fakeFormWithField.values).toEqual({ mockname: 'Mock value' }); + }); + + it('Should be able to add field value to the form values if the field get visible', () => { + service.refreshVisibility(fakeFormWithField); + service.removeInvisibleFormValues(fakeFormWithField); + expect(fakeFormWithField.values).toEqual({ mockname: 'Mock value' }); + + const mockNameFiled = fakeFormWithField.getFormFields().find((field) => field.id === 'mockname'); + mockNameFiled.value = 'test'; + mockNameFiled.updateForm(); + + service.refreshVisibility(fakeFormWithField); + service.removeInvisibleFormValues(fakeFormWithField); + expect(fakeFormWithField.values).toEqual({ mockname: 'test', mockmobilenumber: 'Mock invisible value' }); + }); + + it('Should be able to remove invisible tab fields value from the form values', () => { + service.refreshVisibility(fakeFormWithTab); + expect(fakeFormWithTab.values).toEqual({ mockname: null, mockmobilenumber: null, mockemail: null, mockaddress: null }); + service.removeInvisibleFormValues(fakeFormWithTab); + expect(fakeFormWithTab.values).toEqual({ mockname: null }); + }); + + it('Should be able to add tab fields value to the form values if the tab get visible', () => { + service.refreshVisibility(fakeFormWithTab); + expect(fakeFormWithTab.values).toEqual({ mockname: null, mockmobilenumber: null, mockemail: null, mockaddress: null }); + + const mockNameFiled = fakeFormWithTab.getFormFields().find((field) => field.id === 'mockname'); + mockNameFiled.value = 'test'; + mockNameFiled.updateForm(); + + service.refreshVisibility(fakeFormWithTab); + service.removeInvisibleFormValues(fakeFormWithTab); + expect(fakeFormWithTab.values).toEqual({ mockname: 'test', mockmobilenumber: null, mockemail: null, mockaddress: null }); + }); + }); }); diff --git a/lib/core/form/services/widget-visibility.service.ts b/lib/core/form/services/widget-visibility.service.ts index af080159f1..3d5f2a89b6 100644 --- a/lib/core/form/services/widget-visibility.service.ts +++ b/lib/core/form/services/widget-visibility.service.ts @@ -20,7 +20,7 @@ import { LogService } from '../../services/log.service'; import { Injectable } from '@angular/core'; import moment from 'moment-es6'; import { Observable, from, throwError } from 'rxjs'; -import { FormFieldModel, FormModel, TabModel, ContainerModel } from '../components/widgets/core/index'; +import { FormFieldModel, FormModel, TabModel, ContainerModel, FormFieldTypes } from '../components/widgets/core/index'; import { TaskProcessVariableModel } from '../models/task-process-variable.model'; import { WidgetVisibilityModel, WidgetTypeEnum } from '../models/widget-visibility.model'; import { map, catchError } from 'rxjs/operators'; @@ -323,6 +323,22 @@ export class WidgetVisibilityService { return res || {}; } + removeInvisibleFormValues(formModel: FormModel) { + if (formModel) { + formModel.getFormFields().map((field: FormFieldModel) => { + if (field.type !== FormFieldTypes.CONTAINER) { + if (!field.isVisible) { + delete formModel.values[field.id]; + } else { + field.updateForm(); + } + } + return field; + }); + } + return formModel; + } + private isValidOperator(operator: string): boolean { return operator !== undefined; }