/*! * @license * Copyright 2019 Alfresco Software, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { async, fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NodeEntry, Node, SiteEntry, SitePaging } from '@alfresco/js-api'; import { SearchService, SitesService, setupTestBed } from '@alfresco/adf-core'; import { Observable, Observer, of, throwError } from 'rxjs'; import { DropdownBreadcrumbComponent } from '../breadcrumb'; import { ContentNodeSelectorPanelComponent } from './content-node-selector-panel.component'; import { ContentNodeSelectorService } from './content-node-selector.service'; import { NodePaging } from '@alfresco/js-api'; import { ContentTestingModule } from '../testing/content.testing.module'; import { DocumentListService } from '../document-list/services/document-list.service'; import { DocumentListComponent } from '../document-list/components/document-list.component'; import { CustomResourcesService } from '../document-list/services/custom-resources.service'; import { ShareDataRow } from '../document-list'; const ONE_FOLDER_RESULT = { list: { entries: [ { entry: { id: '123', name: 'MyFolder', isFile: false, isFolder: true, createdByUser: { displayName: 'John Doe' }, modifiedByUser: { displayName: 'John Doe' } } } ], pagination: { hasMoreItems: true } } }; describe('ContentNodeSelectorComponent', () => { const debounceSearch = 200; let component: ContentNodeSelectorPanelComponent; let fixture: ComponentFixture; let contentNodeSelectorService: ContentNodeSelectorService; let searchService: SearchService; let searchSpy: jasmine.Spy; let cnSearchSpy: jasmine.Spy; let _observer: Observer; function typeToSearchBox(searchTerm = 'string-to-search') { const searchInput = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-input"]')); searchInput.nativeElement.value = searchTerm; component.searchInput.setValue(searchTerm); fixture.detectChanges(); } function respondWithSearchResults(result) { _observer.next(result); } setupTestBed({ imports: [ContentTestingModule], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); describe('General component features', () => { beforeEach(() => { fixture = TestBed.createComponent(ContentNodeSelectorPanelComponent); component = fixture.componentInstance; component.debounceSearch = 0; searchService = TestBed.get(SearchService); contentNodeSelectorService = TestBed.get(ContentNodeSelectorService); cnSearchSpy = spyOn(contentNodeSelectorService, 'search').and.callThrough(); searchSpy = spyOn(searchService, 'searchByQueryBody').and.callFake(() => { return new Observable((observer: Observer) => { _observer = observer; }); }); }); afterEach(() => { fixture.destroy(); }); describe('Parameters', () => { let documentListService, sitesService; beforeEach(() => { documentListService = TestBed.get(DocumentListService); sitesService = TestBed.get(SitesService); spyOn(documentListService, 'getFolderNode').and.returnValue(of( { entry: { path: { elements: [] } } })); spyOn(documentListService, 'getFolder').and.returnValue(throwError('No results for test')); spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [ { entry: { guid: 'namek', id: 'namek' } }, { entry: { guid: 'blog', id: 'blog' } }] } })); component.currentFolderId = 'cat-girl-nuku-nuku'; fixture.detectChanges(); }); it('should the document list use the server ordering', () => { expect(component.documentList.sorting).toBe('server'); }); it('should trigger the select event when selection has been made', (done) => { const expectedNode = {}; component.select.subscribe((nodes) => { expect(nodes.length).toBe(1); expect(nodes[0]).toBe(expectedNode); done(); }); component.chosenNode = expectedNode; }); it('should be able to filter out the exclude site content', () => { component.excludeSiteContent = ['blog']; fixture.detectChanges(); const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' } }); expect(component.rowFilter( { node: { entry: testSiteContent } }, null, null)) .toBe(false, 'did not filter out blog'); }); it('should still be able to filter out the exclude site content after rowFilter changes', () => { const filterFunction1 = () => { return true; }; const filterFunction2 = (row: ShareDataRow) => { const node: Node = row.node.entry; return node.isFile; }; component.excludeSiteContent = ['blog']; component.rowFilter = filterFunction1; fixture.detectChanges(); const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' }, isFile: true }); expect(component.rowFilter( { node: { entry: testSiteContent } }, null, null)) .toBe(false, 'did not filter out blog with filterFunction1'); component.rowFilter = filterFunction2; fixture.detectChanges(); expect(component.rowFilter( { node: { entry: testSiteContent } }, null, null)) .toBe(false, 'did not filter out blog with filterFunction2'); }); it('should NOT filter out any site content by default', () => { fixture.detectChanges(); const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' } }); expect(component.rowFilter( { node: { entry: testSiteContent } }, null, null)).toBe(true); }); }); describe('Breadcrumbs', () => { let documentListService, sitesService; beforeEach(() => { documentListService = TestBed.get(DocumentListService); sitesService = TestBed.get(SitesService); spyOn(documentListService, 'getFolderNode').and.returnValue(of( { entry: { path: { elements: [] } } })); spyOn(documentListService, 'getFolder').and.returnValue(throwError('No results for test')); spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } })); component.currentFolderId = 'cat-girl-nuku-nuku'; fixture.detectChanges(); }); it('should show the breadcrumb for the currentFolderId by default', (done) => { fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb).not.toBeNull(); expect(breadcrumb.componentInstance.folderNode).toEqual(undefined); done(); }); }); it('should not show the breadcrumb if search was performed as last action', fakeAsync(() => { typeToSearchBox(); tick(debounceSearch); fixture.detectChanges(); respondWithSearchResults(ONE_FOLDER_RESULT); tick(debounceSearch); fixture.detectChanges(); tick(debounceSearch); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb).toBeNull(); })); it('should show the breadcrumb again on folder navigation in the results list', fakeAsync(() => { typeToSearchBox(); tick(debounceSearch); fixture.detectChanges(); respondWithSearchResults(ONE_FOLDER_RESULT); tick(debounceSearch); fixture.detectChanges(); tick(debounceSearch); component.onFolderChange(); fixture.detectChanges(); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb).not.toBeNull(); })); it('should show the breadcrumb for the selected node when search results are displayed', fakeAsync(() => { typeToSearchBox(); tick(debounceSearch); fixture.detectChanges(); respondWithSearchResults(ONE_FOLDER_RESULT); fixture.detectChanges(); tick(debounceSearch); const chosenNode = new Node({ path: { elements: ['one'] } }); component.onNodeSelect({ detail: { node: { entry: chosenNode } } }); fixture.detectChanges(); tick(debounceSearch); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb).not.toBeNull(); expect(breadcrumb.componentInstance.folderNode.path).toBe(chosenNode.path); })); it('should NOT show the breadcrumb for the selected node when not on search results list', fakeAsync(() => { typeToSearchBox(); fixture.detectChanges(); respondWithSearchResults(ONE_FOLDER_RESULT); fixture.detectChanges(); component.onFolderChange(); fixture.detectChanges(); const chosenNode = { path: { elements: [] } }; component.onNodeSelect({ detail: { node: { entry: chosenNode } } }); fixture.detectChanges(); tick(debounceSearch); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb).not.toBeNull(); expect(breadcrumb.componentInstance.folderNode).toEqual(undefined); })); it('should keep breadcrumb\'s folderNode unchanged if breadcrumbTransform is NOT defined', (done) => { fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); expect(component.breadcrumbTransform).toBeNull(); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb.componentInstance.folderNode).toEqual(undefined); done(); }); }); it('should make changes to breadcrumb\'s folderNode if breadcrumbTransform is defined', (done) => { const transformedFolderNode = { id: 'trans-node', name: 'trans-node-name', path: { elements: [{ id: 'testId', name: 'testName' }] } }; component.breadcrumbTransform = (() => { return transformedFolderNode; }); fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); expect(component.breadcrumbTransform).not.toBeNull(); const breadcrumb = fixture.debugElement.query(By.directive(DropdownBreadcrumbComponent)); expect(breadcrumb.componentInstance.route[0].name).toBe('testName'); expect(breadcrumb.componentInstance.route[0].id).toBe('testId'); done(); }); }); }); describe('Search functionality', () => { let getCorrespondingNodeIdsSpy; const defaultSearchOptions = (searchTerm, rootNodeId = undefined, skipCount = 0) => { const parentFiltering = rootNodeId ? [{ query: `ANCESTOR:'workspace://SpacesStore/${rootNodeId}'` }] : []; const defaultSearchNode: any = { query: { query: searchTerm ? `${searchTerm}* OR name:${searchTerm}*` : searchTerm }, include: ['path', 'allowableOperations', 'properties'], paging: { maxItems: 25, skipCount: skipCount }, filterQueries: [ { query: "TYPE:'cm:folder'" }, { query: 'NOT cm:creator:System' }, ...parentFiltering ], scope: { locations: ['nodes'] } }; return defaultSearchNode; }; beforeEach(() => { const documentListService = TestBed.get(DocumentListService); const expectedDefaultFolderNode = { entry: { path: { elements: [] } } }; spyOn(documentListService, 'getFolderNode').and.returnValue(of(expectedDefaultFolderNode)); spyOn(documentListService, 'getFolder').and.returnValue(of({ list: { pagination: {}, entries: [], source: {} } })); const sitesService = TestBed.get(SitesService); spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } })); const customResourcesService = TestBed.get(CustomResourcesService); getCorrespondingNodeIdsSpy = spyOn(customResourcesService, 'getCorrespondingNodeIds').and .callFake((id) => { if (id === '-sites-') { return of(['123456testId', '09876543testId']); } return of([id]); }); component.currentFolderId = 'cat-girl-nuku-nuku'; component.documentList.ngOnInit(); fixture.detectChanges(); }); it('should load the results by calling the search api on search change', fakeAsync(() => { typeToSearchBox('kakarot'); tick(debounceSearch); fixture.detectChanges(); expect(searchSpy).toHaveBeenCalledWith(defaultSearchOptions('kakarot')); })); it('should reset the currently chosen node in case of starting a new search', fakeAsync(() => { component.chosenNode = {}; typeToSearchBox('kakarot'); tick(debounceSearch); fixture.detectChanges(); expect(component.chosenNode).toBeNull(); })); it('should call the search api on changing the site selectBox value', fakeAsync(() => { typeToSearchBox('vegeta'); tick(debounceSearch); expect(searchSpy.calls.count()).toBe(1, 'Search count should be one after only one search'); component.siteChanged( { entry: { guid: 'namek' } }); expect(searchSpy.calls.count()).toBe(2, 'Search count should be two after the site change'); expect(searchSpy.calls.argsFor(1)).toEqual([defaultSearchOptions('vegeta', 'namek')]); })); it('should call the content node selector\'s search with the right parameters on changing the site selectbox\'s value', fakeAsync(() => { typeToSearchBox('vegeta'); tick(debounceSearch); expect(cnSearchSpy.calls.count()).toBe(1); component.siteChanged( { entry: { guid: '-sites-' } }); expect(cnSearchSpy).toHaveBeenCalled(); expect(cnSearchSpy.calls.count()).toBe(2); expect(cnSearchSpy).toHaveBeenCalledWith('vegeta', undefined, 0, 25); expect(cnSearchSpy).toHaveBeenCalledWith('vegeta', '-sites-', 0, 25, ['123456testId', '09876543testId']); })); it('should call the content node selector\'s search with the right parameters on changing the site selectBox value from a custom dropdown menu', fakeAsync(() => { component.dropdownSiteList = { list: { entries: [ { entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } }; fixture.detectChanges(); typeToSearchBox('vegeta'); tick(debounceSearch); expect(cnSearchSpy.calls.count()).toBe(1); component.siteChanged( { entry: { guid: '-sites-' } }); expect(cnSearchSpy).toHaveBeenCalled(); expect(cnSearchSpy.calls.count()).toBe(2); expect(cnSearchSpy).toHaveBeenCalledWith('vegeta', undefined, 0, 25); expect(cnSearchSpy).toHaveBeenCalledWith('vegeta', '-sites-', 0, 25, ['123456testId', '09876543testId']); })); it('should get the corresponding node ids on search when a known alias is selected from dropdown', fakeAsync(() => { typeToSearchBox('vegeta'); tick(debounceSearch); component.siteChanged( { entry: { guid: '-sites-' } }); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1, 'getCorrespondingNodeIdsSpy calls count should be one after the site changes to known alias \'-sites\-'); expect(getCorrespondingNodeIdsSpy.calls.mostRecent().args[0]).toEqual('-sites-'); })); it('should get the corresponding node ids on search when a known alias is selected from CUSTOM dropdown', fakeAsync(() => { component.dropdownSiteList = { list: { entries: [ { entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } }; fixture.detectChanges(); typeToSearchBox('vegeta'); tick(debounceSearch); component.siteChanged( { entry: { guid: '-sites-' } }); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(1); expect(getCorrespondingNodeIdsSpy.calls.mostRecent().args[0]).toEqual('-sites-'); })); it('should NOT get the corresponding node ids on search when NOTHING is selected from dropdown', fakeAsync(() => { component.dropdownSiteList = { list: { entries: [ { entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } }; fixture.detectChanges(); typeToSearchBox('vegeta'); tick(debounceSearch); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0, 'getCorrespondingNodeIdsSpy calls count should be 0 when no site is selected'); })); it('should NOT get the corresponding node ids on search when NO known alias is selected from dropdown', fakeAsync(() => { typeToSearchBox('vegeta'); tick(debounceSearch); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0, 'getCorrespondingNodeIdsSpy should not be called'); component.siteChanged( { entry: { guid: 'namek' } }); expect(getCorrespondingNodeIdsSpy).not.toHaveBeenCalled(); })); it('should NOT get the corresponding node ids on search when NO known alias is selected from CUSTOM dropdown', fakeAsync(() => { component.dropdownSiteList = { list: { entries: [ { entry: { guid: '-sites-' } }, { entry: { guid: 'namek' } }] } }; fixture.detectChanges(); typeToSearchBox('vegeta'); tick(debounceSearch); expect(getCorrespondingNodeIdsSpy.calls.count()).toBe(0, 'getCorrespondingNodeIdsSpy should not be called'); component.siteChanged( { entry: { guid: 'namek' } }); expect(getCorrespondingNodeIdsSpy).not.toHaveBeenCalled(); })); it('should show the search icon by default without the X (clear) icon', fakeAsync(() => { fixture.detectChanges(); tick(debounceSearch); const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]')); const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]')); expect(searchIcon).not.toBeNull('Search icon should be in the DOM'); expect(clearIcon).toBeNull('Clear icon should NOT be in the DOM'); })); it('should show the X (clear) icon without the search icon when the search contains at least one character', fakeAsync(() => { fixture.detectChanges(); typeToSearchBox('123'); tick(debounceSearch); fixture.detectChanges(); const searchIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-icon"]')); const clearIcon = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]')); expect(searchIcon).toBeNull('Search icon should NOT be in the DOM'); expect(clearIcon).not.toBeNull('Clear icon should be in the DOM'); })); it('should clear the search field, nodes and chosenNode when clicking on the X (clear) icon', () => { component.chosenNode = {}; component.nodePaging = { list: { entries: [{ entry: component.chosenNode }] } }; component.searchTerm = 'piccolo'; component.showingSearchResults = true; component.clear(); expect(component.searchTerm).toBe(''); expect(component.nodePaging).toEqual(null); expect(component.chosenNode).toBeNull(); expect(component.showingSearchResults).toBeFalsy(); }); it('should clear the search field, nodes and chosenNode when deleting the search input', fakeAsync(() => { spyOn(component, 'clear').and.callThrough(); typeToSearchBox('a'); tick(debounceSearch); fixture.detectChanges(); expect(searchSpy.calls.count()).toBe(1); typeToSearchBox(''); tick(debounceSearch); fixture.detectChanges(); expect(searchSpy.calls.count()).toBe(1, 'no other search has been performed'); expect(component.clear).toHaveBeenCalled(); expect(component.folderIdToShow).toBe('cat-girl-nuku-nuku', 'back to the folder in which the search was performed'); })); it('should clear the search field, nodes and chosenNode on folder navigation in the results list', fakeAsync(() => { spyOn(component, 'clearSearch').and.callThrough(); typeToSearchBox('a'); tick(debounceSearch); fixture.detectChanges(); respondWithSearchResults(ONE_FOLDER_RESULT); tick(); fixture.detectChanges(); component.onFolderChange(); fixture.detectChanges(); expect(component.clearSearch).toHaveBeenCalled(); })); it('should show nodes from the same folder as selected in the dropdown on clearing the search input', fakeAsync(() => { typeToSearchBox('piccolo'); tick(debounceSearch); expect(searchSpy.calls.count()).toBe(1); component.siteChanged( { entry: { guid: 'namek' } }); expect(searchSpy.calls.count()).toBe(2); expect(searchSpy.calls.argsFor(1)).toEqual([defaultSearchOptions('piccolo', 'namek')]); component.clear(); expect(component.searchTerm).toBe(''); expect(component.folderIdToShow).toBe('namek'); })); it('should show the current folder\'s content instead of search results if search was not performed', () => { const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku'); }); it('should pass through the rowFilter to the documentList', () => { const filter = (shareDataRow: ShareDataRow) => shareDataRow.node.entry.name === 'impossible-name'; component.rowFilter = filter; fixture.detectChanges(); const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.rowFilter({ node: { entry: new Node({ name: 'impossible-name', id: 'name' }) } })) .toBe(filter( { node: { entry: new Node({ name: 'impossible-name', id: 'name' }) } })); }); it('should pass through the excludeSiteContent to the rowFilter of the documentList', () => { component.excludeSiteContent = ['blog']; fixture.detectChanges(); const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.rowFilter).toBeTruthy('Document list should have had a rowFilter'); const testSiteContent = new Node({ id: 'blog-id', properties: { 'st:componentId': 'blog' } }); expect(documentList.componentInstance.rowFilter( { node: { entry: testSiteContent } }, null, null)) .toBe(false); }); it('should pass through the imageResolver to the documentList', () => { const resolver = () => 'piccolo'; component.imageResolver = resolver; fixture.detectChanges(); const documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.imageResolver).toBe(resolver); }); it('should show the result list when search was performed', (done) => { typeToSearchBox(); setTimeout(() => { respondWithSearchResults(ONE_FOLDER_RESULT); fixture.detectChanges(); const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]')); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.currentFolderId).toBeNull(); done(); }, 300); }); it('should highlight the results when search was performed in the next timeframe', (done) => { typeToSearchBox('My'); setTimeout(() => { respondWithSearchResults(ONE_FOLDER_RESULT); fixture.detectChanges(); fixture.whenStable().then(() => { expect(fixture.debugElement.nativeElement.querySelector('.adf-highlight').innerHTML).toBe('My'); done(); }); }, 300); }); it('should show the default text instead of result list if search was cleared', (done) => { typeToSearchBox(); setTimeout(() => { respondWithSearchResults(ONE_FOLDER_RESULT); fixture.detectChanges(); fixture.whenStable().then(() => { const clearButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-search-clear"]')); expect(clearButton).not.toBeNull('Clear button should be in DOM'); clearButton.triggerEventHandler('click', {}); fixture.detectChanges(); const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]')); expect(documentList).not.toBeNull('Document list should be shown'); expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku'); done(); }); }, 300); }); it('should reload the original documentList when clearing the search input', fakeAsync(() => { typeToSearchBox('shenron'); tick(debounceSearch); respondWithSearchResults(ONE_FOLDER_RESULT); typeToSearchBox(''); tick(debounceSearch); fixture.detectChanges(); const documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]')); expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku'); })); it('should set the folderIdToShow to the default "currentFolderId" if siteId is undefined', (done) => { component.siteChanged( { entry: { guid: 'Kame-Sennin Muten Roshi' } }); fixture.detectChanges(); let documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]')); expect(documentList.componentInstance.currentFolderId).toBe('Kame-Sennin Muten Roshi'); component.siteChanged( { entry: { guid: undefined } }); fixture.detectChanges(); documentList = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-document-list"]')); expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku'); done(); }); describe('Pagination "Load more" button', () => { it('should NOT be shown by default', () => { fixture.detectChanges(); const pagination = fixture.debugElement.query(By.css('[data-automation-id="adf-infinite-pagination-button"]')); expect(pagination).toBeNull(); }); it('button callback should load the next batch of folder results when there is no searchTerm', () => { component.searchTerm = ''; fixture.detectChanges(); component.getNextPageOfSearch({ hasMoreItems: false, skipCount: 10, maxItems: 45, totalItems: 0 }); fixture.detectChanges(); expect(component.searchTerm).toBe(''); expect(component.infiniteScroll).toBeTruthy(); expect(component.pagination.maxItems).toBe(45); expect(searchSpy).not.toHaveBeenCalled(); }); it('should set its loading state to true after search was started', fakeAsync(() => { component.showingSearchResults = true; typeToSearchBox('shenron'); tick(debounceSearch); fixture.detectChanges(); tick(debounceSearch); const spinnerSelector = By.css('[data-automation-id="content-node-selector-search-pagination"] [data-automation-id="adf-infinite-pagination-spinner"]'); const paginationLoading = fixture.debugElement.query(spinnerSelector); expect(paginationLoading).not.toBeNull(); })); it('Should infinite pagination target be null when we use it for search ', fakeAsync(() => { component.showingSearchResults = true; typeToSearchBox('shenron'); tick(debounceSearch); fixture.detectChanges(); tick(debounceSearch); expect(component.target).toBeNull(); })); it('Should infinite pagination target be present when search finish', fakeAsync(() => { component.showingSearchResults = true; typeToSearchBox('shenron'); tick(debounceSearch); fixture.detectChanges(); typeToSearchBox(''); tick(debounceSearch); fixture.detectChanges(); expect(component.target).not.toBeNull(); })); it('Should infinite pagination target on init be the document list', fakeAsync(() => { component.showingSearchResults = true; expect(component.target).toEqual(component.documentList); })); }); }); describe('Chosen node', () => { const entry: Node = {}; const nodePage: NodePaging = { list: {}, pagination: {} }; let hasAllowableOperations; function returnHasPermission(): boolean { return hasAllowableOperations; } beforeEach(() => { const sitesService = TestBed.get(SitesService); spyOn(sitesService, 'getSites').and.returnValue(of({ list: { entries: [] } })); }); describe('in the case when isSelectionValid is a custom function for checking permissions,', () => { beforeEach(() => { component.isSelectionValid = returnHasPermission; }); it('should NOT be null after selecting node with the necessary permissions', async(() => { hasAllowableOperations = true; component.documentList.folderNode = entry; component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).toBe(entry); }); component.documentList.ready.emit(nodePage); fixture.detectChanges(); })); it('should be null after selecting node without the necessary permissions', async(() => { hasAllowableOperations = false; component.documentList.folderNode = entry; component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); }); component.documentList.ready.emit(nodePage); fixture.detectChanges(); })); it('should NOT be null after clicking on a node (with the right permissions) in the list (onNodeSelect)', async(() => { hasAllowableOperations = true; component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).toBe(entry); }); component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); })); it('should remain null when clicking on a node (with the WRONG permissions) in the list (onNodeSelect)', async(() => { hasAllowableOperations = false; component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); }); component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); })); it('should become null when clicking on a node (with the WRONG permissions) after previously selecting a right node', async(() => { component.select.subscribe((nodes) => { if (hasAllowableOperations) { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).not.toBeNull(); } else { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); } }); hasAllowableOperations = true; component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); hasAllowableOperations = false; component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); })); it('should be null when the chosenNode is reset', async(() => { hasAllowableOperations = true; component.onNodeSelect({ detail: { node: { entry: {} } } }); fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); }); component.resetChosenNode(); fixture.detectChanges(); })); }); describe('in the case when isSelectionValid is null', () => { beforeEach(() => { component.isSelectionValid = null; }); it('should NOT be null after selecting node because isSelectionValid would be reset to defaultValidation function', async(() => { component.documentList.folderNode = entry; fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).not.toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); component.documentList.ready.emit(nodePage); fixture.detectChanges(); })); it('should NOT be null after clicking on a node in the list (onNodeSelect)', async(() => { fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).not.toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); })); it('should be null when the chosenNode is reset', async(() => { fixture.detectChanges(); component.onNodeSelect({ detail: { node: { entry: {} } } }); fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); component.resetChosenNode(); fixture.detectChanges(); })); }); describe('in the case when isSelectionValid is not defined', () => { beforeEach(() => { component.isSelectionValid = undefined; }); it('should NOT be null after selecting node because isSelectionValid would be the defaultValidation function', async(() => { component.documentList.folderNode = entry; fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).not.toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); component.documentList.ready.emit(nodePage); fixture.detectChanges(); })); it('should NOT be null after clicking on a node in the list (onNodeSelect)', async(() => { component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).not.toBeNull(); expect(component.chosenNode).not.toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); fixture.detectChanges(); component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); })); it('should be null when the chosenNode is reset', async(() => { fixture.detectChanges(); component.onNodeSelect({ detail: { node: { entry: {} } } }); fixture.detectChanges(); component.select.subscribe((nodes) => { expect(nodes).toBeDefined(); expect(nodes).toBeNull(); expect(component.chosenNode).toBeNull(); expect(component.isSelectionValid).not.toBeNull(); }); component.resetChosenNode(); fixture.detectChanges(); })); }); }); }); });