Ionic version: (check one with "x")
[ ] 1.x
[X] 2.x
I'm submitting a ... (check one with "x")
[X] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/
Current behavior:
Using NavParams in a component throws an error when testing: Error: No provider for NavParams!
Expected behavior:
It would not throw the error :smile:
Steps to reproduce:
Inject navParams into component and run any old Karma test on the component.
Related code:
import {NavParams} from 'ionic-angular';
...
constructor (public navParams: NavParams)
Other information:
Ionic info: (run ionic info
from a terminal/cmd prompt and paste output below):
Cordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-rc.3
Ionic CLI Version: 2.1.12
Ionic App Lib Version: 2.1.7
Ionic App Scripts Version: 0.0.46
ios-deploy version: 1.9.0
ios-sim version: 5.0.8
OS: macOS Sierra
Node Version: v6.9.1
Xcode version: Xcode 8.1 Build version 8B62
Never mind, the issue was not injecting NavParams into providers.
The error is now this, so there is still an issue, and thus, I have reopened it:
Failed: Can't resolve all parameters for NavParams: (?).
Error: Can't resolve all parameters for NavParams: (?).
Can you provide a repo or plunker that reproduces your issue?
http://plnkr.co/edit/GJte2b?p=preview
Hi, I've the same issue. The problem occurs when I try to test a Page that receives something by NavParams. I think is not a Ionic issue, just we don't know how to pass that parameters throught NavParams when testing:
Here is the app logic:
this.navCtrl.setRoot(DeviceListPage, { devices: myDevices});
I receive that properties on my DeviceListPage:
constructor(public navCtrl: NavController, public navParams: NavParams) {
this.devices = navParams.get('devices') || [];
}
It works fine on the emulator, but when I try to test it I don't know where I've to tell to the test file that my Page receives those params to mock it.
That's the reason why i receive 'Can't resolve all parameters for NavParams error. How i can pass to the test file something like 'mocked params'?
This is my TestBed configuration for the device-list.spec.ts:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DeviceListPage ],
providers: [
App, DomController, Form, Keyboard, MenuController, NavController, Platform, NavParams
],
imports: [
IonicModule,
ReactiveFormsModule,
],
})
.compileComponents();
}));
Hi all, I've solved this creating a MockNavParams class in my test file:
class MockNavParams{
data = {
};
get(param){
return this.data[param];
}
}
Then, add it into the TestBed configuration:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ YourModule ],
providers: [
....
{provide: NavParams, useClass: MockNavParams},
],
imports: [
....
],
})
.compileComponents();
}));
Now, your test will work but if your component logic expect to do something with the param received you have two options:
Case: you expect to receive an user as param:
navParams.get('user')
Add the object that you want to receive in the data object inside the MockNavParams class:
class MockNavParams {
data = {
user: {
_id: "001",
name: "Mike",
}
};
get(param){
return this.data[param];
}
}
Keep the data object in the MockNavParams class empty.
In your class constructor, store the navParams.get('user') value in a local variable:
this.user = navParams.get('user');
Your app logic should look for that variable instead of navParams directly. So, now in your test case, you overwrite the variable:
beforeEach(() => {
fixture = TestBed.createComponent(MapPage);
component = fixture.debugElement.componentInstance;
fixture.detectChanges();
});
it('Should have one device if is received by navparams', () => {
component.user = {
_id: "001",
name: "Mike",
}
chai.expect(component.user._id).to.be.equal("001");
});
Since NavParams is something that happens when user navigate, you can test that behaviour using Protractor or other end to end test suite. Keep in mind that Jasmine is just for Unit test.
We can solve it by initialize it through the jasmine spy .
Below is the code which works for me.
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [FormsModule, HttpModule],
providers: [
{ provide: NavParams, useClass: class { NavParams = jasmine.createSpy("NavParams"); } ],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
});
Also we can provide custom values if we have any like below
{
provide: NavParams, useValue: {
data: {
"MYVALUE": "XYZ"
}
}
}
Works for me, thanks for your help! @snehasis
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Most helpful comment
Hi all, I've solved this creating a MockNavParams class in my test file:
Then, add it into the TestBed configuration:
Now, your test will work but if your component logic expect to do something with the param received you have two options:
Case: you expect to receive an user as param:
EASY WAY BUT NOT RECOMMENDED:
Add the object that you want to receive in the data object inside the MockNavParams class:
RECOMMENDED WAY
Keep the data object in the MockNavParams class empty.
In your class constructor, store the navParams.get('user') value in a local variable:
this.user = navParams.get('user');
Your app logic should look for that variable instead of navParams directly. So, now in your test case, you overwrite the variable:
Since NavParams is something that happens when user navigate, you can test that behaviour using Protractor or other end to end test suite. Keep in mind that Jasmine is just for Unit test.