import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, DebugElement, SimpleChange } from '@angular/core'; import { async, ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { of as observableOf } from 'rxjs'; import { filter } from 'rxjs/operators'; import { TranslateModule } from '@ngx-translate/core'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { Store } from '@ngrx/store'; import { SubmissionServiceStub } from '../../../shared/testing/submission-service-stub'; import { mockSubmissionId, mockSubmissionRestResponse } from '../../../shared/mocks/mock-submission'; import { SubmissionService } from '../../submission.service'; import { SubmissionFormCollectionComponent } from './submission-form-collection.component'; import { CommunityDataService } from '../../../core/data/community-data.service'; import { SubmissionJsonPatchOperationsService } from '../../../core/submission/submission-json-patch-operations.service'; import { SubmissionJsonPatchOperationsServiceStub } from '../../../shared/testing/submission-json-patch-operations-service-stub'; import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder'; import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner'; import { Community } from '../../../core/shared/community.model'; import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list'; import { PageInfo } from '../../../core/shared/page-info.model'; import { Collection } from '../../../core/shared/collection.model'; import { createTestComponent } from '../../../shared/testing/utils'; import { cold } from 'jasmine-marbles'; import { SearchResult } from '../../../+search-page/search-result.model'; import { SearchService } from '../../../+search-page/search-service/search.service'; const mockCommunity1Collection1 = Object.assign(new Collection(), { name: 'Community 1-Collection 1', id: '1234567890-1', metadata: [ { key: 'dc.title', language: 'en_US', value: 'Community 1-Collection 1' }] }); const mockCommunity1Collection2 = Object.assign(new Collection(), { name: 'Community 1-Collection 2', id: '1234567890-2', metadata: [ { key: 'dc.title', language: 'en_US', value: 'Community 1-Collection 2' }] }); const mockCommunity2Collection1 = Object.assign(new Collection(), { name: 'Community 2-Collection 1', id: '1234567890-3', metadata: [ { key: 'dc.title', language: 'en_US', value: 'Community 2-Collection 1' }] }); const mockCommunity2Collection2 = Object.assign(new Collection(), { name: 'Community 2-Collection 2', id: '1234567890-4', metadata: [ { key: 'dc.title', language: 'en_US', value: 'Community 2-Collection 2' }] }); const collectionResults = [mockCommunity1Collection1, mockCommunity1Collection2, mockCommunity2Collection1, mockCommunity2Collection2].map((collection: Collection) => Object.assign(new SearchResult<Collection>(), { indexableObject: collection })); const searchService = { search: () => { return observableOf(new RemoteData(true, true, true, undefined, new PaginatedList(new PageInfo(), collectionResults))) } }; const mockCollectionList = [ { communities: [ { id: 'c0e4de93-f506-4990-a840-d406f6f2ada7', name: 'Submission test' } ], collection: { id: '1234567890-1', name: 'Community 1-Collection 1' } }, { communities: [ { id: 'c0e4de93-f506-4990-a840-d406f6f2ada7', name: 'Submission test' } ], collection: { id: '1234567890-2', name: 'Community 1-Collection 2' } }, { communities: [ { id: 'c0e4de93-f506-4990-a840-d406f6f2ada7', name: 'Submission test' } ], collection: { id: '1234567890-3', name: 'Community 2-Collection 1' } }, { communities: [ { id: 'c0e4de93-f506-4990-a840-d406f6f2ada7', name: 'Submission test' } ], collection: { id: '1234567890-4', name: 'Community 2-Collection 2' } } ]; describe('SubmissionFormCollectionComponent Component', () => { let comp: SubmissionFormCollectionComponent; let compAsAny: any; let fixture: ComponentFixture<SubmissionFormCollectionComponent>; let submissionServiceStub: SubmissionServiceStub; let jsonPatchOpServiceStub: SubmissionJsonPatchOperationsServiceStub; const submissionId = mockSubmissionId; const collectionId = '1234567890-1'; const definition = 'traditional'; const submissionRestResponse = mockSubmissionRestResponse; const searchedCollection = 'Community 2-Collection 2'; const communityDataService: any = jasmine.createSpyObj('communityDataService', { findAll: jasmine.createSpy('findAll') }); const store: any = jasmine.createSpyObj('store', { dispatch: jasmine.createSpy('dispatch'), select: jasmine.createSpy('select') }); const jsonPatchOpBuilder: any = jasmine.createSpyObj('jsonPatchOpBuilder', { replace: jasmine.createSpy('replace') }); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ FormsModule, ReactiveFormsModule, NgbModule.forRoot(), TranslateModule.forRoot() ], declarations: [ SubmissionFormCollectionComponent, TestComponent ], providers: [ { provide: SubmissionJsonPatchOperationsService, useClass: SubmissionJsonPatchOperationsServiceStub }, { provide: SubmissionService, useClass: SubmissionServiceStub }, { provide: CommunityDataService, useValue: communityDataService }, { provide: JsonPatchOperationsBuilder, useValue: jsonPatchOpBuilder }, { provide: Store, useValue: store }, { provide: SearchService, useValue: searchService }, ChangeDetectorRef, SubmissionFormCollectionComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }).compileComponents(); })); describe('', () => { let testComp: TestComponent; let testFixture: ComponentFixture<TestComponent>; // synchronous beforeEach beforeEach(() => { const html = ` <ds-submission-form-collection [currentCollectionId]="collectionId" [currentDefinition]="definitionId" [submissionId]="submissionId" (collectionChange)="onCollectionChange($event)"> </ds-submission-form-collection>`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>; testComp = testFixture.componentInstance; }); afterEach(() => { testFixture.destroy(); }); it('should create SubmissionFormCollectionComponent', inject([SubmissionFormCollectionComponent], (app: SubmissionFormCollectionComponent) => { expect(app).toBeDefined(); })); }); describe('', () => { beforeEach(() => { fixture = TestBed.createComponent(SubmissionFormCollectionComponent); comp = fixture.componentInstance; compAsAny = comp; submissionServiceStub = TestBed.get(SubmissionService); jsonPatchOpServiceStub = TestBed.get(SubmissionJsonPatchOperationsService); comp.currentCollectionId = collectionId; comp.currentDefinition = definition; comp.submissionId = submissionId; }); afterEach(() => { comp = null; compAsAny = null; fixture = null; submissionServiceStub = null; jsonPatchOpServiceStub = null; }); it('should init JsonPatchOperationPathCombiner', () => { const expected = new JsonPatchOperationPathCombiner('sections', 'collection'); fixture.detectChanges(); expect(compAsAny.pathCombiner).toEqual(expected); }); it('should init collection list properly', () => { comp.ngOnChanges({ currentCollectionId: new SimpleChange(null, collectionId, true) }); expect(comp.searchListCollection$).toBeObservable(cold('(b)', { b: mockCollectionList })); expect(comp.selectedCollectionName$).toBeObservable(cold('(ab|)', { a: '', b: 'Community 1-Collection 1' })); }); it('should show only the searched collection', () => { comp.searchListCollection$ = observableOf(mockCollectionList); fixture.detectChanges(); comp.searchField.setValue(searchedCollection); fixture.detectChanges(); comp.searchListCollection$.pipe( filter(() => !comp.disabled$.getValue()) ).subscribe((list) => { expect(list).toEqual([mockCollectionList[3]]); }); }); it('should emit collectionChange event when selecting a new collection', () => { spyOn(comp.searchField, 'reset').and.callThrough(); spyOn(comp.collectionChange, 'emit').and.callThrough(); jsonPatchOpServiceStub.jsonPatchByResourceID.and.returnValue(observableOf(submissionRestResponse)); comp.ngOnInit(); comp.onSelect(mockCollectionList[1]); fixture.detectChanges(); expect(comp.searchField.reset).toHaveBeenCalled(); expect(comp.collectionChange.emit).toHaveBeenCalledWith(submissionRestResponse[0]); expect(submissionServiceStub.changeSubmissionCollection).toHaveBeenCalled(); expect(comp.selectedCollectionId).toBe(mockCollectionList[1].collection.id); expect(comp.selectedCollectionName$).toBeObservable(cold('(a|)', { a: mockCollectionList[1].collection.name })); }); it('should reset searchField when dropdown menu has been closed', () => { spyOn(comp.searchField, 'reset').and.callThrough(); comp.toggled(false); expect(comp.searchField.reset).toHaveBeenCalled(); }); describe('', () => { let dropdowBtn: DebugElement; let dropdownMenu: DebugElement; beforeEach(() => { comp.searchListCollection$ = observableOf(mockCollectionList); fixture.detectChanges(); dropdowBtn = fixture.debugElement.query(By.css('#collectionControlsMenuButton')); dropdownMenu = fixture.debugElement.query(By.css('#collectionControlsDropdownMenu')); }); it('should have dropdown menu closed', () => { expect(dropdowBtn).not.toBeUndefined(); expect(dropdownMenu.nativeElement.classList).not.toContain('show'); }); it('should display dropdown menu when click on dropdown button', fakeAsync(() => { spyOn(comp, 'onClose'); dropdowBtn.triggerEventHandler('click', null); tick(); fixture.detectChanges(); fixture.whenStable().then(() => { expect(comp.onClose).toHaveBeenCalled(); expect(dropdownMenu.nativeElement.classList).toContain('show'); expect(dropdownMenu.queryAll(By.css('.collection-item')).length).toBe(4); }); })); it('should trigger onSelect method when select a new collection from dropdown menu', fakeAsync(() => { spyOn(comp, 'onSelect'); dropdowBtn.triggerEventHandler('click', null); tick(); fixture.detectChanges(); const secondLink: DebugElement = dropdownMenu.query(By.css('.collection-item:nth-child(2)')); secondLink.triggerEventHandler('click', null); tick(); fixture.detectChanges(); fixture.whenStable().then(() => { expect(comp.onSelect).toHaveBeenCalled(); }); })); it('should update searchField on input type', fakeAsync(() => { dropdowBtn.triggerEventHandler('click', null); tick(); fixture.detectChanges(); fixture.whenStable().then(() => { const input = fixture.debugElement.query(By.css('input.form-control')); const el = input.nativeElement; expect(el.value).toBe(''); el.value = searchedCollection; el.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(fixture.componentInstance.searchField.value).toEqual(searchedCollection); }); })); }); }); }); // declare a test component @Component({ selector: 'ds-test-cmp', template: `` }) class TestComponent { collectionId = '1234567890-1'; definitionId = 'traditional'; submissionId = mockSubmissionId; onCollectionChange = () => { return; } }