Reputation: 2826
I've created a component which I'm trying to test using Karma and Jasmine. Everything works fine for other components that doesn't have services injected by DI. But this one throws an error without any message and just with a stack.
Here's the component:
import {Component} from 'angular2/core';
import {Application} from './application';
import {ApplicationsService} from './applications.service';
@Component({
selector: 'applications-selector',
styles: [require('./applications-selector.scss')],
template: require('./applications-selector.html'),
providers: [ApplicationsService]
})
export class ApplicationsSelectorComponent {
applications: Application[];
selectedWeek: number;
selectedApplications: Application[];
selectedCycle: string;
constructor(private _applicationsService: ApplicationsService) {
this.getApplications();
}
getApplications() {
this._applicationsService.getApplications().then(applications => this.applications = applications);
}
}
And here's the unit test for this component:
import {
it,
inject,
injectAsync,
describe,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import {provide} from 'angular2/core';
import {ApplicationsSelectorComponent} from './applications-selector.component';
import {ApplicationsService} from './applications.service';
class ApplicationsServiceMock {
getApplications() {
return ['ABC', 'XYZ'];
}
}
describe('ApplicationsSelectorComponent', () => {
beforeEachProviders(() => [
provide(ApplicationsService, { useClass: ApplicationsServiceMock }),
ApplicationsSelectorComponent
]);
it('should have empty default values', inject([ApplicationsSelectorComponent], (component) => {
expect(component.selectedWeek).toBe(undefined);
expect(component.selectedApplications).toBe(undefined);
expect(component.selectedCycle).toBe(undefined);
}));
});
And here's an error that I get as soon as I run this test:
ApplicationsSelectorComponent
× should have empty default values
PhantomJS 2.1.1 (Windows 7 0.0.0)
_instantiateProvider@d:/git/gatekeeper/web/spec-bundle.js:11896:38 <- webpack:///angular2/src/core/di/injector.ts:770:31
_new@d:/git/gatekeeper/web/spec-bundle.js:11885:42 <- webpack:///angular2/src/core/di/injector.ts:759:37
getObjByKeyId@d:/git/gatekeeper/web/spec-bundle.js:11495:55 <- webpack:///angular2/src/core/di/injector.ts:356:44
_getByKeyDefault@d:/git/gatekeeper/web/spec-bundle.js:12083:51 <- webpack:///angular2/src/core/di/injector.ts:977:44
_getByKey@d:/git/gatekeeper/web/spec-bundle.js:12029:42 <- webpack:///angular2/src/core/di/injector.ts:914:35
get@d:/git/gatekeeper/web/spec-bundle.js:11704:31 <- webpack:///angular2/src/core/di/injector.ts:577:26
d:/git/gatekeeper/web/spec-bundle.js:9128:74 <- webpack:///angular2/src/testing/test_injector.ts:151:52
map@[native code]
apply@[native code]
call@[native code]
call@[native code]
map@d:/git/gatekeeper/web/spec-bundle.js:2377:21 <- webpack:///~/es6-shim/es6-shim.js:1113:0
execute@d:/git/gatekeeper/web/spec-bundle.js:9128:39 <- webpack:///angular2/src/testing/test_injector.ts:151:34
execute@d:/git/gatekeeper/web/spec-bundle.js:9017:27 <- webpack:///angular2/src/testing/test_injector.ts:42:22
d:/git/gatekeeper/web/spec-bundle.js:8393:58 <- webpack:///angular2/src/testing/testing.ts:137:49
_instantiate@d:/git/gatekeeper/web/spec-bundle.js:12003:87 <- webpack:///angular2/src/core/di/injector.ts:883:67
An error occurs on inject([ApplicationsSelectorComponent] statement. As soon as I remove it, there's no error, but I need this component to perform tests on it.
What can cause this injection error?
Upvotes: 0
Views: 1379
Reputation: 2826
Finally, it turned out that all the setup was correct but I was just returning incorrect value from ApplicationsServiceMock
. Base service is returning Promise
and I was returnig just an array of value in my mock. That's why when this line this._applicationsService.getApplications().then(applications => this.applications = applications);
was executed from constructor
no then method on array could be found. And tests were failing.
As soon as I've fixed return value from my mock everything works fine.
Here's working code for my test:
import {
it,
beforeEach,
injectAsync,
describe,
TestComponentBuilder
} from 'angular2/testing';
import {Component, provide} from 'angular2/core';
import {Application} from './application';
import {ApplicationsService} from './applications.service';
import {ApplicationsSelectorComponent} from './applications-selector.component';
class ApplicationsServiceMock {
getApplications() {
return Promise.resolve([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]);
}
}
describe('ApplicationsSelectorComponent', () => {
beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
.createAsync(ApplicationsSelectorComponent)
.then((componentFixture: any) => {
this.component = componentFixture;
});
}));
it('should have empty default values', () => {
expect(this.component.componentInstance._applicationsService.getApplications().then(apps => { apps.toEqual([{ 'id': 1, 'name': 'TST', 'project': 'PRJ' }]) }));
});
});
Upvotes: 0
Reputation: 6802
It seems like you're trying to inject components the same way as providers which will not work.
Here is complete minimal example of mocking providers for specific component:
class ApplicationsService {
getApplications() {
return ['ABC'];
}
}
class ApplicationsServiceMock {
getApplications() {
return ['ABC', 'XYZ'];
}
}
@Component({
selector: 'apps',
template: '',
providers: [ApplicationsService]
})
class ApplicationsSelectorComponent {
constructor(private apps: ApplicationsService) {}
}
describe('App', () => {
describe('ApplicationsSelectorComponent', () => {
beforeEach(injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.overrideProviders(ApplicationsSelectorComponent, [provide(ApplicationsService, { useClass: ApplicationsServiceMock })])
.createAsync(ApplicationsSelectorComponent)
.then((componentFixture: any) => {
this.component = componentFixture;
});
}));
it('should have empty default values', () => {
expect(this.component.componentInstance.apps.getApplications()).toEqual(['ABC', 'XYZ'])
});
});
});
Upvotes: 2