import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {ProductsComponent} from './products.component'; import {Component, DebugElement, Input} from "@angular/core"; import {Product} from "../model/product"; import {ProductsService} from "../services/products.service"; import {ReactiveFormsModule} from "@angular/forms"; import {ActivatedRoute, convertToParamMap, ParamMap, Params} from "@angular/router"; import {of, ReplaySubject} from "rxjs"; import {By} from "@angular/platform-browser"; // mock the child component @Component({ selector: 'app-product', template: '<p>Mock child component</p>' }) class MockChildComponent { @Input() product: Product; @Input() type: number; @Input() queues: Array<any>; } // mock the ActivatedRoute class MockActivatedRoute { private paramsSubject = new ReplaySubject<Params>(); private paramMapSubject = new ReplaySubject<ParamMap>(); private queryParamsSubject = new ReplaySubject<Params>(); private queryParamMapSubject = new ReplaySubject<ParamMap>(); readonly params = this.paramsSubject.asObservable(); readonly paramMap = this.paramMapSubject.asObservable(); readonly queryParams = this.queryParamsSubject.asObservable(); readonly queryParamMap = this.queryParamMapSubject.asObservable(); setParams(params: Params) { this.paramsSubject.next(params); this.paramMapSubject.next(convertToParamMap(params)); } setQueryParams(params: Params) { this.queryParamsSubject.next(params); this.queryParamMapSubject.next(convertToParamMap(params)); } } describe('ProductsComponent', () => { let component: ProductsComponent; let fixture: ComponentFixture<ProductsComponent>; let productsServiceSpy: { getRecordCount: jasmine.Spy, getPage: jasmine.Spy, getPageInfo: jasmine.Spy, getProductById: jasmine.Spy }; let mockActivatedRoute: MockActivatedRoute; beforeEach(async(() => { productsServiceSpy = jasmine.createSpyObj( 'ProductsService', ['getRecordCount', 'getPage', 'getPageInfo', 'getProductById'] ); TestBed.configureTestingModule({ declarations: [ProductsComponent, MockChildComponent], providers: [ {provide: ProductsService, useValue: productsServiceSpy}, {provide: ActivatedRoute, useValue: new MockActivatedRoute()} ], imports: [ReactiveFormsModule] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(ProductsComponent); component = fixture.componentInstance; productsServiceSpy = TestBed.get(ProductsService); mockActivatedRoute = TestBed.get(ActivatedRoute); productsServiceSpy.getRecordCount.and.returnValue(of(123)); productsServiceSpy.getPage.and.returnValue(of([])); productsServiceSpy.getPageInfo.and.returnValue(of([])); productsServiceSpy.getProductById.and.returnValue(of({})); }); it('should create', fakeAsync(() => { expect(component).toBeTruthy(); })); it('should call getPageInfoAndProduct() on Init', fakeAsync(() => { let pageInfoProductSpy = spyOn(component, 'getPageInfoAndProduct'); fixture.detectChanges(); // ngInit expect(pageInfoProductSpy).toHaveBeenCalledTimes(1); })); it('should set pattern when pattern query parameter exists', fakeAsync(() => { mockActivatedRoute.setQueryParams({pattern: 'T01'}); expect(component.pattern).toEqual('', 'pattern starts empty'); fixture.detectChanges(); // ngInit expect(component.pattern).toEqual('T01', 'pattern set from query param'); expect(productsServiceSpy.getRecordCount).toHaveBeenCalledWith(1, 1, 'T01'); })); it('should set epoch when epoch query parameter exists', fakeAsync(() => { mockActivatedRoute.setQueryParams({epoch: -1}); expect(component.epoch).toEqual(1, 'epoch starts at 1'); fixture.detectChanges(); // ngInit expect(component.epoch).toEqual(-1, 'epoch set from query param'); expect(productsServiceSpy.getRecordCount).toHaveBeenCalledWith(-1, 1, ''); })); it('should set type when type query parameter exists', fakeAsync(() => { mockActivatedRoute.setQueryParams({type: 'schedblock'}); expect(component.type).toEqual('calibration', 'type starts with calibration'); fixture.detectChanges(); // ngInit expect(component.type).toEqual('schedblock', 'type set from query param'); expect(productsServiceSpy.getRecordCount).toHaveBeenCalledWith(1, 11, ''); })); it('should update pattern and call getPageInfoAndProduct() with pattern formcontrol changes', fakeAsync(() => { let pattern_inputDe: DebugElement = fixture.debugElement.query(By.css('#pattern')); let pattern_inputEl: HTMLInputElement = pattern_inputDe.nativeElement; let pageInfoProductSpy = spyOn(component, 'getPageInfoAndProduct'); expect(component.pattern).toEqual('', 'pattern starts empty'); fixture.detectChanges(); // ngInit expect(pageInfoProductSpy).toHaveBeenCalledTimes(1); expect(pattern_inputEl.value).toEqual('', 'pattern control is null'); pattern_inputEl.value = 'T01'; pattern_inputEl.dispatchEvent(new Event('input')); tick(500); // for the debounce fixture.detectChanges(); expect(component.pattern).toEqual('T01', 'input updated pattern'); expect(pageInfoProductSpy).toHaveBeenCalledTimes(2); })); it('should update epoch and call getPageInfoAndProduct() with drop down selection', fakeAsync(() => { let dropdownButtonDe: DebugElement = fixture.debugElement.query(By.css('#epoch-select')); let dropdownButtonEl: HTMLButtonElement = dropdownButtonDe.nativeElement; let changeEpochButtonDe: DebugElement = fixture.debugElement.query(By.css('#epoch-select-list li button')); let changeEpochButtonEl: HTMLButtonElement = changeEpochButtonDe.nativeElement; let pageInfoProductSpy = spyOn(component, 'getPageInfoAndProduct'); expect(component.epoch).toEqual(1, 'epoch default value'); fixture.detectChanges(); // ngInit(); expect(pageInfoProductSpy).toHaveBeenCalledTimes(1); expect(dropdownButtonEl.textContent).toEqual('Epoch: Epoch 1', 'UI button default text'); changeEpochButtonEl.click(); fixture.detectChanges(); expect(component.epoch).toEqual(-1, 'update epoch value'); expect(dropdownButtonEl.textContent).toEqual('Epoch: Tests', 'UI button text updated'); expect(pageInfoProductSpy).toHaveBeenCalledTimes(2); })); it('should update type and call getPageInfoAndProduct() with drop down selection', fakeAsync(() => { let dropdownButtonDe: DebugElement = fixture.debugElement.query(By.css('#type-select')); let dropdownButtonEl: HTMLButtonElement = dropdownButtonDe.nativeElement; let changeTypeButtonDe: DebugElement = fixture.debugElement.query(By.css('#type-select-list li button')); let changeTypeButtonEl: HTMLButtonElement = changeTypeButtonDe.nativeElement; let pageInfoProductSpy = spyOn(component, 'getPageInfoAndProduct'); expect(component.type).toEqual('calibration', 'epoch default value'); fixture.detectChanges(); // ngInit(); expect(pageInfoProductSpy).toHaveBeenCalledTimes(1); expect(dropdownButtonEl.textContent).toEqual('Type: calibration', 'UI button default text'); changeTypeButtonEl.click(); fixture.detectChanges(); expect(component.type).toEqual('schedblock', 'update epoch value'); expect(dropdownButtonEl.textContent).toEqual('Type: schedblock', 'UI button text updated'); expect(pageInfoProductSpy).toHaveBeenCalledTimes(2); })); it('getEpochName() should translate numbers to names', () => { expect(component.getEpochName(-1)).toEqual('Tests'); expect(component.getEpochName(0)).toEqual('Pilot'); expect(component.getEpochName(1)).toEqual('Epoch 1'); }); it('getTypeId() should translate names to numbers and toggle value for showImageDetails', () => { expect(component.showImageDetails).toBeFalsy('showImageDetails starts false'); expect(component.getTypeId('schedblock')).toEqual(11); expect(component.showImageDetails).toBeFalsy('showImageDetails is false for schedblock'); expect(component.getTypeId('calibration')).toEqual(1); expect(component.showImageDetails).toBeFalsy('showImageDetails is false for calibration'); expect(component.getTypeId('quicklook')).toEqual(4); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for quicklook'); expect(component.getTypeId('image')).toEqual(1); expect(component.showImageDetails).toBeFalsy('showImageDetails is false for image'); expect(component.getTypeId('cube')).toEqual(2); expect(component.showImageDetails).toBeFalsy('showImageDetails is false for cube'); expect(component.getTypeId('se_calibration')).toEqual(14); expect(component.showImageDetails).toBeFalsy('showImageDetails is false for se_calibration'); expect(component.getTypeId('se_cont')).toEqual(17); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for se_cont'); expect(component.getTypeId('se_coarse_cube_image')).toEqual(18); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for _cube_image'); expect(component.getTypeId('se_coarse_plane_image')).toEqual(19); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for se_coarse_plane_image'); expect(component.getTypeId('se_coarse_plane_I_image')).toEqual(22); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for se_coarse_plane_I_image'); expect(component.getTypeId('se_coarse_plane_Q_image')).toEqual(23); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for se_coarse_plane_Q_image'); expect(component.getTypeId('se_coarse_plane_U_image')).toEqual(24); expect(component.showImageDetails).toBeTruthy('showImageDetails is true for se_coarse_plane_U_image'); }); it('goToPage() should detect edges, set page paramenter and call getProducts()', () => { let getProductsSpy = spyOn(component, "getProducts"); getProductsSpy.and.returnValue(''); component.currentPage = 1; component.pages = 5; expect(component.goToPage(1)).toBeFalsy('return false for request to go to current page'); expect(getProductsSpy).toHaveBeenCalledTimes(0); component.goToPage(6); expect(component.currentPage).toEqual(5, 'send to last page if requested to go to a page beyond it'); expect(getProductsSpy).toHaveBeenCalledTimes(1); component.goToPage(3); expect(component.currentPage).toEqual(3, 'set current page'); expect(getProductsSpy).toHaveBeenCalledTimes(2); }); it('getPages() should return an sequential array of integers the size of pages', () => { component.pages = 5; expect(component.getPages().length).toEqual(5, 'returns array for pages'); }); it('getProducts() should set products from service and call getPageInfo()', fakeAsync(() => { let expectedPageResult = [{ category: "CALIBRATION", completed: false, configurations: [], epoch: 1, extraInfoForJobName: "T13t02.T13t08.T12t08", fileNames: ["PPR.xml"], id: 18469, latestProductVersion: {present: true}, minitiles: [], name: "T13t02.T13t08.T12t08", notes: null, preRequisites: [], status: "COMPLETED", tags: [], typeId: 1, typeName: "calibration", versions: [] } as Product]; productsServiceSpy.getPage.and.returnValue(of(expectedPageResult)); let getPageInfoSpy = spyOn(component, "getPageInfo"); expect(component.products).toEqual([], 'start with empty products array'); expect(component.queues).toEqual([], 'start with empty queues array'); component.getProducts(1); tick(); expect(component.products).toEqual(expectedPageResult, 'set products from service results'); expect(productsServiceSpy.getPage).toHaveBeenCalledTimes(1); expect(getPageInfoSpy).toHaveBeenCalledTimes(1); })); it('getPageInfo() should call a service and set the queues', fakeAsync(() => { let expectedPageInfoResult = ["calibration", "compression"]; productsServiceSpy.getPageInfo.and.returnValue(of(expectedPageInfoResult)); expect(component.products).toEqual([], 'start with empty products array'); expect(component.queues).toEqual([], 'start with empty queues array'); component.getPageInfo(); tick(); expect(productsServiceSpy.getPageInfo).toHaveBeenCalledTimes(1); expect(component.queues).toEqual(expectedPageInfoResult, 'set queues from product service'); })); it('getProductById() should call a service, and set products, numResults, pages, and current page', fakeAsync(() => { let expectedProductResult = { category: "CALIBRATION", completed: false, configurations: [], epoch: 1, extraInfoForJobName: "T13t02.T13t08.T12t08", fileNames: ["PPR.xml"], id: 18469, latestProductVersion: {present: true}, minitiles: [], name: "T13t02.T13t08.T12t08", notes: null, preRequisites: [], status: "COMPLETED", tags: [], typeId: 1, typeName: "calibration", versions: [] } as Product; productsServiceSpy.getProductById.and.returnValue(of(expectedProductResult)); expect(component.products).toEqual([], 'products start empty'); expect(component.numResults).toEqual(0, 'numResults start empty'); expect(component.pages).toEqual(1, 'pages start at 1'); expect(component.currentPage).toEqual(1, 'currentPage start at 1'); // just to check to make sure the changes occur component.pages = 0; component.currentPage = 0; component.getProductById('123'); tick(); expect(productsServiceSpy.getProductById).toHaveBeenCalledWith('123'); expect(component.products).toEqual([expectedProductResult], 'products set with service'); expect(component.numResults).toEqual(1, 'numResults set to 1'); expect(component.pages).toEqual(1, 'pages set to 1'); expect(component.currentPage).toEqual(1, 'currentPage set to 1'); })); it('getPageInfoAndProdct() should determin which retreival functions to call', fakeAsync(() => { let getPageCountSpy = spyOn(component, "getPageCount"); let getProductsSpy = spyOn(component, "getProducts"); let getProductByIdSpy = spyOn(component, "getProductById"); let getPageInfoSpy = spyOn(component, "getPageInfo"); component.pattern = ''; component.getPageInfoAndProduct(); expect(getPageCountSpy).toHaveBeenCalledTimes(1); expect(getProductsSpy).toHaveBeenCalledTimes(1); expect(getProductByIdSpy).toHaveBeenCalledTimes(0); expect(getPageInfoSpy).toHaveBeenCalledTimes(1); component.pattern = 'ABC'; component.getPageInfoAndProduct(); expect(getPageCountSpy).toHaveBeenCalledTimes(2); expect(getProductsSpy).toHaveBeenCalledTimes(2); expect(getProductByIdSpy).toHaveBeenCalledTimes(0); expect(getPageInfoSpy).toHaveBeenCalledTimes(2); component.pattern = '123'; component.getPageInfoAndProduct(); expect(getPageCountSpy).toHaveBeenCalledTimes(2); expect(getProductsSpy).toHaveBeenCalledTimes(2); expect(getProductByIdSpy).toHaveBeenCalledTimes(1); expect(getPageInfoSpy).toHaveBeenCalledTimes(3); })); });