diff --git a/src/app/shared/mocks/mock-form-builder-service.ts b/src/app/shared/mocks/mock-form-builder-service.ts index f37030eccb..9f329032db 100644 --- a/src/app/shared/mocks/mock-form-builder-service.ts +++ b/src/app/shared/mocks/mock-form-builder-service.ts @@ -7,8 +7,10 @@ export function getMockFormBuilderService(): FormBuilderService { createFormGroup: new FormGroup({}), getValueFromModel: {}, getFormControlById: new FormControl(), + hasMappedGroupValue: false, findById: {}, getPath: ['test', 'path'], + getId: 'path', clearAllModelsValue : {}, insertFormArrayGroup: {}, isQualdrop: false diff --git a/src/app/shared/mocks/mock-form-operations-service.ts b/src/app/shared/mocks/mock-form-operations-service.ts new file mode 100644 index 0000000000..910e309251 --- /dev/null +++ b/src/app/shared/mocks/mock-form-operations-service.ts @@ -0,0 +1,17 @@ +import { FormOperationsService } from '../../submission/sections/form/form-operations.service'; + +export function getMockFormOperationsService(): FormOperationsService { + return jasmine.createSpyObj('FormOperationsService', { + dispatchOperationsFromEvent: jasmine.createSpy('dispatchOperationsFromEvent'), + getArrayIndexFromEvent: jasmine.createSpy('getArrayIndexFromEvent'), + isPartOfArrayOfGroup: jasmine.createSpy('isPartOfArrayOfGroup'), + getQualdropValueMap: jasmine.createSpy('getQualdropValueMap'), + getFieldPathFromEvent: jasmine.createSpy('getFieldPathFromEvent'), + getQualdropItemPathFromEvent: jasmine.createSpy('getQualdropItemPathFromEvent'), + getFieldPathSegmentedFromChangeEvent: jasmine.createSpy('getFieldPathSegmentedFromChangeEvent'), + getFieldValueFromChangeEvent: jasmine.createSpy('getFieldValueFromChangeEvent'), + getValueMap: jasmine.createSpy('getValueMap'), + + }); + +} diff --git a/src/app/shared/mocks/mock-form-service.ts b/src/app/shared/mocks/mock-form-service.ts index 0ab3fbffcc..4768caadb6 100644 --- a/src/app/shared/mocks/mock-form-service.ts +++ b/src/app/shared/mocks/mock-form-service.ts @@ -1,12 +1,17 @@ +import { of as observableOf } from 'rxjs'; + import { FormService } from '../form/form.service'; export function getMockFormService( id$: string = 'random_id' ): FormService { return jasmine.createSpyObj('FormService', { + getFormData: jasmine.createSpy('getFormData'), getUniqueId: id$, resetForm: {}, - validateAllFormFields: {} + validateAllFormFields: {}, + isValid: observableOf(true), + isFormInitialized: observableOf(true) }); } diff --git a/src/app/shared/mocks/mock-scroll-to-service.ts b/src/app/shared/mocks/mock-scroll-to-service.ts new file mode 100644 index 0000000000..9c600e405e --- /dev/null +++ b/src/app/shared/mocks/mock-scroll-to-service.ts @@ -0,0 +1,7 @@ +import { ScrollToService } from '@nicky-lenaers/ngx-scroll-to'; + +export function getMockScrollToService(): ScrollToService { + return jasmine.createSpyObj('scrollToService', { + scrollTo: jasmine.createSpy('scrollTo') + }); +} diff --git a/src/app/submission/form/submission-form.component.spec.ts b/src/app/submission/form/submission-form.component.spec.ts index c894cc816d..dccb3adcea 100644 --- a/src/app/submission/form/submission-form.component.spec.ts +++ b/src/app/submission/form/submission-form.component.spec.ts @@ -93,9 +93,9 @@ describe('SubmissionFormComponent Component', () => { }); afterEach(() => { + fixture.destroy(); comp = null; compAsAny = null; - fixture = null; }); it('should not has effect when collectionId and submissionId are undefined', () => { diff --git a/src/app/submission/sections/container/section-container.component.html b/src/app/submission/sections/container/section-container.component.html index 458ea93b9f..fb29f606e6 100644 --- a/src/app/submission/sections/container/section-container.component.html +++ b/src/app/submission/sections/container/section-container.component.html @@ -17,7 +17,7 @@ aria-hidden="true"> - -
+
{ - let testComp: TestComponent; - let testFixture: ComponentFixture; - let html; + let comp: SectionContainerComponent; + let compAsAny: any; + let fixture: ComponentFixture; - const config = { - autosave: { - metadata: ['dc.title', 'dc.identifier.doi', 'dc.identifier.pmid', 'dc.identifier.arxiv'], - timer: 5 - }, - metadata: { - icons: [ - { - name: 'dc.contributor.author', - config: { - withAuthority:{ - style: 'fa-user' - } - } - }, - { - name: 'local.contributor.affiliation', - config: { - withAuthority:{ - style: 'fa-university' - }, - withoutAuthority:{ - style: 'fa-university text-muted' - } - } - }, - { - name: 'default', - config: {} - } - ] - } - } as any; - const restService = new SubmissionRestServiceStub(); - const router = new MockRouter(); - const store = new Store(observableOf({}), new ActionsSubject(), undefined); + let submissionServiceStub: SubmissionServiceStub; + let sectionsServiceStub: SectionsServiceStub; + + const submissionId = mockSubmissionId; + const collectionId = mockSubmissionCollectionId; + + function init() { + sectionsServiceStub = TestBed.get(SectionsService); + submissionServiceStub = TestBed.get(SubmissionService); + + sectionsServiceStub.isSectionValid.and.returnValue(observableOf(true)); + sectionsServiceStub.getSectionState.and.returnValue(observableOf(sectionState)); + submissionServiceStub.getActiveSectionId.and.returnValue(observableOf('traditionalpageone')); + } // async beforeEach beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - BrowserModule, - CommonModule, NgbModule.forRoot(), TranslateModule.forRoot() ], @@ -85,41 +76,149 @@ describe('SectionContainerComponent test suite', () => { TestComponent, ], // declare the test component providers: [ - ChangeDetectorRef, - NotificationsService, - RouteService, - ScrollToService, - SectionContainerComponent, - SectionsService, - SubmissionService, - { provide: ActivatedRoute, useValue: new MockActivatedRoute() }, - { provide: Router, useValue: router }, - { provide: SubmissionRestService, useValue: restService }, - { provide: GLOBAL_CONFIG, useValue: config }, - { provide: Store, useValue: store } + { provide: SectionsService, useClass: SectionsServiceStub }, + { provide: SubmissionService, useClass: SubmissionServiceStub }, + SectionContainerComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA] - }); + }).compileComponents(); })); describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + let html; + // synchronous beforeEach beforeEach(() => { html = ` - `; + `; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; + init(); }); - it('should create Chips Component', inject([SectionContainerComponent], (app: SectionContainerComponent) => { + it('should create SectionContainerComponent', inject([SectionContainerComponent], (app: SectionContainerComponent) => { expect(app).toBeDefined(); })); }); + describe('', () => { + beforeEach(() => { + init(); + fixture = TestBed.createComponent(SectionContainerComponent); + comp = fixture.componentInstance; + compAsAny = comp; + comp.submissionId = submissionId; + comp.collectionId = collectionId; + comp.sectionData = sectionObject; + + spyOn(comp, 'getSectionContent'); + fixture.detectChanges(); + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + + it('should inject section properly', () => { + spyOn(comp.sectionRef, 'isEnabled').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'hasGenericErrors').and.returnValue(false); + + comp.ngOnInit(); + fixture.detectChanges(); + + const section = fixture.debugElement.query(By.css('[id^=\'sectionContent_\']')); + expect(comp.getSectionContent).toHaveBeenCalled(); + expect(section).toBeDefined(); + }); + + it('should call removeSection properly', () => { + + const mockEvent = jasmine.createSpyObj('event', { + preventDefault: jasmine.createSpy('preventDefault'), + stopPropagation: jasmine.createSpy('stopPropagation'), + }); + spyOn(comp.sectionRef, 'removeSection'); + comp.removeSection(mockEvent); + + expect(mockEvent.preventDefault).toHaveBeenCalled(); + expect(mockEvent.stopPropagation).toHaveBeenCalled(); + expect(comp.sectionRef.removeSection).toHaveBeenCalledWith(submissionId, 'traditionalpageone'); + }); + + it('should display generic section errors div', () => { + let sectionErrorsDiv = fixture.debugElement.query(By.css('[id^=\'sectionGenericError_\']')); + expect(sectionErrorsDiv).toBeNull(); + + spyOn(comp.sectionRef, 'isEnabled').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'hasGenericErrors').and.returnValue(true); + + comp.ngOnInit(); + fixture.detectChanges(); + + sectionErrorsDiv = fixture.debugElement.query(By.css('[id^=\'sectionGenericError_\']')); + expect(sectionErrorsDiv).toBeDefined(); + }); + + it('should display warning icon', () => { + + spyOn(comp.sectionRef, 'isEnabled').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'isValid').and.returnValue(observableOf(false)); + spyOn(comp.sectionRef, 'hasErrors').and.returnValue(false); + + comp.ngOnInit(); + fixture.detectChanges(); + + const iconWarn = fixture.debugElement.query(By.css('i.text-warning')); + const iconErr = fixture.debugElement.query(By.css('i.text-danger')); + const iconSuccess = fixture.debugElement.query(By.css('i.text-success')); + expect(iconWarn).toBeDefined(); + expect(iconErr).toBeNull(); + expect(iconSuccess).toBeNull(); + }); + + it('should display error icon', () => { + + spyOn(comp.sectionRef, 'isEnabled').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'isValid').and.returnValue(observableOf(false)); + spyOn(comp.sectionRef, 'hasErrors').and.returnValue(true); + + comp.ngOnInit(); + fixture.detectChanges(); + + const iconWarn = fixture.debugElement.query(By.css('i.text-warning')); + const iconErr = fixture.debugElement.query(By.css('i.text-danger')); + const iconSuccess = fixture.debugElement.query(By.css('i.text-success')); + expect(iconWarn).toBeNull(); + expect(iconErr).toBeDefined(); + expect(iconSuccess).toBeNull(); + }); + + it('should display success icon', () => { + + spyOn(comp.sectionRef, 'isEnabled').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'isValid').and.returnValue(observableOf(true)); + spyOn(comp.sectionRef, 'hasErrors').and.returnValue(false); + + comp.ngOnInit(); + fixture.detectChanges(); + + const iconWarn = fixture.debugElement.query(By.css('i.text-warning')); + const iconErr = fixture.debugElement.query(By.css('i.text-danger')); + const iconSuccess = fixture.debugElement.query(By.css('i.text-success')); + expect(iconWarn).toBeNull(); + expect(iconErr).toBeNull(); + expect(iconSuccess).toBeDefined(); + }); + + }); }); // declare a test component @@ -130,14 +229,6 @@ describe('SectionContainerComponent test suite', () => { class TestComponent { public collectionId = '1c11f3f1-ba1f-4f36-908a-3f1ea9a557eb'; - public submissionId = 1; - public object = { - config: 'https://dspace7.4science.it/or2018/api/config/submissionforms/traditionalpageone', - mandatory: true, - data: {}, - errors: [], - header: 'submit.progressbar.describe.stepone', - id: 'traditionalpageone', - sectionType: SectionsType.SubmissionForm - } + public submissionId = mockSubmissionId; + public object = sectionObject; } diff --git a/src/app/submission/sections/form/section-form.component.spec.ts b/src/app/submission/sections/form/section-form.component.spec.ts new file mode 100644 index 0000000000..30f93772ce --- /dev/null +++ b/src/app/submission/sections/form/section-form.component.spec.ts @@ -0,0 +1,454 @@ +import { ChangeDetectorRef, Component, NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'; + +import { of as observableOf } from 'rxjs'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; + +import { createTestComponent } from '../../../shared/testing/utils'; +import { NotificationsService } from '../../../shared/notifications/notifications.service'; +import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub'; +import { SubmissionService } from '../../submission.service'; +import { SubmissionServiceStub } from '../../../shared/testing/submission-service-stub'; +import { getMockTranslateService } from '../../../shared/mocks/mock-translate.service'; +import { SectionsService } from '../sections.service'; +import { SectionsServiceStub } from '../../../shared/testing/sections-service-stub'; +import { FormSectionComponent } from './section-form.component'; +import { FormBuilderService } from '../../../shared/form/builder/form-builder.service'; +import { getMockFormBuilderService } from '../../../shared/mocks/mock-form-builder-service'; +import { getMockFormOperationsService } from '../../../shared/mocks/mock-form-operations-service'; +import { FormOperationsService } from './form-operations.service'; +import { getMockFormService } from '../../../shared/mocks/mock-form-service'; +import { FormService } from '../../../shared/form/form.service'; +import { SubmissionFormsConfigService } from '../../../core/config/submission-forms-config.service'; +import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config'; +import { MOCK_SUBMISSION_CONFIG } from '../../../shared/testing/mock-submission-config'; +import { SectionDataObject } from '../models/section-data.model'; +import { SectionsType } from '../sections-type'; +import { + mockSubmissionCollectionId, + mockSubmissionId, + mockUploadResponse1ParsedErrors +} from '../../../shared/mocks/mock-submission'; +import { BrowserModule } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormComponent } from '../../../shared/form/form.component'; +import { FormFieldModel } from '../../../shared/form/builder/models/form-field.model'; +import { FormRowModel } from '../../../core/config/models/config-submission-forms.model'; +import { ConfigData } from '../../../core/config/config-data'; +import { PageInfo } from '../../../core/shared/page-info.model'; +import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model'; +import { DynamicRowGroupModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; +import { DsDynamicInputModel } from '../../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model'; +import { SubmissionSectionError } from '../../objects/submission-objects.reducer'; +import { DynamicFormControlEvent, DynamicFormControlEventType } from '@ng-dynamic-forms/core'; +import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; + +function getMockSubmissionFormsConfigService(): SubmissionFormsConfigService { + return jasmine.createSpyObj('FormOperationsService', { + getConfigAll: jasmine.createSpy('getConfigAll'), + getConfigByHref: jasmine.createSpy('getConfigByHref'), + getConfigByName: jasmine.createSpy('getConfigByName'), + getConfigBySearch: jasmine.createSpy('getConfigBySearch') + }); +} + +const sectionObject: SectionDataObject = { + config: 'https://dspace7.4science.it/or2018/api/config/submissionforms/traditionalpageone', + mandatory: true, + data: {}, + errors: [], + header: 'submit.progressbar.describe.stepone', + id: 'traditionalpageone', + sectionType: SectionsType.SubmissionForm +}; + +const testFormConfiguration = { + name: 'testFormConfiguration', + rows: [ + { + fields: [ + { + input: { + type: 'onebox' + }, + label: 'Title', + mandatory: 'true', + repeatable: false, + hints: ' Enter Title.', + selectableMetadata: [ + { + metadata: 'dc.title' + } + ], + languageCodes: [] + } as FormFieldModel + ] + } as FormRowModel, + { + fields: [ + { + input: { + type: 'onebox' + }, + label: 'Author', + mandatory: 'false', + repeatable: false, + hints: ' Enter Author.', + selectableMetadata: [ + { + metadata: 'dc.contributor' + } + ], + languageCodes: [] + } as FormFieldModel + ] + } as FormRowModel, + ], + self: 'testFormConfiguration.url', + type: 'submissionform', + _links: { + self: 'testFormConfiguration.url' + } +} as any; + +const testFormModel = [ + new DynamicRowGroupModel({ + id: 'df-row-group-config-1', + group: [new DsDynamicInputModel({ id: 'dc.title' })], + }), + new DynamicRowGroupModel({ + id: 'df-row-group-config-2', + group: [new DsDynamicInputModel({ id: 'dc.contributor' })], + }) +]; + +const dynamicFormControlEvent: DynamicFormControlEvent = { + $event: new Event('change'), + context: null, + control: null, + group: testFormModel[0] as any, + model: testFormModel[0].group[0], + type: DynamicFormControlEventType.Change +}; + +describe('FormSectionComponent test suite', () => { + + let comp: FormSectionComponent; + let compAsAny: any; + let fixture: ComponentFixture; + let submissionServiceStub: SubmissionServiceStub; + let sectionsServiceStub: SectionsServiceStub; + let notificationsServiceStub: NotificationsServiceStub; + let formService: any; + let formConfigService: any; + let formOperationsService: any; + let formBuilderService: any; + let translateService: any; + + const envConfig: GlobalConfig = MOCK_SUBMISSION_CONFIG; + const submissionId = mockSubmissionId; + const collectionId = mockSubmissionCollectionId; + const parsedSectionErrors: any = mockUploadResponse1ParsedErrors.traditionalpageone; + const formConfigData = new ConfigData(new PageInfo(), testFormConfiguration); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserModule, + CommonModule, + FormsModule, + ReactiveFormsModule, + TranslateModule.forRoot() + ], + declarations: [ + FormComponent, + FormSectionComponent, + TestComponent + ], + providers: [ + { provide: FormBuilderService, useValue: getMockFormBuilderService() }, + { provide: FormOperationsService, useValue: getMockFormOperationsService() }, + { provide: FormService, useValue: getMockFormService() }, + { provide: SubmissionFormsConfigService, useValue: getMockSubmissionFormsConfigService() }, + { provide: NotificationsService, useClass: NotificationsServiceStub }, + { provide: SectionsService, useClass: SectionsServiceStub }, + { provide: SubmissionService, useClass: SubmissionServiceStub }, + { provide: TranslateService, useValue: getMockTranslateService() }, + { provide: GLOBAL_CONFIG, useValue: envConfig }, + { provide: 'collectionIdProvider', useValue: collectionId }, + { provide: 'sectionDataProvider', useValue: sectionObject }, + { provide: 'submissionIdProvider', useValue: submissionId }, + ChangeDetectorRef, + FormSectionComponent + ], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents().then(); + })); + + describe('', () => { + let testComp: TestComponent; + let testFixture: ComponentFixture; + + // synchronous beforeEach + beforeEach(() => { + const html = ` + `; + + testFixture = createTestComponent(html, TestComponent) as ComponentFixture; + testComp = testFixture.componentInstance; + }); + + afterEach(() => { + testFixture.destroy(); + }); + + it('should create FormSectionComponent', inject([FormSectionComponent], (app: FormSectionComponent) => { + + expect(app).toBeDefined(); + + })); + }); + + describe('', () => { + beforeEach(() => { + fixture = TestBed.createComponent(FormSectionComponent); + comp = fixture.componentInstance; + compAsAny = comp; + submissionServiceStub = TestBed.get(SubmissionService); + sectionsServiceStub = TestBed.get(SectionsService); + formService = TestBed.get(FormService); + formConfigService = TestBed.get(SubmissionFormsConfigService); + formBuilderService = TestBed.get(FormBuilderService); + formOperationsService = TestBed.get(FormOperationsService); + translateService = TestBed.get(TranslateService); + notificationsServiceStub = TestBed.get(NotificationsService); + + translateService.get.and.returnValue(observableOf('test')); + compAsAny.pathCombiner = new JsonPatchOperationPathCombiner('sections', sectionObject.id); + }); + + afterEach(() => { + fixture.destroy(); + comp = null; + compAsAny = null; + }); + + it('should init section properly', () => { + const sectionData = {}; + formConfigService.getConfigByHref.and.returnValue(observableOf(formConfigData)); + sectionsServiceStub.getSectionData.and.returnValue(observableOf(sectionData)); + spyOn(comp, 'initForm'); + spyOn(comp, 'subscriptions'); + + comp.onSectionInit(); + fixture.detectChanges(); + + expect(compAsAny.formConfig).toEqual(formConfigData.payload); + expect(comp.sectionData.errors).toEqual([]); + expect(comp.sectionData.data).toEqual(sectionData); + expect(comp.isLoading).toBeFalsy(); + expect(comp.initForm).toHaveBeenCalledWith(sectionData); + expect(comp.subscriptions).toHaveBeenCalled(); + + }); + + it('should init form model properly', () => { + formBuilderService.modelFromConfiguration.and.returnValue(testFormModel); + const sectionData = {}; + + comp.initForm(sectionData); + + expect(comp.formModel).toEqual(testFormModel); + + }); + + it('should set a section Error when init form model fails', () => { + formBuilderService.modelFromConfiguration.and.throwError('test'); + const sectionData = {}; + const sectionError: SubmissionSectionError = { + message: 'test' + 'Error: test', + path: '/sections/' + sectionObject.id + }; + + comp.initForm(sectionData); + + expect(comp.formModel).toBeUndefined(); + expect(sectionsServiceStub.setSectionError).toHaveBeenCalledWith(submissionId, sectionObject.id, sectionError); + + }); + + it('should return true when has Metadata Enrichment', () => { + const newSectionData = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + }; + compAsAny.formData = {}; + + expect(comp.hasMetadataEnrichment(newSectionData)).toBeTruthy(); + }); + + it('should return false when has not Metadata Enrichment', () => { + const newSectionData = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + }; + compAsAny.formData = newSectionData; + + expect(comp.hasMetadataEnrichment(newSectionData)).toBeFalsy(); + }); + + it('should update form properly', () => { + spyOn(comp, 'initForm'); + spyOn(comp, 'checksForErrors'); + const sectionData: any = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + }; + const sectionError = []; + comp.sectionData.data = {}; + comp.sectionData.errors = []; + compAsAny.formData = {}; + + comp.updateForm(sectionData, sectionError); + + expect(comp.isUpdating).toBeFalsy(); + expect(comp.initForm).toHaveBeenCalled(); + expect(comp.checksForErrors).toHaveBeenCalled(); + expect(notificationsServiceStub.info).toHaveBeenCalled(); + expect(comp.sectionData.data).toEqual(sectionData); + + }); + + it('should update form error properly', () => { + spyOn(comp, 'initForm'); + spyOn(comp, 'checksForErrors'); + const sectionData: any = {}; + + comp.updateForm(sectionData, parsedSectionErrors); + + expect(comp.initForm).not.toHaveBeenCalled(); + expect(comp.checksForErrors).toHaveBeenCalled(); + + }); + + it('should check for error', () => { + comp.isUpdating = false; + comp.formId = 'test'; + comp.sectionData.errors = []; + + comp.checksForErrors(parsedSectionErrors); + + expect(sectionsServiceStub.checkSectionErrors).toHaveBeenCalledWith( + submissionId, + sectionObject.id, + 'test', + parsedSectionErrors, + [] + ); + expect(comp.sectionData.errors).toEqual(parsedSectionErrors); + }); + + it('should subscribe to state properly', () => { + spyOn(comp, 'updateForm'); + const formData = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + }; + const sectionData: any = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + }; + const sectionState = { + data: sectionData, + errors: parsedSectionErrors + }; + + formService.getFormData.and.returnValue(observableOf(formData)); + sectionsServiceStub.getSectionState.and.returnValue(observableOf(sectionState)); + + comp.subscriptions(); + + expect(compAsAny.subs.length).toBe(2); + expect(compAsAny.formData).toEqual(formData); + expect(comp.updateForm).toHaveBeenCalledWith(sectionState.data, sectionState.errors); + + }); + + it('should call dispatchOperationsFromEvent on form change', () => { + spyOn(comp, 'hasStoredValue').and.returnValue(false); + formOperationsService.getFieldPathSegmentedFromChangeEvent.and.returnValue('path'); + formOperationsService.getFieldValueFromChangeEvent.and.returnValue('test'); + + comp.onChange(dynamicFormControlEvent); + + expect(formOperationsService.dispatchOperationsFromEvent).toHaveBeenCalled(); + expect(formOperationsService.getFieldPathSegmentedFromChangeEvent).toHaveBeenCalledWith(dynamicFormControlEvent); + expect(formOperationsService.getFieldValueFromChangeEvent).toHaveBeenCalledWith(dynamicFormControlEvent); + expect(submissionServiceStub.dispatchSave).not.toHaveBeenCalledWith(submissionId); + + }); + + it('should call dispatchSave on form change when metadata is in submission autosave configuration', () => { + spyOn(comp, 'hasStoredValue').and.returnValue(false); + formOperationsService.getFieldPathSegmentedFromChangeEvent.and.returnValue('dc.title'); + formOperationsService.getFieldValueFromChangeEvent.and.returnValue('test'); + + comp.onChange(dynamicFormControlEvent); + + expect(formOperationsService.dispatchOperationsFromEvent).toHaveBeenCalled(); + expect(formOperationsService.getFieldPathSegmentedFromChangeEvent).toHaveBeenCalledWith(dynamicFormControlEvent); + expect(formOperationsService.getFieldValueFromChangeEvent).toHaveBeenCalledWith(dynamicFormControlEvent); + expect(submissionServiceStub.dispatchSave).toHaveBeenCalledWith(submissionId); + + }); + + it('should set previousValue on form focus event', () => { + formBuilderService.hasMappedGroupValue.and.returnValue(false); + formOperationsService.getFieldValueFromChangeEvent.and.returnValue('test'); + + comp.onFocus(dynamicFormControlEvent); + + expect(compAsAny.previousValue.path).toEqual(['test', 'path']); + expect(compAsAny.previousValue.value).toBe('test'); + + formBuilderService.hasMappedGroupValue.and.returnValue(true); + formOperationsService.getQualdropValueMap.and.returnValue('qualdrop'); + + comp.onFocus(dynamicFormControlEvent); + expect(compAsAny.previousValue.path).toEqual(['test', 'path']); + expect(compAsAny.previousValue.value).toBe('qualdrop'); + + formBuilderService.hasMappedGroupValue.and.returnValue(false); + formOperationsService.getFieldValueFromChangeEvent.and.returnValue(new FormFieldMetadataValueObject('form value test')); + + comp.onFocus(dynamicFormControlEvent); + expect(compAsAny.previousValue.path).toEqual(['test', 'path']); + expect(compAsAny.previousValue.value).toEqual(new FormFieldMetadataValueObject('form value test')); + }); + + it('should call dispatchOperationsFromEvent on form remove event', () => { + spyOn(comp, 'hasStoredValue').and.returnValue(false); + + comp.onRemove(dynamicFormControlEvent); + + expect(formOperationsService.dispatchOperationsFromEvent).toHaveBeenCalled(); + + }); + + it('should check if has stored value in the section state', () => { + comp.sectionData.data = { + 'dc.title': [new FormFieldMetadataValueObject('test')] + } as any; + + expect(comp.hasStoredValue('dc.title', 0)).toBeTruthy(); + expect(comp.hasStoredValue('dc.title', 1)).toBeFalsy(); + expect(comp.hasStoredValue('title', 0)).toBeFalsy(); + + }); + }); +}); + +// declare a test component +@Component({ + selector: 'ds-test-cmp', + template: `` +}) +class TestComponent { + +} diff --git a/src/app/submission/sections/form/section-form.component.ts b/src/app/submission/sections/form/section-form.component.ts index a57fb60faf..dbe8832479 100644 --- a/src/app/submission/sections/form/section-form.component.ts +++ b/src/app/submission/sections/form/section-form.component.ts @@ -73,7 +73,7 @@ export class FormSectionComponent extends SectionModelComponent { this.formConfigService.getConfigByHref(this.sectionData.config).pipe( map((configData: ConfigData) => configData.payload), tap((config: SubmissionFormsModel) => this.formConfig = config), - flatMap((config: ConfigData) => this.sectionService.getSectionData(this.submissionId, this.sectionData.id)), + flatMap(() => this.sectionService.getSectionData(this.submissionId, this.sectionData.id)), take(1)) .subscribe((sectionData: WorkspaceitemSectionDataType) => { if (isUndefined(this.formModel)) { @@ -86,25 +86,6 @@ export class FormSectionComponent extends SectionModelComponent { this.cdr.detectChanges(); } }) - -/* this.formConfigService.getConfigByHref(this.sectionData.config).pipe( - map((config: ConfigData) => config.payload)) - .subscribe((config: SubmissionFormsModel) => { - this.formConfig = config; - this.sectionService.getSectionData(this.submissionId, this.sectionData.id).pipe( - take(1)) - .subscribe((sectionData: WorkspaceitemSectionDataType) => { - if (isUndefined(this.formModel)) { - this.sectionData.errors = []; - // Is the first loading so init form - this.initForm(sectionData); - this.sectionData.data = sectionData; - this.subscriptions(); - this.isLoading = false; - this.cdr.detectChanges(); - } - }) - });*/ } onSectionDestroy() { @@ -248,8 +229,8 @@ export class FormSectionComponent extends SectionModelComponent { } hasStoredValue(fieldId, index) { - if (isNotEmpty(this.sectionData.data) && isNotEmpty(this.sectionData.data[index])) { - return this.sectionData.data.hasOwnProperty(fieldId); + if (isNotEmpty(this.sectionData.data)) { + return this.sectionData.data.hasOwnProperty(fieldId) && isNotEmpty(this.sectionData.data[fieldId][index]); } else { return false; } diff --git a/src/app/submission/sections/sections.service.spec.ts b/src/app/submission/sections/sections.service.spec.ts index ba007c6592..45965e8776 100644 --- a/src/app/submission/sections/sections.service.spec.ts +++ b/src/app/submission/sections/sections.service.spec.ts @@ -27,6 +27,7 @@ import { FormAddError, FormClearErrorsAction, FormRemoveErrorAction } from '../. import parseSectionErrors from '../utils/parseSectionErrors'; import { SubmissionScopeType } from '../../core/submission/submission-scope-type'; import { SubmissionSectionError } from '../objects/submission-objects.reducer'; +import { getMockScrollToService } from '../../shared/mocks/mock-scroll-to-service'; describe('SectionsService test suite', () => { let notificationsServiceStub: NotificationsServiceStub; @@ -47,16 +48,10 @@ describe('SectionsService test suite', () => { select: jasmine.createSpy('select') }); - function getMockScrollToService(): ScrollToService { - return jasmine.createSpyObj('scrollToService', { - scrollTo: jasmine.createSpy('scrollTo') - }); - } - beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - StoreModule.forRoot({submissionReducers} as any), + StoreModule.forRoot({ submissionReducers } as any), TranslateModule.forRoot({ loader: { provide: TranslateLoader, @@ -184,7 +179,7 @@ describe('SectionsService test suite', () => { describe('isSectionValid', () => { it('should return an observable of boolean', () => { - store.select.and.returnValue(observableOf({isValid: false})); + store.select.and.returnValue(observableOf({ isValid: false })); let expected = cold('(b|)', { b: false @@ -192,7 +187,7 @@ describe('SectionsService test suite', () => { expect(service.isSectionValid(submissionId, sectionId)).toBeObservable(expected); - store.select.and.returnValue(observableOf({isValid: true})); + store.select.and.returnValue(observableOf({ isValid: true })); expected = cold('(b|)', { b: true @@ -224,7 +219,7 @@ describe('SectionsService test suite', () => { describe('isSectionEnabled', () => { it('should return an observable of boolean', () => { - store.select.and.returnValue(observableOf({enabled: false})); + store.select.and.returnValue(observableOf({ enabled: false })); let expected = cold('(b|)', { b: false @@ -232,7 +227,7 @@ describe('SectionsService test suite', () => { expect(service.isSectionEnabled(submissionId, sectionId)).toBeObservable(expected); - store.select.and.returnValue(observableOf({enabled: true})); + store.select.and.returnValue(observableOf({ enabled: true })); expected = cold('(b|)', { b: true @@ -353,7 +348,7 @@ describe('SectionsService test suite', () => { it('should dispatch a new UpdateSectionDataAction', () => { const scheduler = getTestScheduler(); - const data: any = {test: 'test'}; + const data: any = { test: 'test' }; spyOn(service, 'isSectionAvailable').and.returnValue(observableOf(true)); spyOn(service, 'isSectionEnabled').and.returnValue(observableOf(true)); scheduler.schedule(() => service.updateSectionData(submissionId, sectionId, data, [])); @@ -364,7 +359,7 @@ describe('SectionsService test suite', () => { it('should dispatch a new UpdateSectionDataAction and display a new notification when section is not enabled', () => { const scheduler = getTestScheduler(); - const data: any = {test: 'test'}; + const data: any = { test: 'test' }; spyOn(service, 'isSectionAvailable').and.returnValue(observableOf(true)); spyOn(service, 'isSectionEnabled').and.returnValue(observableOf(false)); translateService.get.and.returnValue(observableOf('test'));