From 3fdb074d05e9c3bff420712880df02f66a66a901 Mon Sep 17 00:00:00 2001 From: Giuseppe Digilio Date: Tue, 19 Jun 2018 15:10:56 +0200 Subject: [PATCH] Added more tests --- .../ds-dynamic-form-control.component.spec.ts | 4 +- ....model.ts => ds-dynamic-qualdrop.model.ts} | 12 +- .../typeahead/dynamic-typeahead.model.ts | 1 - .../form/builder/form-builder.service.spec.ts | 760 ++++++++++++++++++ .../form/builder/form-builder.service.ts | 24 +- .../builder/parsers/concat-field-parser.ts | 14 +- .../builder/parsers/onebox-field-parser.ts | 22 +- 7 files changed, 801 insertions(+), 36 deletions(-) rename src/app/shared/form/builder/ds-dynamic-form-ui/models/{ds-dynamic-combobox.model.ts => ds-dynamic-qualdrop.model.ts} (82%) create mode 100644 src/app/shared/form/builder/form-builder.service.spec.ts diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts index 16dcce1cf9..3e24916899 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.spec.ts @@ -37,7 +37,7 @@ import { DynamicLookupModel } from './models/lookup/dynamic-lookup.model'; import { DynamicScrollableDropdownModel } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; import { DynamicTagModel } from './models/tag/dynamic-tag.model'; import { DynamicTypeaheadModel } from './models/typeahead/dynamic-typeahead.model'; -import { DynamicComboboxModel } from './models/ds-dynamic-combobox.model'; +import { DynamicQualdropModel } from './models/ds-dynamic-qualdrop.model'; describe('DsDynamicFormControlComponent test suite', () => { @@ -80,7 +80,7 @@ describe('DsDynamicFormControlComponent test suite', () => { }), new DynamicDsDatePickerModel({id: 'datepicker'}), new DynamicLookupModel({id: 'lookup', separator: ','}), - new DynamicComboboxModel({id: 'combobox', readOnly: false}) + new DynamicQualdropModel({id: 'combobox', readOnly: false}) ]; const testModel = formModel[8]; let formGroup: FormGroup; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-combobox.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model.ts similarity index 82% rename from src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-combobox.model.ts rename to src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model.ts index 2f260ff50d..fa91c0ad6b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-combobox.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model.ts @@ -4,24 +4,24 @@ import { Subject } from 'rxjs/Subject'; import { DynamicFormGroupModelConfig } from '@ng-dynamic-forms/core/src/model/form-group/dynamic-form-group.model'; import { LanguageCode } from '../../models/form-field-language-value.model'; -export const COMBOBOX_GROUP_SUFFIX = '_COMBO_GROUP'; -export const COMBOBOX_METADATA_SUFFIX = '_COMBO_METADATA'; -export const COMBOBOX_VALUE_SUFFIX = '_COMBO_VALUE'; +export const QUALDROP_GROUP_SUFFIX = '_QUALDROP_GROUP'; +export const QUALDROP_METADATA_SUFFIX = '_QUALDROP_METADATA'; +export const QUALDROP_VALUE_SUFFIX = '_QUALDROP_VALUE'; -export interface DsDynamicComboboxModelConfig extends DynamicFormGroupModelConfig { +export interface DsDynamicQualdropModelConfig extends DynamicFormGroupModelConfig { languageCodes?: LanguageCode[]; language?: string; readOnly: boolean; } -export class DynamicComboboxModel extends DynamicFormGroupModel { +export class DynamicQualdropModel extends DynamicFormGroupModel { @serializable() private _language: string; @serializable() private _languageCodes: LanguageCode[]; @serializable() languageUpdates: Subject; @serializable() hasLanguages = false; @serializable() readOnly: boolean; - constructor(config: DsDynamicComboboxModelConfig, layout?: DynamicFormControlLayout) { + constructor(config: DsDynamicQualdropModelConfig, layout?: DynamicFormControlLayout) { super(config, layout); this.readOnly = config.readOnly; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model.ts index fd68cf43ad..866055ed04 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model.ts @@ -1,6 +1,5 @@ import { AUTOCOMPLETE_OFF, DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core'; import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model'; -import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model'; export const DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD = 'TYPEAHEAD'; diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts new file mode 100644 index 0000000000..c31d5c39aa --- /dev/null +++ b/src/app/shared/form/builder/form-builder.service.spec.ts @@ -0,0 +1,760 @@ +import { inject, TestBed } from '@angular/core/testing'; +import { + FormArray, + FormControl, + FormGroup, + NG_ASYNC_VALIDATORS, + NG_VALIDATORS, + ReactiveFormsModule +} from '@angular/forms'; +import { + DynamicCheckboxGroupModel, + DynamicCheckboxModel, + DynamicColorPickerModel, + DynamicDatePickerModel, + DynamicEditorModel, + DynamicFileUploadModel, + DynamicFormArrayModel, + DynamicFormControlModel, + DynamicFormControlValue, + DynamicFormGroupModel, + DynamicFormService, + DynamicFormValidationService, + DynamicFormValueControlModel, + DynamicInputModel, + DynamicRadioGroupModel, + DynamicRatingModel, + DynamicSelectModel, + DynamicSliderModel, + DynamicSwitchModel, + DynamicTextAreaModel, + DynamicTimePickerModel +} from '@ng-dynamic-forms/core'; +import { DynamicTagModel } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model'; +import { DynamicListCheckboxGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model'; +import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; +import { DynamicScrollableDropdownModel } from './ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; +import { DynamicGroupModel } from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { DynamicLookupModel } from './ds-dynamic-form-ui/models/lookup/dynamic-lookup.model'; +import { DynamicDsDatePickerModel } from './ds-dynamic-form-ui/models/date-picker/date-picker.model'; +import { DynamicTypeaheadModel } from './ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.model'; +import { DynamicListRadioGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model'; +import { AuthorityOptions } from '../../../core/integration/models/authority-options.model'; +import { FormFieldModel } from './models/form-field.model'; +import { FormRowModel, SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model'; +import { FormBuilderService } from './form-builder.service'; +import { DynamicRowGroupModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; +import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model'; +import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model'; +import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-concat.model'; + +describe('FormBuilderService test suite', () => { + + let testModel: DynamicFormControlModel[]; + let testFormConfiguration: SubmissionFormsModel; + let service: FormBuilderService; + + function testValidator() { + return {testValidator: {valid: true}}; + } + + function testAsyncValidator() { + return new Promise((resolve) => setTimeout(() => resolve(true), 0)); + } + + beforeEach(() => { + + TestBed.configureTestingModule({ + imports: [ReactiveFormsModule], + providers: [ + FormBuilderService, + DynamicFormService, + DynamicFormValidationService, + {provide: NG_VALIDATORS, useValue: testValidator, multi: true}, + {provide: NG_ASYNC_VALIDATORS, useValue: testAsyncValidator, multi: true} + ] + }); + + const authorityOptions: AuthorityOptions = { + closed: false, + metadata: 'list', + name: 'type_programme', + scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23' + }; + + testModel = [ + + new DynamicSelectModel( + { + id: 'testSelect', + options: [ + { + label: 'Option 1', + value: 'option-1' + }, + { + label: 'Option 2', + value: 'option-2' + } + ], + value: 'option-3' + } + ), + + new DynamicInputModel( + { + id: 'testInput', + mask: ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/], + } + ), + + new DynamicCheckboxGroupModel( + { + id: 'testCheckboxGroup', + group: [ + new DynamicCheckboxModel( + { + id: 'testCheckboxGroup1', + value: true + } + ), + new DynamicCheckboxModel( + { + id: 'testCheckboxGroup2', + value: true + } + ) + ] + } + ), + + new DynamicRadioGroupModel( + { + id: 'testRadioGroup', + options: [ + { + label: 'Option 1', + value: 'option-1' + }, + { + label: 'Option 2', + value: 'option-2' + } + ], + value: 'option-3' + } + ), + + new DynamicTextAreaModel({id: 'testTextArea'}), + + new DynamicCheckboxModel({id: 'testCheckbox'}), + + new DynamicFormArrayModel( + { + id: 'testFormArray', + initialCount: 5, + groupFactory: () => { + return [ + new DynamicInputModel({id: 'testFormArrayGroupInput'}), + new DynamicFormArrayModel({ + id: 'testNestedFormArray', groupFactory: () => [ + new DynamicInputModel({id: 'testNestedFormArrayGroupInput'}) + ] + }) + ]; + } + } + ), + + new DynamicFormGroupModel( + { + id: 'testFormGroup', + group: [ + new DynamicInputModel({id: 'nestedTestInput'}), + new DynamicTextAreaModel({id: 'nestedTestTextArea'}) + ] + } + ), + + new DynamicSliderModel({id: 'testSlider'}), + + new DynamicSwitchModel({id: 'testSwitch'}), + + new DynamicDatePickerModel({id: 'testDatepicker', value: new Date()}), + + new DynamicFileUploadModel({id: 'testFileUpload'}), + + new DynamicEditorModel({id: 'testEditor'}), + + new DynamicTimePickerModel({id: 'testTimePicker'}), + + new DynamicRatingModel({id: 'testRating'}), + + new DynamicColorPickerModel({id: 'testColorPicker'}), + + new DynamicTypeaheadModel({id: 'testTypeahead'}), + + new DynamicScrollableDropdownModel({id: 'testScrollableDropdown', authorityOptions: authorityOptions}), + + new DynamicTagModel({id: 'testTag'}), + + new DynamicListCheckboxGroupModel({id: 'testCheckboxList', authorityOptions: authorityOptions, repeatable: true}), + + new DynamicListRadioGroupModel({id: 'testRadioList', authorityOptions: authorityOptions, repeatable: false}), + + new DynamicGroupModel({ + id: 'testRelationGroup', + formConfiguration: [{ + fields: [{ + hints: 'Enter the name of the author.', + input: {type: 'onebox'}, + label: 'Authors', + languageCodes: [], + mandatory: 'true', + mandatoryMessage: 'Required field!', + repeatable: false, + selectableMetadata: [{ + authority: 'RPAuthority', + closed: false, + metadata: 'dc.contributor.author' + }], + } as FormFieldModel] + } as FormRowModel, { + fields: [{ + hints: 'Enter the affiliation of the author.', + input: {type: 'onebox'}, + label: 'Affiliation', + languageCodes: [], + mandatory: 'false', + repeatable: false, + selectableMetadata: [{ + authority: 'OUAuthority', + closed: false, + metadata: 'local.contributor.affiliation' + }] + } as FormFieldModel] + } as FormRowModel], + mandatoryField: '', + name: 'testRelationGroup', + relationFields: [], + scopeUUID: '', + submissionScope: '' + }), + + new DynamicDsDatePickerModel({id: 'testDate'}), + + new DynamicLookupModel({id: 'testLookup', separator: ','}), + + new DynamicQualdropModel({id: 'testCombobox', readOnly: false}) + ]; + + testFormConfiguration = { + name: 'testFormConfiguration', + rows: [ + { + 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, + { + input: {type: 'name'}, + label: 'Name', + mandatory: 'false', + repeatable: false, + hints: 'Enter full name.', + selectableMetadata: [ + { + metadata: 'name' + } + ], + languageCodes: [] + } as FormFieldModel + ] + } as FormRowModel, + { + fields: [ + { + hints: 'If the item has any identification numbers or codes associated with↵ it, please enter the types and the actual numbers or codes.', + input: {type: 'onebox'}, + label: 'Identifiers', + languageCodes: [], + mandatory: 'false', + repeatable: false, + selectableMetadata: [ + {metadata: 'dc.identifier.issn', label: 'ISSN'}, + {metadata: 'dc.identifier.other', label: 'Other'}, + {metadata: 'dc.identifier.ismn', label: 'ISMN'}, + {metadata: 'dc.identifier.govdoc', label: 'Gov\'t Doc #'}, + {metadata: 'dc.identifier.uri', label: 'URI'}, + {metadata: 'dc.identifier.isbn', label: 'ISBN'}, + {metadata: 'dc.identifier.doi', label: 'DOI'}, + {metadata: 'dc.identifier.pmid', label: 'PubMed ID'}, + {metadata: 'dc.identifier.arxiv', label: 'arXiv'} + ] + }, { + input: {type: 'onebox'}, + label: 'Publisher', + mandatory: 'false', + repeatable: false, + hints: 'Enter the name of the publisher of the previously issued instance of this item.', + selectableMetadata: [ + { + metadata: 'publisher' + } + ], + languageCodes: [] + } + ] + } as FormRowModel, + { + fields: [ + { + input: {type: 'onebox'}, + label: 'Conference', + mandatory: 'false', + repeatable: false, + hints: 'Enter the name of the events, if any.', + selectableMetadata: [ + { + metadata: 'conference', + authority: 'EVENTAuthority', + closed: false + } + ], + languageCodes: [] + } + ] + } as FormRowModel + ], + self: 'testFormConfiguration.url', + type: 'submissionform', + _links: { + self: 'testFormConfiguration.url' + } + } + }); + + beforeEach(inject([FormBuilderService], (formService: FormBuilderService) => service = formService)); + + it('should find a dynamic form control model by id', () => { + + expect(service.findById('testCheckbox', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testCheckboxGroup', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testDatepicker', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testFormArray', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testInput', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testRadioGroup', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testSelect', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testSlider', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testSwitch', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testTextArea', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testFileUpload', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testEditor', testModel) instanceof DynamicEditorModel).toBe(true); + expect(service.findById('testTimePicker', testModel) instanceof DynamicTimePickerModel).toBe(true); + expect(service.findById('testRating', testModel) instanceof DynamicRatingModel).toBe(true); + expect(service.findById('testColorPicker', testModel) instanceof DynamicColorPickerModel).toBe(true); + }); + + it('should find a nested dynamic form control model by id', () => { + + expect(service.findById('testCheckboxGroup1', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('testCheckboxGroup2', testModel) instanceof DynamicFormControlModel).toBe(true); + expect(service.findById('nestedTestInput', testModel) instanceof DynamicFormControlModel).toBe(true); + }); + + it('should create an array of form models', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + + expect(formModel[0] instanceof DynamicRowGroupModel).toBe(true); + expect((formModel[0] as DynamicRowGroupModel).group.length).toBe(3); + expect((formModel[0] as DynamicRowGroupModel).get(0) instanceof DynamicLookupModel).toBe(true); + expect((formModel[0] as DynamicRowGroupModel).get(1) instanceof DsDynamicInputModel).toBe(true); + expect((formModel[0] as DynamicRowGroupModel).get(2) instanceof DynamicConcatModel).toBe(true); + + expect(formModel[1] instanceof DynamicRowGroupModel).toBe(true); + expect((formModel[1] as DynamicRowGroupModel).group.length).toBe(2); + expect((formModel[1] as DynamicRowGroupModel).get(0) instanceof DynamicQualdropModel).toBe(true); + expect(((formModel[1] as DynamicRowGroupModel).get(0) as DynamicQualdropModel).get(0) instanceof DynamicSelectModel).toBe(true); + expect(((formModel[1] as DynamicRowGroupModel).get(0) as DynamicQualdropModel).get(1) instanceof DsDynamicInputModel).toBe(true); + expect((formModel[1] as DynamicRowGroupModel).get(1) instanceof DsDynamicInputModel).toBe(true); + + expect(formModel[2] instanceof DynamicRowGroupModel).toBe(true); + expect((formModel[2] as DynamicRowGroupModel).group.length).toBe(1); + expect((formModel[2] as DynamicRowGroupModel).get(0) instanceof DynamicTypeaheadModel).toBe(true); + }); + + it('should return form\'s fields value from form model', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + let value = {} as any; + + expect(service.getValueFromModel(formModel)).toEqual(value); + + ((formModel[0] as DynamicRowGroupModel).get(1) as DsDynamicInputModel).valueUpdates.next('test'); + + value = { + issue: [new FormFieldMetadataValueObject('test')] + }; + expect(service.getValueFromModel(formModel)).toEqual(value); + + ((formModel[2] as DynamicRowGroupModel).get(0) as DynamicTypeaheadModel).valueUpdates.next('test one'); + value = { + issue: [new FormFieldMetadataValueObject('test')], + conference: [new FormFieldMetadataValueObject('test one')] + }; + expect(service.getValueFromModel(formModel)).toEqual(value); + }); + + it('should clear all form\'s fields value', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + const value = {} as any; + + ((formModel[0] as DynamicRowGroupModel).get(1) as DsDynamicInputModel).valueUpdates.next('test'); + ((formModel[2] as DynamicRowGroupModel).get(0) as DynamicTypeaheadModel).valueUpdates.next('test one'); + + service.clearAllModelsValue(formModel); + expect(((formModel[0] as DynamicRowGroupModel).get(1) as DynamicTypeaheadModel).value).toEqual(undefined) + expect(((formModel[2] as DynamicRowGroupModel).get(0) as DynamicTypeaheadModel).value).toEqual(undefined) + }); + + it('should return true when model has a custom group model as parent', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + let model = service.findById('dc_identifier_QUALDROP_VALUE', formModel); + let modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel); + model.parent = modelParent; + + expect(service.isModelInCustomGroup(model)).toBe(true); + + model = service.findById('name_CONCAT_FIRST_INPUT', formModel); + modelParent = service.findById('name_CONCAT_GROUP', formModel); + model.parent = modelParent; + + expect(service.isModelInCustomGroup(model)).toBe(true); + }); + + it('should return true when model value is an array', () => { + let model = service.findById('testCheckboxList', testModel) as DynamicFormArrayModel; + + expect(service.hasArrayGroupValue(model)).toBe(true); + + model = service.findById('testRadioList', testModel) as DynamicFormArrayModel; + + expect(service.hasArrayGroupValue(model)).toBe(true); + + model = service.findById('testTag', testModel) as DynamicFormArrayModel; + + expect(service.hasArrayGroupValue(model)).toBe(true); + }); + + it('should return true when model value is a map', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + const model = service.findById('dc_identifier_QUALDROP_VALUE', formModel); + const modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel); + model.parent = modelParent; + + expect(service.hasMappedGroupValue(model)).toBe(true); + }); + + it('should return true when model is a Qualdrop Group', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + const model = service.findById('dc_identifier_QUALDROP_GROUP', formModel); + + expect(service.isQualdropGroup(model)).toBe(true); + }); + + it('should return true when model is a Custom Group', () => { + const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID'); + let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel); + + expect(service.isCustomGroup(model)).toBe(true); + + model = service.findById('name_CONCAT_GROUP', formModel); + + expect(service.isCustomGroup(model)).toBe(true); + }); + + it('should return true when model is a List Group', () => { + let model = service.findById('testCheckboxList', testModel); + + expect(service.isListGroup(model)).toBe(true); + + model = service.findById('testRadioList', testModel); + + expect(service.isListGroup(model)).toBe(true); + }); + + it('should return true when model is a Relation Group', () => { + const model = service.findById('testRelationGroup', testModel); + + expect(service.isRelationGroup(model)).toBe(true); + }); + + it('should return properly form control by field id', () => { + const group = service.createFormGroup(testModel); + const control = group.controls.testLookup; + + expect(service.getFormControlById('testLookup', group, testModel)).toEqual(control); + }); + + it('should return field id from model', () => { + const model = service.findById('testRadioList', testModel); + + expect(service.getId(model)).toEqual('testRadioList'); + }); + + it('should create a form group', () => { + + const formGroup = service.createFormGroup(testModel); + + expect(formGroup instanceof FormGroup).toBe(true); + + expect(formGroup.get('testCheckbox') instanceof FormControl).toBe(true); + expect(formGroup.get('testCheckboxGroup') instanceof FormGroup).toBe(true); + expect(formGroup.get('testDatepicker') instanceof FormControl).toBe(true); + expect(formGroup.get('testFormArray') instanceof FormArray).toBe(true); + expect(formGroup.get('testInput') instanceof FormControl).toBe(true); + expect(formGroup.get('testRadioGroup') instanceof FormControl).toBe(true); + expect(formGroup.get('testSelect') instanceof FormControl).toBe(true); + expect(formGroup.get('testTextArea') instanceof FormControl).toBe(true); + expect(formGroup.get('testFileUpload') instanceof FormControl).toBe(true); + expect(formGroup.get('testEditor') instanceof FormControl).toBe(true); + expect(formGroup.get('testTimePicker') instanceof FormControl).toBe(true); + expect(formGroup.get('testRating') instanceof FormControl).toBe(true); + expect(formGroup.get('testColorPicker') instanceof FormControl).toBe(true); + }); + + it('should throw when unknown DynamicFormControlModel id is specified in JSON', () => { + + expect(() => service.fromJSON([{id: 'test'}])) + .toThrow(new Error(`unknown form control model type defined on JSON object with id "test"`)); + }); + + it('should resolve array group path', () => { + + service.createFormGroup(testModel); + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const nestedModel = (model.get(0).get(1) as DynamicFormArrayModel).get(0); + + expect(service.getPath(model)).toEqual(['testFormArray']); + expect(service.getPath(nestedModel)).toEqual(['testFormArray', '0', 'testNestedFormArray', '0']); + }); + + it('should add a form control to an existing form group', () => { + + const formGroup = service.createFormGroup(testModel); + const nestedFormGroup = formGroup.controls.testFormGroup as FormGroup; + const nestedFormGroupModel = testModel[7] as DynamicFormGroupModel; + const newModel1 = new DynamicInputModel({id: 'newInput1'}); + const newModel2 = new DynamicInputModel({id: 'newInput2'}); + + service.addFormGroupControl(formGroup, testModel, newModel1); + service.addFormGroupControl(nestedFormGroup, nestedFormGroupModel, newModel2); + + expect(formGroup.controls[newModel1.id]).toBeTruthy(); + expect(testModel[testModel.length - 1] === newModel1).toBe(true); + + expect((formGroup.controls.testFormGroup as FormGroup).controls[newModel2.id]).toBeTruthy(); + expect(nestedFormGroupModel.get(nestedFormGroupModel.group.length - 1) === newModel2).toBe(true); + }); + + it('should insert a form control to an existing form group', () => { + + const formGroup = service.createFormGroup(testModel); + const nestedFormGroup = formGroup.controls.testFormGroup as FormGroup; + const nestedFormGroupModel = testModel[7] as DynamicFormGroupModel; + const newModel1 = new DynamicInputModel({id: 'newInput1'}); + const newModel2 = new DynamicInputModel({id: 'newInput2'}); + + service.insertFormGroupControl(4, formGroup, testModel, newModel1); + service.insertFormGroupControl(0, nestedFormGroup, nestedFormGroupModel, newModel2); + + expect(formGroup.controls[newModel1.id]).toBeTruthy(); + expect(testModel[4] === newModel1).toBe(true); + expect(service.getPath(testModel[4])).toEqual(['newInput1']); + + expect((formGroup.controls.testFormGroup as FormGroup).controls[newModel2.id]).toBeTruthy(); + expect(nestedFormGroupModel.get(0) === newModel2).toBe(true); + expect(service.getPath(nestedFormGroupModel.get(0))).toEqual(['testFormGroup', 'newInput2']); + }); + + it('should move an existing form control to a different group position', () => { + + const formGroup = service.createFormGroup(testModel); + const nestedFormGroupModel = testModel[7] as DynamicFormGroupModel; + const model1 = testModel[0]; + const model2 = nestedFormGroupModel.get(0); + + service.moveFormGroupControl(0, 2, testModel); + + expect(formGroup.controls[model1.id]).toBeTruthy(); + expect(testModel[2] === model1).toBe(true); + + service.moveFormGroupControl(0, 1, nestedFormGroupModel); + + expect((formGroup.controls.testFormGroup as FormGroup).controls[model2.id]).toBeTruthy(); + expect(nestedFormGroupModel.get(1) === model2).toBe(true); + }); + + it('should remove a form control from an existing form group', () => { + + const formGroup = service.createFormGroup(testModel); + const nestedFormGroup = formGroup.controls.testFormGroup as FormGroup; + const nestedFormGroupModel = testModel[7] as DynamicFormGroupModel; + const length = testModel.length; + const size = nestedFormGroupModel.size(); + const index = 1; + const id1 = testModel[index].id; + const id2 = nestedFormGroupModel.get(index).id; + + service.removeFormGroupControl(index, formGroup, testModel); + + expect(Object.keys(formGroup.controls).length).toBe(length - 1); + expect(formGroup.controls[id1]).toBeUndefined(); + + expect(testModel.length).toBe(length - 1); + expect(service.findById(id1, testModel)).toBeNull(); + + service.removeFormGroupControl(index, nestedFormGroup, nestedFormGroupModel); + + expect(Object.keys(nestedFormGroup.controls).length).toBe(size - 1); + expect(nestedFormGroup.controls[id2]).toBeUndefined(); + + expect(nestedFormGroupModel.size()).toBe(size - 1); + expect(service.findById(id2, testModel)).toBeNull(); + }); + + it('should create a form array', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + let formArray; + + expect(service.createFormArray).toBeTruthy(); + + formArray = service.createFormArray(model); + + expect(formArray instanceof FormArray).toBe(true); + expect(formArray.length).toBe(model.initialCount); + }); + + it('should add a form array group', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + + service.addFormArrayGroup(formArray, model); + + expect(formArray.length).toBe(model.initialCount + 1); + }); + + it('should insert a form array group', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + + service.insertFormArrayGroup(0, formArray, model); + + expect(formArray.length).toBe(model.initialCount + 1); + }); + + it('should move up a form array group', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + const index = 3; + const step = 1; + + (formArray.at(index) as FormGroup).controls.testFormArrayGroupInput.setValue('next test value 1'); + (formArray.at(index + step) as FormGroup).controls.testFormArrayGroupInput.setValue('next test value 2'); + + (model.get(index).get(0) as DynamicFormValueControlModel).valueUpdates.next('next test value 1'); + (model.get(index + step).get(0) as DynamicFormValueControlModel).valueUpdates.next('next test value 2'); + + service.moveFormArrayGroup(index, step, formArray, model); + + expect(formArray.length).toBe(model.initialCount); + + expect((formArray.at(index) as FormGroup).controls.testFormArrayGroupInput.value).toEqual('next test value 2'); + expect((formArray.at(index + step) as FormGroup).controls.testFormArrayGroupInput.value).toEqual('next test value 1'); + + expect((model.get(index).get(0) as DynamicFormValueControlModel).value).toEqual('next test value 2'); + expect((model.get(index + step).get(0) as DynamicFormValueControlModel).value).toEqual('next test value 1'); + }); + + it('should move down a form array group', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + const index = 3; + const step = -1; + + (formArray.at(index) as FormGroup).controls.testFormArrayGroupInput.setValue('next test value 1'); + (formArray.at(index + step) as FormGroup).controls.testFormArrayGroupInput.setValue('next test value 2'); + + (model.get(index).get(0) as DynamicFormValueControlModel).valueUpdates.next('next test value 1'); + (model.get(index + step).get(0) as DynamicFormValueControlModel).valueUpdates.next('next test value 2'); + + service.moveFormArrayGroup(index, step, formArray, model); + + expect(formArray.length).toBe(model.initialCount); + + expect((formArray.at(index) as FormGroup).controls.testFormArrayGroupInput.value).toEqual('next test value 2'); + expect((formArray.at(index + step) as FormGroup).controls.testFormArrayGroupInput.value).toEqual('next test value 1'); + + expect((model.get(index).get(0) as DynamicFormValueControlModel).value).toEqual('next test value 2'); + expect((model.get(index + step).get(0) as DynamicFormValueControlModel).value).toEqual('next test value 1'); + }); + + it('should throw when form array group is to be moved out of bounds', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + + expect(() => service.moveFormArrayGroup(2, -5, formArray, model)) + .toThrow(new Error(`form array group cannot be moved due to index or new index being out of bounds`)); + }); + + it('should remove a form array group', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + + service.removeFormArrayGroup(0, formArray, model); + + expect(formArray.length).toBe(model.initialCount - 1); + }); + + it('should clear a form array', () => { + + const model = service.findById('testFormArray', testModel) as DynamicFormArrayModel; + const formArray = service.createFormArray(model); + + service.clearFormArray(formArray, model); + + expect(formArray.length === 0).toBe(true); + }); +}); diff --git a/src/app/shared/form/builder/form-builder.service.ts b/src/app/shared/form/builder/form-builder.service.ts index b33018ea0c..a58061e448 100644 --- a/src/app/shared/form/builder/form-builder.service.ts +++ b/src/app/shared/form/builder/form-builder.service.ts @@ -13,7 +13,7 @@ import { import { mergeWith, isObject } from 'lodash'; import { isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util'; -import { DynamicComboboxModel } from './ds-dynamic-form-ui/models/ds-dynamic-combobox.model'; +import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model'; import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-concat.model'; import { DynamicListCheckboxGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model'; @@ -148,8 +148,8 @@ export class FormBuilderService extends DynamicFormService { let controlId; // Get the field's name - if (controlModel instanceof DynamicComboboxModel) { - // If is instance of DynamicComboboxModel take the qualdrop id as field's name + if (controlModel instanceof DynamicQualdropModel) { + // If is instance of DynamicQualdropModel take the qualdrop id as field's name controlId = controlModel.qualdropId; } else { controlId = controlModel.name; @@ -220,22 +220,26 @@ export class FormBuilderService extends DynamicFormService { isModelInCustomGroup(model: DynamicFormControlModel) { return model.parent && (model.parent instanceof DynamicConcatModel - || model.parent instanceof DynamicComboboxModel); + || model.parent instanceof DynamicQualdropModel); + } + + hasArrayGroupValue(model: DynamicFormControlModel) { + return model && (this.isListGroup(model) || model.type === DYNAMIC_FORM_CONTROL_TYPE_TAG); } hasMappedGroupValue(model: DynamicFormControlModel) { - return ((model.parent && model.parent instanceof DynamicComboboxModel) + return ((model.parent && model.parent instanceof DynamicQualdropModel) || model.parent instanceof DynamicGroupModel); } - isComboboxGroup(model: DynamicFormControlModel) { - return model && model instanceof DynamicComboboxModel; + isQualdropGroup(model: DynamicFormControlModel) { + return model && model instanceof DynamicQualdropModel; } isCustomGroup(model: DynamicFormControlModel) { return model && (model instanceof DynamicConcatModel - || model instanceof DynamicComboboxModel + || this.isQualdropGroup(model) || this.isListGroup(model)); } @@ -245,10 +249,6 @@ export class FormBuilderService extends DynamicFormService { || model instanceof DynamicListRadioGroupModel); } - isModelInAuthorityGroup(model: DynamicFormControlModel) { - return model && (this.isListGroup(model) || model.type === DYNAMIC_FORM_CONTROL_TYPE_TAG); - } - isRelationGroup(model: DynamicFormControlModel) { return model && model.type === DYNAMIC_FORM_CONTROL_TYPE_RELATION; } diff --git a/src/app/shared/form/builder/parsers/concat-field-parser.ts b/src/app/shared/form/builder/parsers/concat-field-parser.ts index 14150e9ccc..bd636e94de 100644 --- a/src/app/shared/form/builder/parsers/concat-field-parser.ts +++ b/src/app/shared/form/builder/parsers/concat-field-parser.ts @@ -31,10 +31,16 @@ export class ConcatFieldParser extends FieldParser { let clsGroup: DynamicFormControlLayout; let clsInput: DynamicFormControlLayout; - const newId = this.configData.selectableMetadata[0].metadata - .split('.') - .slice(0, this.configData.selectableMetadata[0].metadata.split('.').length - 1) - .join('.'); + let newId: string; + + if (this.configData.selectableMetadata[0].metadata.includes('.')) { + newId = this.configData.selectableMetadata[0].metadata + .split('.') + .slice(0, this.configData.selectableMetadata[0].metadata.split('.').length - 1) + .join('.'); + } else { + newId = this.configData.selectableMetadata[0].metadata + } clsInput = { grid: { 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 6c7b16cf10..703e79bf56 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.ts @@ -3,12 +3,12 @@ import { DynamicSelectModel, DynamicSelectModelConfig } from '@ng-dynamic-forms/ import { FieldParser } from './field-parser'; import { FormFieldModel } from '../models/form-field.model'; import { - COMBOBOX_GROUP_SUFFIX, - COMBOBOX_METADATA_SUFFIX, - COMBOBOX_VALUE_SUFFIX, - DsDynamicComboboxModelConfig, - DynamicComboboxModel -} from '../ds-dynamic-form-ui/models/ds-dynamic-combobox.model'; + QUALDROP_GROUP_SUFFIX, + QUALDROP_METADATA_SUFFIX, + QUALDROP_VALUE_SUFFIX, + DsDynamicQualdropModelConfig, + DynamicQualdropModel +} from '../ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { isNotEmpty } from '../../../empty.util'; import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-form-ui/models/ds-dynamic-input.model'; @@ -58,25 +58,25 @@ export class OneboxFieldParser extends FieldParser { .slice(0, this.configData.selectableMetadata[0].metadata.split('.').length - 1) .join('.'); - const inputSelectGroup: DsDynamicComboboxModelConfig = Object.create(null); - inputSelectGroup.id = newId.replace(/\./g, '_') + COMBOBOX_GROUP_SUFFIX; + const inputSelectGroup: DsDynamicQualdropModelConfig = Object.create(null); + inputSelectGroup.id = newId.replace(/\./g, '_') + QUALDROP_GROUP_SUFFIX; inputSelectGroup.group = []; inputSelectGroup.legend = this.configData.label; - const selectModelConfig: DynamicSelectModelConfig = this.initModel(newId + COMBOBOX_METADATA_SUFFIX); + const selectModelConfig: DynamicSelectModelConfig = this.initModel(newId + QUALDROP_METADATA_SUFFIX); this.setOptions(selectModelConfig); if (isNotEmpty(fieldValue)) { selectModelConfig.value = fieldValue.metadata; } inputSelectGroup.group.push(new DynamicSelectModel(selectModelConfig, clsSelect)); - const inputModelConfig: DsDynamicInputModelConfig = this.initModel(newId + COMBOBOX_VALUE_SUFFIX, true, true); + const inputModelConfig: DsDynamicInputModelConfig = this.initModel(newId + QUALDROP_VALUE_SUFFIX, true, true); this.setValues(inputModelConfig, fieldValue); inputSelectGroup.readOnly = selectModelConfig.disabled && inputModelConfig.readOnly; inputSelectGroup.group.push(new DsDynamicInputModel(inputModelConfig, clsInput)); - return new DynamicComboboxModel(inputSelectGroup, clsGroup); + return new DynamicQualdropModel(inputSelectGroup, clsGroup); } else if (this.configData.selectableMetadata[0].authority) { const typeaheadModelConfig: DsDynamicTypeaheadModelConfig = this.initModel(); this.setAuthorityOptions(typeaheadModelConfig, this.authorityUuid);