Having trouble setting up my Angular test correctly. The issue seems to be with my spy not functioning as expected. I'm new to Angular and still learning how to write tests. This is for my first Angular app using the latest version of CLI 7.x, which is a simple slideshow application. The slideshow itself works fine, but I'm having difficulties getting the tests to pass.
The initial challenge involves extracting the href from the JavaScript window.location. Following advice from Stackoverflow and other sources, I created a class to encapsulate the window object to make it testable. Here's what it looks like in a service named windowobject.service.ts:
import { Injectable } from '@angular/core';
function getWindow (): any {
return window;
}
@Injectable({
providedIn: 'root'
})
export class WindowObjectService {
constructor() { }
get browserWindow(): any {
return getWindow();
}
}
While this setup works perfectly, the problem arises when trying to mock it in the test. My test file is called photos.component.spec.ts:
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { PhotosComponent } from './photos.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' ;
import { WindowObjectService } from '../services/windowobject.service';
import { environment } from '../../environments/environment';
const expectedId = 916;
class MockWindowObjectService {
browserWindow(): any {
return { window: {
location: {
href: environment.baseUrl + '/angular/slideshow/index.html?id=' + expectedId
}
}
};
}
}
describe('PhotosComponent', () => {
let component: PhotosComponent;
let fixture: ComponentFixture<PhotosComponent>;
let windowService: MockWindowObjectService;
let windowSpy;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, NgbModule ],
declarations: [PhotosComponent],
providers: [ { provide: WindowObjectService, useClass: MockWindowObjectService } ]
})
.compileComponents().then(() => {
windowService = TestBed.get(WindowObjectService);
fixture = TestBed.createComponent(PhotosComponent);
component = fixture.componentInstance;
});
}));
it('should create', () => {
expect(component).toBeTruthy();
});
it('should call window object service', () => {
windowSpy = spyOn(windowService, 'browserWindow').and.callThrough();
expect(windowService.browserWindow).toHaveBeenCalled();
});
});
Currently working on mocking the window object service and verifying if it has been called successfully. Once confirmed, the next step would be to check if it returns the mocked value. I've experimented with different configurations of the test, but nothing seems to work. Only receiving an error about the spy not being triggered. Any suggestions on how to resolve this and make the mock & spy functional?
Update: Adding photos.component.ts file. This component utilizes ng-bootstrap carousel & pagination to display a slideshow featuring one image at a time that can be navigated through carousel arrows or pagination. The photo collection ID is extracted from a query string value in the URL.
import { Component, OnInit, ViewChild } from '@angular/core';
import { PhotosService } from '../services/photos.service';
import { IPhoto } from '../models/photo';
import { NgbCarousel, NgbCarouselConfig, NgbPaginationConfig } from '@ng-bootstrap/ng-bootstrap';
import { WindowObjectService } from '../services/windowobject.service';
@Component({
selector: 'app-photos',
templateUrl: './photos.component.html',
styleUrls: ['./photos.component.scss'],
providers: [NgbCarouselConfig, WindowObjectService]
})
export class PhotosComponent implements OnInit {
// reference to "photosCarousel"
@ViewChild('photosCarousel') photosCarousel: NgbCarousel;
private _photosService: any;
private _windowService: WindowObjectService;
errorMessage: string;
photos: IPhoto[] = new Array;
page = 1;
collectionSize: number;
tripReportId: string;
constructor(carouselConfig: NgbCarouselConfig, paginationConfig: NgbPaginationConfig, phototsService: PhotosService,
windowService: WindowObjectService) {
carouselConfig.showNavigationArrows = true;
carouselConfig.showNavigationIndicators = false;
carouselConfig.interval = 0; // Amount of time in milliseconds before next slide is shown.
carouselConfig.wrap = false;
paginationConfig.pageSize = 1;
paginationConfig.maxSize = 5;
paginationConfig.size = 'sm';
paginationConfig.boundaryLinks = false;
this._photosService = phototsService;
this._windowService = windowService;
}
ngOnInit() {
console.log('this._windowService.browserWindow.location.href', this._windowService.browserWindow.location.href);
this.tripReportId = this._windowService.browserWindow.location.href.split('?')[1].split('=')[1];
this._photosService.getPhotos(this.tripReportId).subscribe(
photos => {
this.photos = photos;
this.collectionSize = photos.length;
},
error => this.errorMessage = <any>error
);
this.collectionSize = this.photos.length;
}
pageChanged(pageNumber: number): void {
this.photosCarousel.select(pageNumber.toString());
}
public onSlide(slideData) {
this.page = slideData.current;
}
}