From d41aa9fbc6622533c5250a20f5d77be545631f3a Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Mon, 14 Jan 2019 12:17:39 +0100 Subject: [PATCH] Added tests --- .../builder/parsers/onebox-field-parser.ts | 26 +- .../shared/mocks/mock-form-builder-service.ts | 6 +- src/app/shared/mocks/mock-form-models.ts | 244 ++++++ .../section-form-operations.service.spec.ts | 761 ++++++++++++++++++ .../form/section-form-operations.service.ts | 13 +- 5 files changed, 1022 insertions(+), 28 deletions(-) create mode 100644 src/app/shared/mocks/mock-form-models.ts create mode 100644 src/app/submission/sections/form/section-form-operations.service.spec.ts diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.ts index e1c5f40039..d347f38eee 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.ts @@ -20,7 +20,7 @@ export class OneboxFieldParser extends FieldParser { public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { if (this.configData.selectableMetadata.length > 1) { - // Case ComboBox + // Case Qualdrop Model const clsGroup = { element: { control: 'form-row', @@ -73,29 +73,13 @@ export class OneboxFieldParser extends FieldParser { const typeaheadModelConfig: DsDynamicTypeaheadModelConfig = this.initModel(null, label); this.setAuthorityOptions(typeaheadModelConfig, this.parserOptions.authorityUuid); this.setValues(typeaheadModelConfig, fieldValue, true); - const typeaheadModel = new DynamicTypeaheadModel(typeaheadModelConfig); -/* typeaheadModel.languageCodes = [{ - display: 'English', - code: 'en_US' - }, - { - display: 'Italian', - code: 'it_IT' - }];*/ - return typeaheadModel; + + return new DynamicTypeaheadModel(typeaheadModelConfig); } else { const inputModelConfig: DsDynamicInputModelConfig = this.initModel(null, label); this.setValues(inputModelConfig, fieldValue); - const inputModel = new DsDynamicInputModel(inputModelConfig); -/* inputModel.languageCodes = [{ - display: 'English', - code: 'en_US' - }, - { - display: 'Italian', - code: 'it_IT' - }];*/ - return inputModel; + + return new DsDynamicInputModel(inputModelConfig); } } } diff --git a/src/app/shared/mocks/mock-form-builder-service.ts b/src/app/shared/mocks/mock-form-builder-service.ts index 9f329032db..e37df20e13 100644 --- a/src/app/shared/mocks/mock-form-builder-service.ts +++ b/src/app/shared/mocks/mock-form-builder-service.ts @@ -13,7 +13,11 @@ export function getMockFormBuilderService(): FormBuilderService { getId: 'path', clearAllModelsValue : {}, insertFormArrayGroup: {}, - isQualdrop: false + isQualdrop: false, + isQualdropGroup: false, + isModelInCustomGroup: true, + isRelationGroup: true, + hasArrayGroupValue: true }); diff --git a/src/app/shared/mocks/mock-form-models.ts b/src/app/shared/mocks/mock-form-models.ts new file mode 100644 index 0000000000..f3973abf63 --- /dev/null +++ b/src/app/shared/mocks/mock-form-models.ts @@ -0,0 +1,244 @@ +import { DsDynamicInputModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model'; +import { DynamicQualdropModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; +import { + DynamicRowArrayModel, + DynamicRowArrayModelConfig +} from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; +import { DynamicSelectModel } from '@ng-dynamic-forms/core'; +import { FormRowModel } from '../../core/config/models/config-submission-forms.model'; +import { SubmissionScopeType } from '../../core/submission/submission-scope-type'; +import { DynamicRelationGroupModel } from '../form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; +import { FormFieldModel } from '../form/builder/models/form-field.model'; +import { AuthorityOptions } from '../../core/integration/models/authority-options.model'; +import { AuthorityValue } from '../../core/integration/models/authority.value'; +import { FormFieldMetadataValueObject } from '../form/builder/models/form-field-metadata-value.model'; +import { DynamicRowGroupModel } from '../form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; + +export const qualdropSelectConfig = { + name: 'dc.identifier_QUALDROP_METADATA', + id: 'dc_identifier_QUALDROP_METADATA', + readOnly: false, + disabled: false, + label: 'Identifiers', + placeholder: 'Identifiers', + options: [ + { + label: 'ISSN', + value: 'dc.identifier.issn' + }, + { + label: 'Other', + value: 'dc.identifier.other' + }, + { + label: 'ISMN', + value: 'dc.identifier.ismn' + }, + { + label: 'Gov\'t Doc #', + value: 'dc.identifier.govdoc' + }, + { + label: 'URI', + value: 'dc.identifier.uri' + }, + { + label: 'ISBN', + value: 'dc.identifier.isbn' + } + ], + value: 'dc.identifier.issn' +}; + +export const qualdropInputConfig = { + name: 'dc.identifier_QUALDROP_VALUE', + id: 'dc_identifier_QUALDROP_VALUE', + readOnly: false, + disabled: false, + value: 'test' +}; + +export const mockQualdropSelectModel = new DynamicSelectModel(qualdropSelectConfig); +export const mockQualdropInputModel = new DsDynamicInputModel(qualdropInputConfig); + +export const qualdropConfig = { + id: 'dc_identifier_QUALDROP_GROUP', + legend: 'Identifiers', + readOnly: false, + group: [mockQualdropSelectModel, mockQualdropInputModel] +}; + +export const MockQualdropModel = new DynamicQualdropModel(qualdropConfig); + +const rowArrayQualdropConfig = { + id: 'row_QUALDROP_GROUP', + initialCount: 1, + notRepeatable: true, + groupFactory: () => { + return [MockQualdropModel]; + } +} as DynamicRowArrayModelConfig; + +export const MockRowArrayQualdropModel: DynamicRowArrayModel = new DynamicRowArrayModel(rowArrayQualdropConfig); + +const mockFormRowModel = { + fields: [ + { + input: {type: 'lookup'}, + label: 'Journal', + mandatory: 'false', + repeatable: false, + hints: 'Enter the name of the journal where the item has been\n\t\t\t\t\tpublished, if any.', + selectableMetadata: [ + { + metadata: 'journal', + authority: 'JOURNALAuthority', + closed: false + } + ], + languageCodes: [] + } as FormFieldModel, + { + input: {type: 'onebox'}, + label: 'Issue', + mandatory: 'false', + repeatable: false, + hints: ' Enter issue number.', + selectableMetadata: [ + { + metadata: 'issue' + } + ], + languageCodes: [] + } as FormFieldModel + ] +} as FormRowModel; + +const relationGroupConfig = { + id: 'relationGroup', + formConfiguration: [mockFormRowModel], + mandatoryField: 'false', + relationFields: ['journal', 'issue'], + scopeUUID: 'scope', + submissionScope: SubmissionScopeType.WorkspaceItem, + value: { + journal: [ + 'journal test 1', + 'journal test 2' + ], + issue: [ + 'issue test 1', + 'issue test 2' + ], + } +}; + +export const MockRelationModel: DynamicRelationGroupModel = new DynamicRelationGroupModel(relationGroupConfig); + +export const inputWithLanguageAndAuthorityConfig = { + authorityOptions: new AuthorityOptions('testAuthority', 'testWithAuthority', 'scope'), + languageCodes: [ + { + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + } + ], + language: 'en_US', + name: 'testWithAuthority', + id: 'testWithAuthority', + readOnly: false, + disabled: false, + value: { + value: 'testWithLanguageAndAuthority', + display: 'testWithLanguageAndAuthority', + id: 'testWithLanguageAndAuthority', + } +}; + +export const mockInputWithLanguageAndAuthorityModel = new DsDynamicInputModel(inputWithLanguageAndAuthorityConfig); + +export const inputWithLanguageConfig = { + languageCodes: [ + { + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + } + ], + language: 'en_US', + name: 'testWithLanguage', + id: 'testWithLanguage', + readOnly: false, + disabled: false, + value: 'testWithLanguage' +}; + +export const mockInputWithLanguageModel = new DsDynamicInputModel(inputWithLanguageConfig); + +export const inputWithLanguageAndAuthorityArrayConfig = { + authorityOptions: new AuthorityOptions('testAuthority', 'testWithAuthority', 'scope'), + languageCodes: [ + { + display: 'English', + code: 'en_US' + }, + { + display: 'Italian', + code: 'it_IT' + } + ], + language: 'en_US', + name: 'testWithLanguageAndAuthorityArray', + id: 'testWithLanguageAndAuthorityArray', + readOnly: false, + disabled: false, + value: [{ + value: 'testLanguageAndAuthorityArray', + display: 'testLanguageAndAuthorityArray', + id: 'testLanguageAndAuthorityArray', + }] +}; + +export const mockInputWithLanguageAndAuthorityArrayModel = new DsDynamicInputModel(inputWithLanguageAndAuthorityArrayConfig); + +export const inputWithFormFieldValueConfig = { + name: 'testWithFormField', + id: 'testWithFormField', + readOnly: false, + disabled: false, + value: new FormFieldMetadataValueObject('testWithFormFieldValue') +}; + +export const mockInputWithFormFieldValueModel = new DsDynamicInputModel(inputWithFormFieldValueConfig); + +export const inputWithAuthorityValueConfig = { + name: 'testWithAuthorityField', + id: 'testWithAuthorityField', + readOnly: false, + disabled: false, + value: Object.assign({}, new AuthorityValue(), { value: 'testWithAuthorityValue', id: 'testWithAuthorityValue', display: 'testWithAuthorityValue' }) +}; + +export const mockInputWithAuthorityValueModel = new DsDynamicInputModel(inputWithAuthorityValueConfig); + +export const inputWithObjectValueConfig = { + name: 'testWithObjectValue', + id: 'testWithObjectValue', + readOnly: false, + disabled: false, + value: { value: 'testWithObjectValue', id: 'testWithObjectValue', display: 'testWithObjectValue' } +}; + +export const mockInputWithObjectValueModel = new DsDynamicInputModel(inputWithObjectValueConfig); + +export const mockRowGroupModel = new DynamicRowGroupModel({ + id: 'mockRowGroupModel', + group: [mockInputWithFormFieldValueModel], +}); diff --git a/src/app/submission/sections/form/section-form-operations.service.spec.ts b/src/app/submission/sections/form/section-form-operations.service.spec.ts new file mode 100644 index 0000000000..1519da7557 --- /dev/null +++ b/src/app/submission/sections/form/section-form-operations.service.spec.ts @@ -0,0 +1,761 @@ +import { async, TestBed } from '@angular/core/testing'; + +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { + DYNAMIC_FORM_CONTROL_TYPE_ARRAY, + DYNAMIC_FORM_CONTROL_TYPE_GROUP, + DynamicFormControlEvent +} from '@ng-dynamic-forms/core'; + +import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; +import { getMockFormBuilderService } from '../../../shared/mocks/mock-form-builder-service'; +import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; +import { MockTranslateLoader } from '../../../shared/mocks/mock-translate-loader'; +import { SectionFormOperationsService } from './section-form-operations.service'; +import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; +import { FormFieldPreviousValueObject } from '../../../shared/form/builder/models/form-field-previous-value-object'; +import { + mockInputWithAuthorityValueModel, + mockInputWithFormFieldValueModel, + mockInputWithLanguageAndAuthorityArrayModel, + mockInputWithLanguageAndAuthorityModel, + mockInputWithLanguageModel, + mockInputWithObjectValueModel, + mockQualdropInputModel, + MockQualdropModel, + MockRelationModel, + mockRowGroupModel +} from '../../../shared/mocks/mock-form-models'; +import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; +import { AuthorityValue } from '../../../core/integration/models/authority.value'; + +describe('SectionFormOperationsService test suite', () => { + let formBuilderService: any; + let service: SectionFormOperationsService; + let serviceAsAny: any; + + const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { + add: jasmine.createSpy('add'), + replace: jasmine.createSpy('replace'), + remove: jasmine.createSpy('remove'), + }); + const pathCombiner = new JsonPatchOperationPathCombiner('sections', 'test'); + + const dynamicFormControlChangeEvent: DynamicFormControlEvent = { + $event: new Event('change'), + context: null, + control: null, + group: null, + model: null, + type: 'change' + }; + + const dynamicFormControlRemoveEvent: DynamicFormControlEvent = { + $event: new Event('change'), + context: null, + control: null, + group: null, + model: null, + type: 'remove' + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: MockTranslateLoader + } + }) + ], + providers: [ + { provide: FormBuilderService, useValue: getMockFormBuilderService() }, + { provide: JsonPatchOperationsBuilder, useValue: jsonPatchOpBuilder }, + SectionFormOperationsService + ] + }).compileComponents().then(); + })); + + beforeEach(() => { + service = TestBed.get(SectionFormOperationsService); + serviceAsAny = service; + formBuilderService = TestBed.get(FormBuilderService); + }); + + describe('dispatchOperationsFromEvent', () => { + it('should call dispatchOperationsFromRemoveEvent on remove event', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + spyOn(serviceAsAny, 'dispatchOperationsFromRemoveEvent'); + + service.dispatchOperationsFromEvent(pathCombiner, dynamicFormControlRemoveEvent, previousValue, true); + + expect(serviceAsAny.dispatchOperationsFromRemoveEvent).toHaveBeenCalled(); + }); + + it('should call dispatchOperationsFromChangeEvent on change event', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + spyOn(serviceAsAny, 'dispatchOperationsFromChangeEvent'); + + service.dispatchOperationsFromEvent(pathCombiner, dynamicFormControlChangeEvent, previousValue, true); + + expect(serviceAsAny.dispatchOperationsFromChangeEvent).toHaveBeenCalled(); + }); + }); + + describe('getArrayIndexFromEvent', () => { + it('should return the index of the array to which the element belongs', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + context: { + index: 1 + } + }); + + expect(service.getArrayIndexFromEvent(event)).toBe(1); + }); + + it('should return the index of the array to which the parent element belongs', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: { + parent: { + index: 2 + } + } + } + }); + spyOn(serviceAsAny, 'isPartOfArrayOfGroup').and.returnValue(true); + + expect(service.getArrayIndexFromEvent(event)).toBe(2); + }); + + it('should return zero when element doesn\'t belong to an array', () => { + + spyOn(serviceAsAny, 'isPartOfArrayOfGroup').and.returnValue(false); + + expect(service.getArrayIndexFromEvent(dynamicFormControlChangeEvent)).toBe(0); + }); + + it('should return zero when event is empty', () => { + + expect(service.getArrayIndexFromEvent(null)).toBe(0); + }); + + }); + + describe('isPartOfArrayOfGroup', () => { + it('should return true when parent element belongs to an array group element', () => { + const model = { + parent: { + type: DYNAMIC_FORM_CONTROL_TYPE_GROUP, + parent: { + context: { + type: DYNAMIC_FORM_CONTROL_TYPE_ARRAY + } + } + } + }; + + expect(service.isPartOfArrayOfGroup(model)).toBeTruthy(); + }); + + it('should return false when parent element doesn\'t belong to an array group element', () => { + const model = { + parent: null + }; + + expect(service.isPartOfArrayOfGroup(model)).toBeFalsy(); + }); + + }); + + describe('getQualdropValueMap', () => { + it('should return map properly', () => { + const context = { + groups: [ + { + group: [MockQualdropModel] + } + ] + }; + const model = { + parent: { + parent: { + context: context + } + } + }; + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: model + }); + const expectMap = new Map(); + expectMap.set(MockQualdropModel.qualdropId, [MockQualdropModel.value]); + + formBuilderService.isQualdropGroup.and.returnValue(false); + + expect(service.getQualdropValueMap(event)).toEqual(expectMap); + }); + + it('should return map properly when model is DynamicQualdropModel', () => { + const context = { + groups: [ + { + group: [MockQualdropModel] + } + ] + }; + const model = { + parent: { + context: context + } + }; + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: model + }); + const expectMap = new Map(); + expectMap.set(MockQualdropModel.qualdropId, [MockQualdropModel.value]); + + formBuilderService.isQualdropGroup.and.returnValue(true); + + expect(service.getQualdropValueMap(event)).toEqual(expectMap); + }); + }); + + describe('getFieldPathFromEvent', () => { + it('should field path properly', () => { + const spy = spyOn(serviceAsAny, 'getArrayIndexFromEvent'); + spy.and.returnValue(1); + spyOn(serviceAsAny, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + + expect(service.getFieldPathFromEvent(dynamicFormControlChangeEvent)).toBe('path/1'); + + spy.and.returnValue(undefined); + + expect(service.getFieldPathFromEvent(dynamicFormControlChangeEvent)).toBe('path'); + }); + }); + + describe('getQualdropItemPathFromEvent', () => { + it('should return path properly', () => { + const context = { + groups: [ + { + group: [MockQualdropModel] + } + ] + }; + const model = { + parent: { + parent: { + context: context + } + } + }; + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: model + }); + const expectPath = 'dc.identifier.issn/0'; + spyOn(serviceAsAny, 'getArrayIndexFromEvent').and.returnValue(0); + + formBuilderService.isQualdropGroup.and.returnValue(false); + + expect(service.getQualdropItemPathFromEvent(event)).toEqual(expectPath); + }); + + it('should return path properly when model is DynamicQualdropModel', () => { + const context = { + groups: [ + { + group: [MockQualdropModel] + } + ] + }; + const model = { + parent: { + context: context + } + }; + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: model + }); + const expectPath = 'dc.identifier.issn/0'; + spyOn(serviceAsAny, 'getArrayIndexFromEvent').and.returnValue(0); + + formBuilderService.isQualdropGroup.and.returnValue(true); + + expect(service.getQualdropItemPathFromEvent(event)).toEqual(expectPath); + }); + }); + + describe('getFieldPathSegmentedFromChangeEvent', () => { + it('should return field segmented path properly', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockQualdropInputModel + }); + formBuilderService.isQualdropGroup.and.returnValues(false, false); + + expect(service.getFieldPathSegmentedFromChangeEvent(event)).toEqual('path'); + }); + + it('should return field segmented path properly when model is DynamicQualdropModel', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: MockQualdropModel + }); + formBuilderService.isQualdropGroup.and.returnValue(true); + + expect(service.getFieldPathSegmentedFromChangeEvent(event)).toEqual('dc.identifier.issn'); + }); + + it('should return field segmented path properly when model belongs to a DynamicQualdropModel', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: MockQualdropModel + } + }); + formBuilderService.isQualdropGroup.and.returnValues(false, true); + + expect(service.getFieldPathSegmentedFromChangeEvent(event)).toEqual('dc.identifier.issn'); + }); + + }); + + describe('getFieldValueFromChangeEvent', () => { + it('should return field value properly when model belongs to a DynamicQualdropModel', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: MockQualdropModel + } + }); + formBuilderService.isModelInCustomGroup.and.returnValue(true); + const expectedValue = 'test'; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + }); + + it('should return field value properly when model is DynamicRelationGroupModel', () => { + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: MockRelationModel + }); + formBuilderService.isModelInCustomGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(true); + const expectedValue = { + journal: [ + 'journal test 1', + 'journal test 2' + ], + issue: [ + 'issue test 1', + 'issue test 2' + ], + }; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + }); + + it('should return field value properly when model has language', () => { + let event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithLanguageModel + }); + formBuilderService.isModelInCustomGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + let expectedValue: any = new FormFieldMetadataValueObject(mockInputWithLanguageModel.value, 'en_US'); + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + + event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithLanguageAndAuthorityModel + }); + expectedValue = Object.assign(new AuthorityValue(), mockInputWithLanguageAndAuthorityModel.value, {language: mockInputWithLanguageAndAuthorityModel.language}); + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + + event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithLanguageAndAuthorityArrayModel + }); + expectedValue = [ + Object.assign(new AuthorityValue(), mockInputWithLanguageAndAuthorityArrayModel.value[0], + { language: mockInputWithLanguageAndAuthorityArrayModel.language } + ) + ]; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + }); + + it('should return field value properly when model has an object as value', () => { + let event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithFormFieldValueModel + }); + formBuilderService.isModelInCustomGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + let expectedValue: any = mockInputWithFormFieldValueModel.value; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + + event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithAuthorityValueModel + }); + expectedValue = mockInputWithAuthorityValueModel.value; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + + event = Object.assign({}, dynamicFormControlChangeEvent, { + model: mockInputWithObjectValueModel + }); + expectedValue = mockInputWithObjectValueModel.value; + + expect(service.getFieldValueFromChangeEvent(event)).toEqual(expectedValue); + }); + }); + + describe('getValueMap', () => { + it('should return field segmented path properly when model belongs to a DynamicQualdropModel', () => { + const items = [ + { path: 'test1' }, + { path: 'test2' }, + { path1: 'test3' }, + ]; + const expectedMap = new Map(); + expectedMap.set('path', ['test1', 'test2']); + expectedMap.set('path1', ['test3']); + + expect(service.getValueMap(items)).toEqual(expectedMap); + }); + }); + + describe('dispatchOperationsFromRemoveEvent', () => { + it('should call dispatchOperationsFromMap when is Qualdrop Group model', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue('test'); + spyOn(serviceAsAny, 'getQualdropValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(true); + + serviceAsAny.dispatchOperationsFromRemoveEvent(pathCombiner, dynamicFormControlRemoveEvent, previousValue); + + expect(serviceAsAny.dispatchOperationsFromMap).toHaveBeenCalled(); + }); + + it('should dispatch a json-path remove operation', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue('test'); + formBuilderService.isQualdropGroup.and.returnValue(false); + + serviceAsAny.dispatchOperationsFromRemoveEvent(pathCombiner, dynamicFormControlRemoveEvent, previousValue); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalled(); + }); + + }); + + describe('dispatchOperationsFromChangeEvent', () => { + it('should call dispatchOperationsFromMap when is Qualdrop Group model', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: MockQualdropModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue('test'); + spyOn(serviceAsAny, 'getQualdropValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(true); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(serviceAsAny.getQualdropValueMap).toHaveBeenCalled(); + expect(serviceAsAny.dispatchOperationsFromMap).toHaveBeenCalled(); + }); + + it('should call dispatchOperationsFromMap when is Qualdrop Group model', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: MockRelationModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue('test'); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(true); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(serviceAsAny.getValueMap).toHaveBeenCalled(); + expect(serviceAsAny.dispatchOperationsFromMap).toHaveBeenCalled(); + }); + + it('should dispatch a json-path add operation', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue('test'); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(true); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith(pathCombiner.getPath('path'), 'test', true); + }); + + it('should dispatch a json-path remove operation when previous path is equal and there is no value', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + const spyPath = spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject()); + const spyIndex = spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path')); + + spyIndex.and.returnValue(1); + spyPath.and.returnValue('path/1'); + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path/1')); + }); + + it('should dispatch a json-path replace operation when previous path is equal and there is no value', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject('test')); + spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.replace).toHaveBeenCalledWith( + pathCombiner.getPath('path/0'), + new FormFieldMetadataValueObject('test')); + }); + + it('should dispatch a json-path remove operation when has a stored value', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + const spyPath = spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject()); + const spyIndex = spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(false); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path')); + + spyIndex.and.returnValue(1); + spyPath.and.returnValue('path/1'); + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path/1')); + }); + + it('should dispatch a json-path replace operation when has a stored value', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject('test')); + spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(false); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true); + + expect(jsonPatchOpBuilder.replace).toHaveBeenCalledWith( + pathCombiner.getPath('path/0'), + new FormFieldMetadataValueObject('test')); + }); + + it('should dispatch a json-path add operation when has a value and field index is zero or undefined', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + const spyPath = spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/0'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject('test')); + const spyIndex = spyOn(service, 'getArrayIndexFromEvent').and.returnValue(0); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(false); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath('path'), + new FormFieldMetadataValueObject('test'), + true); + + spyIndex.and.returnValue(undefined); + spyPath.and.returnValue('path'); + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, true); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath('path'), + new FormFieldMetadataValueObject('test'), + true); + }); + + it('should dispatch a json-path add operation when has a value', () => { + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], 'value'); + const event = Object.assign({}, dynamicFormControlChangeEvent, { + model: { + parent: mockRowGroupModel + } + }); + spyOn(service, 'getFieldPathFromEvent').and.returnValue('path/1'); + spyOn(service, 'getFieldPathSegmentedFromChangeEvent').and.returnValue('path'); + spyOn(service, 'getFieldValueFromChangeEvent').and.returnValue(new FormFieldMetadataValueObject('test')); + spyOn(service, 'getArrayIndexFromEvent').and.returnValue(1); + spyOn(serviceAsAny, 'getValueMap'); + spyOn(serviceAsAny, 'dispatchOperationsFromMap'); + formBuilderService.isQualdropGroup.and.returnValue(false); + formBuilderService.isRelationGroup.and.returnValue(false); + formBuilderService.hasArrayGroupValue.and.returnValue(false); + spyOn(previousValue, 'isPathEqual').and.returnValue(false); + + serviceAsAny.dispatchOperationsFromChangeEvent(pathCombiner, event, previousValue, false); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith( + pathCombiner.getPath('path/1'), + new FormFieldMetadataValueObject('test')); + }); + }); + + describe('dispatchOperationsFromMap', () => { + it('should dispatch a json-path remove operation when event type is remove', () => { + const valueMap = new Map(); + valueMap.set('path', ['testMap']); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], valueMap); + spyOn(serviceAsAny, 'getQualdropItemPathFromEvent').and.returnValue('path/test'); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlRemoveEvent, previousValue); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path/test')); + }); + + it('should dispatch a json-path add operation when a map has a new entry', () => { + const valueMap = new Map(); + valueMap.set('path', ['testMapNew']); + const previousValueMap = new Map(); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], previousValueMap); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlChangeEvent, previousValue); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith(pathCombiner.getPath('path'), ['testMapNew'], true); + }); + + it('should dispatch a json-path add operation when a map entry has changed', () => { + const valueMap = new Map(); + valueMap.set('path', ['testMapNew']); + const previousValueMap = new Map(); + previousValueMap.set('path', ['testMap']); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], previousValueMap); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlChangeEvent, previousValue); + + expect(jsonPatchOpBuilder.add).toHaveBeenCalledWith(pathCombiner.getPath('path'), ['testMapNew'], true); + }); + + it('should dispatch a json-path remove operation when a map entry has changed', () => { + const valueMap = new Map(); + valueMap.set('path', ['testMap']); + valueMap.set('path2', false); + const previousValueMap = new Map(); + previousValueMap.set('path', ['testMap']); + previousValueMap.set('path2', ['testMap2']); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], previousValueMap); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlChangeEvent, previousValue); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path2')); + }); + + it('should dispatch a json-path remove operation when current value is an empty map', () => { + const valueMap = new Map(); + const previousValueMap = new Map(); + previousValueMap.set('path', ['testMap']); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], previousValueMap); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlChangeEvent, previousValue); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path')); + }); + + it('should dispatch a json-path remove operation when current value has a null entry and previous value is an empty map', () => { + const valueMap = new Map(); + valueMap.set('path', [null]); + const previousValueMap = new Map(); + const previousValue = new FormFieldPreviousValueObject(['path', 'test'], previousValueMap); + spyOn(previousValue, 'isPathEqual').and.returnValue(true); + + serviceAsAny.dispatchOperationsFromMap(valueMap, pathCombiner, dynamicFormControlChangeEvent, previousValue); + + expect(jsonPatchOpBuilder.remove).toHaveBeenCalledWith(pathCombiner.getPath('path')); + }); + }) + +}); diff --git a/src/app/submission/sections/form/section-form-operations.service.ts b/src/app/submission/sections/form/section-form-operations.service.ts index 6423c559a5..9483c8d23e 100644 --- a/src/app/submission/sections/form/section-form-operations.service.ts +++ b/src/app/submission/sections/form/section-form-operations.service.ts @@ -27,10 +27,10 @@ export class SectionFormOperationsService { constructor(private formBuilder: FormBuilderService, private operationsBuilder: JsonPatchOperationsBuilder) { } - dispatchOperationsFromEvent(pathCombiner: JsonPatchOperationPathCombiner, - event: DynamicFormControlEvent, - previousValue: FormFieldPreviousValueObject, - hasStoredValue: boolean): void { + public dispatchOperationsFromEvent(pathCombiner: JsonPatchOperationPathCombiner, + event: DynamicFormControlEvent, + previousValue: FormFieldPreviousValueObject, + hasStoredValue: boolean): void { switch (event.type) { case 'remove': this.dispatchOperationsFromRemoveEvent(pathCombiner, event, previousValue); @@ -43,7 +43,7 @@ export class SectionFormOperationsService { } } - getArrayIndexFromEvent(event: DynamicFormControlEvent): number { + public getArrayIndexFromEvent(event: DynamicFormControlEvent): number { let fieldIndex: number; if (isNotEmpty(event)) { if (isNull(event.context)) { @@ -60,7 +60,7 @@ export class SectionFormOperationsService { return isNotUndefined(fieldIndex) ? fieldIndex : 0; } - isPartOfArrayOfGroup(model: any): boolean { + public isPartOfArrayOfGroup(model: any): boolean { return (isNotNull(model.parent) && (model.parent as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP && (model.parent as any).parent @@ -113,6 +113,7 @@ export class SectionFormOperationsService { path = groupModel.qualdropId + '/' + (metadataValueMap.get(groupModel.qualdropId).length - 1) } }); + return path; }