Reputation: 7653
mIve got the following unit tests that tests a Component I have written in Ionic 2. The unit tests gives an error from one of the Ionic libraries, I assume that I am not mocking it out properly or as such
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import {} from 'jasmine';
import { LocationSearchModal } from './LocationSearchModal';
import { LocationService } from '../../services/LocationService';
import { PouchDbService } from '../../services/common/PouchDbService';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TestBed } from '@angular/core/testing';
import { App, MenuController, NavController, Platform, Config, Keyboard, Form, IonicModule, ViewController, GestureController, NavParams } from 'ionic-angular';
import { ConfigMock } from '../../mocks';
import { TranslateModule } from 'ng2-translate';
import { LoadingController } from 'ionic-angular';
let fixture: ComponentFixture<LocationSearchModal> = null;
let instance: any = null;
describe('LocationSearchModal', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LocationSearchModal
],
providers: [
App, Platform, Form, Keyboard, MenuController, NavController, GestureController, LocationService, LoadingController,
{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },
{ provide: NavParams, useClass: class { NavParams = jasmine.createSpy("navParams"); } },
{ provide: PouchDbService, useClass: class { PouchDbService = jasmine.createSpy("pouchDbService"); } },
{provide: Config, useClass: ConfigMock}
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
TranslateModule.forRoot(),
],
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(LocationSearchModal);
instance = fixture.debugElement.componentInstance;
fixture.autoDetectChanges(true);
});
}));
afterEach(() => {
fixture.destroy();
});
it('loads', () => {
expect(fixture).not.toBeNull();
expect(instance).not.toBeNull();
})
})
This is the relevant excerpt which uses the ViewController from the component that is being tested.
this.locationService.getLocationById(this.selectedLocation)
.subscribe((location: any) => {
this.viewController.dismiss(location.doc)
});
The test fails and I get the following stack trace
Chrome 53.0.2785 (Linux 0.0.0)
TypeError: viewCtrl._setHeader is not a function
at new Header (webpack:///home/milinda/workspaces/eclipse/inspection/addedinspection/Inspection-Upgrade/~/ionic-angular/components/toolbar/toolbar.js:14:0 <- src/test.ts:11833:30)
at new Wrapper_Header (/IonicModule/Header/wrapper.ngfactory.js:7:18)
This is related to the ViewController
line which I have created a jasmine spy for
{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },
After having a look at the code base I found the _setHeader method in here
I also tried writing a custom provider but got the same error as well. Any idea on what is the correct method of testing the ViewController.
Additionally sometimes after resolving the ViewController issue an issue may occur from NavParams perhaps
Upvotes: 4
Views: 3500
Reputation: 223
add
{ provide: ViewController, useClass: class { ViewController = jasmine.createSpy("viewController"); } },
to provides
Upvotes: 0
Reputation: 1029
In case someone doesn't notice the comments on James Macmillan's answer:
@eesdil wrote:
From beenotung, there is built in mocks in ionic also: import {mockApp, mockConfig, mockPlatform, mockView} from "ionic-angular/util/mock-providers"; and use it like {provide: ViewController, useValue: mockView()}, – Sep 26 '17 at 9:40
This is the solution that worked for me.
Upvotes: 1
Reputation: 8726
let viewCtrlSpy = jasmine.createSpyObj('ViewController',
['data', 'readReady', 'writeReady', 'dismiss', '_setHeader', '_setNavbar', '_setIONContent', '_setIONContentRef']);
viewCtrlSpy
spy in providers array as follow:providers: [
.......
{
provide: ViewController,
useValue: viewCtrlSpy
}
..........
Spying is more efficient in this case than mocking.
Upvotes: 0
Reputation: 1075
Accepted answer did not work for ionic version 3.9.2, however following fixed the issue:
export class ViewControllerMock {
public readReady: any = {
emit(): void {
},
subscribe(): any {
}
};
public writeReady: any = {
emit(): void {
},
subscribe(): any {
}
};
public contentRef(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public didEnter(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public didLeave(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public onDidDismiss(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public onWillDismiss(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public willEnter(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public willLeave(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public willUnload(): any {
return new Promise(function (resolve: Function): void {
resolve();
});
}
public dismiss(): any {
return true;
}
public enableBack(): any {
return true;
}
public getContent(): any {
return true;
}
public hasNavbar(): any {
return true;
}
public index(): any {
return true;
}
public isFirst(): any {
return true;
}
public isLast(): any {
return true;
}
public pageRef(): any {
return true;
}
public setBackButtonText(): any {
return true;
}
public showBackButton(): any {
return true;
}
public _setHeader(): any {
return true;
}
public _setIONContent(): any {
return true;
}
public _setIONContentRef(): any {
return true;
}
public _setNavbar(): any {
return true;
}
public _setContent(): any {
return true;
}
public _setContentRef(): any {
return true;
}
public _setFooter(): any {
return true;
}
}
Ionic Info
cli packages:
@ionic/cli-plugin-proxy : 1.5.6
@ionic/cli-utils : 1.14.0
ionic (Ionic CLI) : 3.14.0
local packages:
@ionic/app-scripts : 3.1.0
Ionic Framework : ionic-angular 3.9.2
Upvotes: 1
Reputation: 176
Building on Marky Sparky's answer. As of ionic 3+:
export class ViewControllerMock{
readReady = {
subscribe(){
}
};
writeReady = {
subscribe(){
}
};
dismiss(){
console.log('View Controller Dismiss Called');
}
_setHeader(){
}
_setNavbar(){
}
_setIONContent(){
}
_setIONContentRef(){
}
}
Working on version:
Cordova CLI: 6.5.0
Ionic Framework Version: 3.0.1
Ionic CLI Version: 3.0.0-beta7
ios-deploy version: 1.9.1
ios-sim version: Not installed
OS: macOS Sierra
Node Version: v7.8.0
Xcode version: Xcode 8.3.2 Build version 8E2002
Upvotes: 16
Reputation: 61
I had the same issue when referring to ViewController in unit tests. I just solved it. Create a mock like this
class ViewControllerMock {
public _setHeader(): any {
return {}
};
public _setIONContent(): any {
return {}
};
public _setIONContentRef(): any {
return {}
};
}
Then add it to your providers in the call to TestBed.configureTestingModule like this:
TestBed.configureTestingModule({
declarations: [
...components,
OrdinalPipe,
IgnoreNulls
],
providers: [
NavController,
ChartsService, FundsService, Utils, BlogService
, Payment, PlanHelper, Storage, PalIdle, SimpleExpiry, ContentService, PlansService,
App, Platform, Form, Keyboard, MenuController,
{ provide: ModalController, useClass: ModalControllerMock },
{ provide: ViewController, useClass: ViewControllerMock },
{ provide: Config, useClass: ConfigMock }
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule,
],
})
This worked for me when I had the viewCtrl._setHeader is not a function error earlier today. Hope it helps.
Upvotes: 4