Angular 2.0.0 - Ionic 2 RC0 - Npm 3.10.8 - Node v4.5.0 - Karma 1.3.0 - Jasmine 2.5.2
I am trying to test my application using Karma and Jasmine. Now I have come to the point that I have followed some tutorials (I am new to these testing platforms). But unfortunately, I get an error when trying to run my test.
I am trying to test EventsPagethat has no import Http, but it calls mine APICaller.service, which uses Http. So I created MockAPICaller, but it seems to still want it Http(perhaps because it is in the constructor APICaller, but I don’t know how to fix it).
Therefore, I suspect that the problem is within MockAPICaller, but I do not know for sure.
I will post MockAPICaller.service, APICaller.service, EventsPageand my events.spec.ts. (in that order so you can skip if you need / want.
Mockapicaller
import { SpyObject } from './helper';
import { APICaller } from '../apicaller.service';
import Spy = jasmine.Spy;
export class MockAPICaller extends SpyObject {
getEventsSpy: Spy;
searchEventSpy:Spy;
getParticipantSpy:Spy;
getEventParticipantsSpy:Spy;
searchEventParticipantSpy:Spy;
addNewCommentSpy:Spy;
updateCommentSpy:Spy;
deleteCommentSpy:Spy;
getUsernameSpy:Spy;
presentSuccessMessageSpy:Spy;
fakeResponse:any;
constructor(){
super( APICaller );
this.fakeResponse = null;
this.getEventsSpy = this.spy('getEvents').andReturn(this);
this.searchEventSpy = this.spy('searchEvent').andReturn(this);
this.getParticipantSpy = this.spy('getParticipant').andReturn(this);
this.getEventParticipantsSpy = this.spy('getEventParticipant').andReturn(this);
this.searchEventParticipantSpy = this.spy('searchEventParticipant').andReturn(this);
this.addNewCommentSpy = this.spy('addNewComment').andReturn(this);
this.updateCommentSpy = this.spy('updateComment').andReturn(this);
this.deleteCommentSpy = this.spy('deleteComment').andReturn(this);
this.getUsernameSpy = this.spy('getUsername').andReturn(this);
this.presentSuccessMessageSpy = this.spy('presentSuccessMessage').andReturn(this);
}
subscribe(callback: any){
callback(this.fakeResponse);
}
setResponse(json:any):void{
this.fakeResponse = json;
}
}
Apicaller
import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { ToastController } from 'ionic-angular';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import { Event } from '../models/event.model';
import { Participant } from '../models/participant.model';
import { Comment } from '../models/comment.model';
@Injectable()
export class APICaller {
http : Http;
baseUrl : string = "http://some.correct.url:8080/myAPI";
constructor(public httpService: Http, public toastCtrl:ToastController) {
this.http = httpService;
}
getEvents() : Observable<Array<Event>> {
return this.http
.get(`${ this.baseUrl }/events`)
.map(response => {
return response.json();
});
}
searchEvent(searchTerm : string) : Observable<Array<Event>> {
return this.http
.get(`${ this.baseUrl }/events/search/${ searchTerm }`)
.map(response => {
return response.json();
});
}
getParticipant(participantId : number) : Observable<Participant>{
return this.http
.get(`${ this.baseUrl }/participants/${ participantId }`)
.map(response => {
return response.json();
});
}
getEventParticipants(eventId:number) : Observable<Array<Participant>> {
return this.http
.get(`${ this.baseUrl }/events/${ eventId }/participants`)
.map(response => {
return response.json();
});
}
searchEventParticipant(eventId : number, searchTerm : string) : Observable<Array<Participant>> {
return this.http
.get(`${ this.baseUrl }/events/${ eventId }/participants/search/${ searchTerm }`)
.map(response => {
return response.json();
});
}
addNewComment(participantId : number, content : string) : Observable<Comment> {
return this.http
.post(`${ this.baseUrl }/participants/${ participantId }/addComment`
,{
user: this.getUsername("apikey"),
content: content
}).map((response) => {
this.presentSuccessMessage("Comment added");
return (response.json());
});
}
updateComment(participantId : number, commentId : number, content : string) : Observable<Comment> {
return this.http
.put(`${ this.baseUrl }/participants/${ participantId }/updateComment/${ commentId }`,{
id: commentId,
content: content
}).map(response => {
this.presentSuccessMessage("Comment updated");
return response.json();
});
}
deleteComment(participantId : number, commentId : number) : Observable<Comment> {
return this.http
.delete(`${ this.baseUrl }/participants/${ participantId }/deleteComment/${ commentId }`)
.map(response => {
this.presentSuccessMessage("Comment deleted");
return response.json();
});
}
presentSuccessMessage(messageContent : string) {
let message = this.toastCtrl
.create({
message: messageContent,
duration: 3000
});
message.present();
}
getUsername(someRandomKey : string) : string {
return "developer";
}
}
EventsPage
import { Component } from '@angular/core';
import { NavController, Loading, LoadingController } from 'ionic-angular';
import { APICaller } from '../../services/apicaller.service';
import { EventDetailComponent } from '../event-detail/event-detail.component';
import { Event } from '../../models/event.model';
@Component({
selector: 'events-component',
templateUrl: 'events.component.html',
providers: [ APICaller ]
})
export class EventsPage {
public events : Array<Event>;
public selectedEvent : Event;
public noEvents:boolean;
constructor(public navCtrl : NavController, public apiCaller:APICaller, public loadingCtrl : LoadingController) {
this.getEvents();
}
getEvents(){
let loading = this.loadingCtrl.create({
content: "Loading..."
});
loading.present();
this.noEvents = true;
this.apiCaller.getEvents()
.subscribe(response => {
this.events = response;
if(this.events.length > 0){
this.noEvents = false;
}
loading.dismiss();
});
}
selectEvent(event: any, eventObj){
this.selectedEvent = eventObj;
}
searchEvents(ev){
this.noEvents = true;
if(ev.target.value != ''){
this.apiCaller.searchEvent(ev.target.value)
.subscribe(response => {
this.events = response;
if(this.events.length > 0){
this.noEvents = false;
}
});
}else{
this.getEvents();
}
}
cancelSearch(ev){
ev.target.value = "";
this.noEvents = false;
}
doRefresh(refresher) {
this.getEvents();
setTimeout(() => {
refresher.complete();
}, 1000);
}
goToEventDetail(eventOb: any, eventParam){
this.navCtrl.push(EventDetailComponent
, {
event: eventParam
});
}
}
events.spec.ts
import { TestBed, inject, tick, fakeAsync } from '@angular/core/testing';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions} from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { FormsModule } from '@angular/forms';
import { NavController, LoadingController } from 'ionic-angular';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { mockNavController } from 'ionic-angular/util/mock-providers';
import { EventsPage } from './events.component';
import { MockAPICaller } from '../../services/mocks/apicaller.service';
import { APICaller } from '../../services/apicaller.service';
describe('Component: EventsComponent', () => {
let mockAPICaller : MockAPICaller = new MockAPICaller();
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA],//for usage of Ionic2
providers: [
{provide: NavController, useValue: mockNavController },
{provide: LoadingController, useValue: LoadingController},
{provide: APICaller, useValue: mockAPICaller}
],
imports: [FormsModule]
});
});
it('should return all events', ()=>{
let fixture = TestBed.createComponent(EventsPage);
let eventsPage = fixture.debugElement.componentInstance;
fixture.detectChanges();
mockAPICaller.setResponse(JSON.stringify(`{
id: 4,
title: 'Weekend',
eventdate: '24/09/2016',
kind: 'closed',
startingtime: '18:00',
endtime: '21:00',
description: 'Go home'
}`));
let results = eventsPage.getEvents();
expect(results.length).toBe(1);
expect(results[0].id).toBe(4);
});
});