// Load the implementations that should be tested import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core'; import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { By } from '@angular/platform-browser'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { StoreModule } from '@ngrx/store'; import { NgxPaginationModule } from 'ngx-pagination'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { PaginationComponent } from './pagination.component'; import { PaginationComponentOptions } from './pagination-component-options.model'; import { TranslateLoaderMock } from '../mocks/translate-loader.mock'; import { HostWindowServiceMock } from '../mocks/host-window-service.mock'; import { MockActivatedRoute } from '../mocks/active-router.mock'; import { RouterMock } from '../mocks/router.mock'; import { HostWindowService } from '../host-window.service'; import { EnumKeysPipe } from '../utils/enum-keys-pipe'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { createTestComponent } from '../testing/utils.test'; import { storeModuleConfig } from '../../app.reducer'; import { PaginationService } from '../../core/pagination/pagination.service'; import { FindListOptions } from '../../core/data/request.models'; import { BehaviorSubject, of as observableOf } from 'rxjs'; import { PaginationServiceStub } from '../testing/pagination-service.stub'; function expectPages(fixture: ComponentFixture, pagesDef: string[]): void { const de = fixture.debugElement.query(By.css('.pagination')); const pages = de.nativeElement.querySelectorAll('li'); expect(pages.length).toEqual(pagesDef.length); for (let i = 0; i < pagesDef.length; i++) { const pageDef = pagesDef[i]; const classIndicator = pageDef.charAt(0); if (classIndicator === '+') { expect(pages[i].classList.contains('active')).toBeTruthy(); expect(pages[i].classList.contains('disabled')).toBeFalsy(); expect(normalizeText(pages[i].textContent)).toEqual(normalizeText(pageDef)); } else if (classIndicator === '-') { expect(pages[i].classList.contains('active')).toBeFalsy(); expect(pages[i].classList.contains('disabled')).toBeTruthy(); expect(normalizeText(pages[i].textContent)).toEqual(normalizeText(pageDef)); if (normalizeText(pages[i].textContent) !== '...') { expect(pages[i].querySelector('a').getAttribute('tabindex')).toEqual('-1'); } } else { expect(pages[i].classList.contains('active')).toBeFalsy(); expect(pages[i].classList.contains('disabled')).toBeFalsy(); expect(normalizeText(pages[i].textContent)).toEqual(normalizeText(pageDef)); if (normalizeText(pages[i].textContent) !== '...') { expect(pages[i].querySelector('a').hasAttribute('tabindex')).toBeFalsy(); } } } } function changePageSize(fixture: ComponentFixture, pageSize: string): void { const buttonEl = fixture.nativeElement.querySelector('#paginationControls'); buttonEl.click(); const dropdownMenu = fixture.debugElement.query(By.css('#paginationControlsDropdownMenu')); const buttons = dropdownMenu.nativeElement.querySelectorAll('button'); for (const button of buttons) { if (button.textContent.trim() === pageSize) { button.click(); fixture.detectChanges(); break; } } } function changePage(fixture: ComponentFixture, idx: number): void { const de = fixture.debugElement.query(By.css('.pagination')); const buttons = de.nativeElement.querySelectorAll('li'); buttons[idx].querySelector('a').click(); fixture.detectChanges(); } function normalizeText(txt: string): string { const matches = txt.match(/([0-9«»]|\.{3})/); return matches ? matches[0] : ''; } describe('Pagination component', () => { let testComp: TestComponent; let testFixture: ComponentFixture; let de: DebugElement; let html; let hostWindowServiceStub: HostWindowServiceMock; let activatedRouteStub: MockActivatedRoute; let routerStub: RouterMock; let paginationService; // Define initial state and test state const _initialState = { width: 1600, height: 770 }; const pagination = new PaginationComponentOptions(); pagination.currentPage = 1; pagination.pageSize = 10; const sort = new SortOptions('score', SortDirection.DESC); const findlistOptions = Object.assign(new FindListOptions(), { currentPage: 1, elementsPerPage: 10 }); let currentPagination; let currentSort; let currentFindListOptions; // waitForAsync beforeEach beforeEach(waitForAsync(() => { activatedRouteStub = new MockActivatedRoute(); routerStub = new RouterMock(); hostWindowServiceStub = new HostWindowServiceMock(_initialState.width); currentPagination = new BehaviorSubject(pagination); currentSort = new BehaviorSubject(sort); currentFindListOptions = new BehaviorSubject(findlistOptions); paginationService = jasmine.createSpyObj('PaginationService', { getCurrentPagination: currentPagination, getCurrentSort: currentSort, getFindListOptions: currentFindListOptions, resetPage: {}, updateRoute: {}, updateRouteWithUrl: {} }); TestBed.configureTestingModule({ imports: [ CommonModule, StoreModule.forRoot({}, storeModuleConfig), TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateLoaderMock } }), NgxPaginationModule, NgbModule, RouterTestingModule.withRoutes([ { path: 'home', component: TestComponent } ])], declarations: [ PaginationComponent, TestComponent, EnumKeysPipe ], // declare the test component providers: [ { provide: ActivatedRoute, useValue: activatedRouteStub }, { provide: Router, useValue: routerStub }, { provide: HostWindowService, useValue: hostWindowServiceStub }, { provide: PaginationService, useValue: paginationService }, ChangeDetectorRef, PaginationComponent ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }); })); // synchronous beforeEach beforeEach(() => { html = `
  • {{item}}
