Bruno Donnini Fachine
Bruno Donnini Fachine

Reputation: 31

Problems with NavController when unit testing an Ionic 2 app

I'm having trouble unit testing with NavController.

I'm stuck at this error:

Cannot resolve all parameters for 'NavController'(?, ?, ?, ?, ?, ?, ?, ?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'NavController' is decorated with Injectable.

I tried everything I found on the net, like using '@Inject', and nothing seems to work.

Here is the code:

Component

import {Page, MenuController, NavController} from 'ionic-angular';
import {SignupPage} from '../signup/signup';

@Page({
  templateUrl: 'build/pages/welcome/welcome.html'
})
export class WelcomePage {

  //  Variables
  constructor(private menu: MenuController, private nav: NavController) {
    this.menu.enable(false);
  }

  goToSignupPage() {
    this.nav.push(SignupPage)
  }
}

Unit test

import {beforeEachProviders, it, describe, expect, inject} from '@angular/core/testing';
import {MenuController, NavController} from 'ionic-angular';
import {WelcomePage} from './welcome';

describe('WelcomePage', () => {

  beforeEachProviders(() => [WelcomePage, MenuController, NavController]);

  it('should have the menu disabled on instatiation', inject([WelcomePage], (welcomePage) => {

    // Expectations
    expect(welcomePage.menu.isEnabled()).toBeFalsy();

  }));

});

Any idea whats wrong?

UPDATE:

Thanks for the replies, guys.

It really helped me to understand how to do it.

I didn't use sinon, but I was able to test if the push was called using the spyOn from Jasmine.

For that, I did a subtle change to the provide part:

beforeEachProviders(() => [WelcomePage, MenuController,
{ provide: NavController, useValue: {push: NavController.prototype.push} }]);

(Probably it would be nice to serve the NavController.prototype directly to have access to all the other properties.)

And then tested like this:

it('should go to signup page when calling goToSignupPage()', 
inject([WelcomePage], (welcomePage) => {

  // Spies
  spyOn(welcomePage.nav, 'push').and.stub();

  // Call
  welcomePage.goToSignupPage();

  // Expectations
  expect(welcomePage.nav.push).toHaveBeenCalledWith(SignupPage);

}));

Upvotes: 3

Views: 2075

Answers (2)

Edd
Edd

Reputation: 25

As GoldBones, the problem is that the NavController that has been imported is a class not a provider, so you need to define your own provider. The provide(...) syntax is deprecated, but the final code is pretty similar to the old syntax:

beforeEachProviders(() => [WelcomePage, MenuController, {provide: NavController, useValue: {} }]);

I've used an empty object above, but as WelcomePage uses the push method, you will need to stub this out with something like:

let stubNavController = {push: (page) => {}};
beforeEachProviders(() => [WelcomePage, MenuController, {provide: NavController, useValue: stubNavController }]);

Using a spying library like Sinon could be useful here if you want to test that the method was called.

Upvotes: 1

Goldbones
Goldbones

Reputation: 1457

Try this on your Unit Test class:

beforeEachProviders(() => [WelcomePage, MenuController, provide(NavController, { useValue: WelcomePage })]);

and then:

import {provide} from '@angular/core';

Upvotes: 3

Related Questions