问题
Angular 2.0.0 - Ionic 2 RC0 - Npm 3.10.8 - Node v4.5.0 - Karma 1.3.0 - Jasmine 2.5.2
previous question: Angular 2 -- Mocking - No Provider for HTTP
I'm now getting a new error while executing npm test
: null is not an object (evaluating '_this.events.length')
Which is triggered by this code: if(this.events.length > 0){
in EventsPage which means my response I set in events.spec.ts
is somehow not properly returned.
I'm new to mocking Angular2 so it's moest likely a rookie mistake.
(changed some code from previous question, so I'll repost them)
EventPage
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';
/*
Class for Evenementen Overzicht.
*/
@Component({
selector: 'events-component',
templateUrl: 'events.component.html',
providers: [ APICaller ]
})
/** -------------------------------------------------------------------------------------- */
export class EventsPage {
//list of all events
public events : Array<Event>;
//the event that has been clicked on the page
public selectedEvent : Event;
//boolean to show 'no events' error message
public noEvents:boolean;
/** -------------------------------------------------------------------------------------- */
constructor(public navCtrl : NavController, public apiCaller:APICaller, public loadingCtrl : LoadingController) {
//retrieve all events --> async method, can't use this.events yet.
this.getEvents();
}
/** -------------------------------------------------------------------------------------- */
/**Get Events - Sets the 'events' variable to all events found by the API. */
getEvents(){
//setup a loadingscreen (broke testing so removed for now)
// let loading = this.loadingCtrl.create({
// content: "Loading..."
// });
//present the loadingscreen
// loading.present();
//reset the noEvents boolean.
this.noEvents = true;
//call the api and get all events
this.apiCaller.getEvents()
.subscribe(response => {
console.log("RESP:"+response);
//response is list of events
this.events = response;
//if the event is not empty, set noEvents to false.
if(this.events.length > 0){ //<----------------------------FAILS HERE
this.noEvents = false;
}
//close the loading message.
// loading.dismiss();
});
}
}
EventPage -- Spec
import { TestBed, inject, tick, fakeAsync } from '@angular/core/testing';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions} from '@angular/http';
import { FormsModule } from '@angular/forms';
import { NavController, LoadingController } from 'ionic-angular';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { mockNavController, mockApp } 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();
let loadingCtrl : LoadingController = new LoadingController(this);
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [EventsPage],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{provide: APICaller, useValue: mockAPICaller},
{provide: NavController, useValue: mockNavController },
{provide: LoadingController, useValue: loadingCtrl},
],
imports: [FormsModule]
});
TestBed.overrideComponent(EventsPage,{
set: {
providers: [
{provide: APICaller, useValue: mockAPICaller}
]
}
});
});
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'
}]`));
eventsPage.getEvents();
fixture.detectChanges();
console.log(eventsPage.events);
});
});
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;
}
}
回答1:
You should set the response on the mock before creating the component. You are calling getEvents
in the component constructor, and the mock hasn't set the data yet.
it('should return all events', () => {
mockAPICaller.setResponse(JSON.stringify(`[{
id: 4,
title: 'Weekend',
eventdate: '24/09/2016',
kind: 'closed',
startingtime: '18:00',
endtime: '21:00',
description: 'Go Home'
}]`));
let fixture = TestBed.createComponent(EventsPage);
let eventsPage = fixture.debugElement.componentInstance;
fixture.detectChanges();
eventsPage.getEvents();
fixture.detectChanges();
console.log(eventsPage.events);
});
来源:https://stackoverflow.com/questions/39893172/angular-2-mocking-response-is-null