`; testFixture = createTestComponent(html, TestComponent) as ComponentFixture; testComp = testFixture.componentInstance; }); it('should create Pagination Component', inject([PaginationComponent], (app: PaginationComponent) => { expect(app).toBeDefined(); })); it('should render', () => { expect(testComp.paginationOptions.id).toEqual('test'); expect(testComp.paginationOptions.currentPage).toEqual(1); expect(testComp.paginationOptions.pageSize).toEqual(10); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '» Next']); }); it('should render and respond to page change', () => { testComp.collectionSize = 30; testFixture.detectChanges(); currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 3})); testFixture.detectChanges(); expectPages(testFixture, ['« Previous', '1', '2', '+3', '-» Next']); currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 2})); testFixture.detectChanges(); expectPages(testFixture, ['« Previous', '1', '+2', '3', '» Next']); }); it('should render and respond to collectionSize change', () => { testComp.collectionSize = 30; testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']); testComp.collectionSize = 40; testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '» Next']); }); it('should render and respond to pageSize change', () => { const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p; testComp.collectionSize = 30; testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']); currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 5})); testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '» Next']); currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 10})); testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']); currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 20})); testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '» Next']); }); it('should emit pageSizeChange event with correct value', fakeAsync(() => { const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p; spyOn(testComp, 'pageSizeChanged'); testComp.pageSizeChanged(5); tick(); expect(testComp.pageSizeChanged).toHaveBeenCalledWith(5); })); it('should call the updateRoute method on the paginationService with the correct params', fakeAsync(() => { testComp.collectionSize = 60; changePage(testFixture, 3); tick(); expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '3'}), {}, false); changePage(testFixture, 0); tick(); expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '2'}), {}, false); })); it('should set correct pageSize route parameters', fakeAsync(() => { routerStub = testFixture.debugElement.injector.get(Router) as any; testComp.collectionSize = 60; changePageSize(testFixture, '20'); tick(); expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ pageId: 'test', page: 1, pageSize: 20}), {}, false); })); it('should respond to windows resize', () => { const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p; hostWindowServiceStub = testFixture.debugElement.injector.get(HostWindowService) as any; hostWindowServiceStub.setWidth(400); hostWindowServiceStub.isXs().subscribe((status) => { paginationComponent.isXs = status; testFixture.detectChanges(); expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '-...', '10', '» Next']); de = testFixture.debugElement.query(By.css('ul.pagination')); expect(de.nativeElement.classList.contains('pagination-sm')).toBeTruthy(); }); }); }); // declare a test component @Component({ selector: 'ds-test-cmp', template: '' }) class TestComponent { collection: string[] = []; collectionSize: number; paginationOptions = new PaginationComponentOptions(); sortOptions = new SortOptions('dc.title', SortDirection.ASC); constructor() { this.collection = Array.from(new Array(100), (x, i) => `item ${i + 1}`); this.collectionSize = 100; this.paginationOptions.id = 'test'; } pageChanged(page) { this.paginationOptions.currentPage = page; } pageSizeChanged(pageSize) { this.paginationOptions.pageSize = pageSize; } }