How to properly unit test an Angular2 http service with the MockBackend? - unit-testing

When running npm test I get this error:
src/client/app/shared/services/scientist.service.spec.ts(20,7): error TS2345: Argument of type 'Function' is not assignable to parameter of type '(done: () => void) => void'.
Type 'Function' provides no match for the signature '(done: () => void): void'
I'am using this angular2 seed: https://github.com/mgechev/angular2-seed and I changed the scientist name-list service to get the data from http, based on this blog: http://chariotsolutions.com/blog/post/testing-http-services-angular-2-jasmine/.
So I created my Scientist class with asScientist and asScientists methods that create instances from json.
scientist.service.ts:
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import {Scientist} from './scientist';
#Injectable()
export class ScientistService {
private url = 'http://path/to/scientists/';
constructor(private http:Http) {
}
get():Observable<Scientist[]> {
return this.http.get(this.url)
.map((res:Response) => {
return Scientist.asScientists(res.json());
});
}
}
scientist.service.spec.ts:
import {provide} from 'angular2/core';
import {beforeEachProviders, inject} from 'angular2/testing';
import {XHRBackend, ResponseOptions, Response} from 'angular2/http';
import {MockBackend, MockConnection} from 'angular2/src/http/backends/mock_backend';
import {Scientist} from './scientist';
import {ScientistService} from './scientist.service.ts';
export function main() {
describe('Scientist Service', () => {
beforeEachProviders(() => {
return [HTTP_PROVIDERS, provide(XHRBackend, {useClass: MockBackend}), ScientistService];
});
it('should get the list of scientists',
// ##### Line below causes the error #####
inject([XHRBackend, ScientistService], (mockBackend:MockBackend, scientistService:ScientistService) => {
mockBackend.connections.subscribe(
(connection:MockConnection) => {
// Haven't changed these yet since I want to make the test pass first
connection.mockRespond(new Response(
new ResponseOptions({
body: [
{
id: 26,
contentRendered: '<p><b>Hi there</b></p>',
contentMarkdown: '*Hi there*'
}]
}
)));
});
scientistService.get().subscribe((scientists:Scientist[]) => {
expect(scientists.length).toBe(1);
//expect(scientists[0].id).toBe(26);
//expect(data[0].contentMarkdown).toBe('*Hi there*');
},
(error:any) => {
// we can call a failure case here...
fail(error);
});
}));
});
}
It seems to be a syntax error but not a very obvious one, so any kind of help will be appreciated!

Maybe you need import all test methods from the angular2/testing module.
Like this:
import {it, beforeEachProviders, describe, expect, beforeEach, inject, injectAsync} from 'angular2/testing';
Because in your code I saw you just import "beforeEachProviders" and "inject".

Related

How to fix "Error: Cannot call setTimeout from within a sync test." when testing for a service?

I'm trying to unit test a very basic service that uses ngx-socket-io using Jasmine + Karma.
I keep getting Error: Cannot call setTimeout from within a sync test.
Here's my service:
import { Injectable } from '#angular/core';
import { Socket } from 'ngx-socket-io';
import { Message } from 'src/app/models/message';
#Injectable({
providedIn: 'root'
})
export class MessageService {
constructor(private socket: Socket) { };
newMessages(){
return this.socket.fromEvent<Message>('newMessage');
}
newMessage(message: String) {
this.socket.emit('messageSent', message);
}
}
This is my unit test:
import { TestBed } from '#angular/core/testing';
import { MessageService } from './message.service';
import SocketMock from 'socket.io-mock';
import { WrappedSocket } from 'ngx-socket-io/src/socket-io.service';
describe('MessageService', () => {
let service: MessageService;
let socket: WrappedSocket = new WrappedSocket(new SocketMock());
beforeEach(() => {
TestBed.configureTestingModule({
providers :[
MessageService,
{provide: WrappedSocket, useValue: socket}
]
});
service = TestBed.get(MessageService);
});
it('should be created', async () => {
expect(service).toBeTruthy();
});
});
Here is the full error output:
Error: Cannot call setTimeout from within a sync test.
at SyncTestZoneSpec.onScheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:366:1)
at ZoneDelegate../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:404:1)
at Zone../node_modules/zone.js/dist/zone.js.Zone.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:238:1)
at Zone../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:261:1)
at scheduleMacroTaskWithCurrentZone (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:1245:1)
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:2317:1
at proto.<computed> (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:1569:1)
at Request.create (http://localhost:9876/_karma_webpack_/webpack:/node_modules/engine.io-client/lib/transports/polling-xhr.js:268:1)
at new Request (http://localhost:9876/_karma_webpack_/webpack:/node_modules/engine.io-client/lib/transports/polling-xhr.js:165:1)
at XHR.request (http://localhost:9876/_karma_webpack_/webpack:/node_modules/engine.io-client/lib/transports/polling-xhr.js:92:1)
I just want to test that the service is created for now. What's going on, and how can I get the test to pass?
Try to use an async beforeEach. Probably setTimeout is called from there.
Check your test.ts file. Mainly the zone.js imports
Order should be
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
Reference - https://github.com/angular/zone.js/issues/1058

How to Unit Test an Angular 2.0 service that includes router-deprecated version?

It's kinda confusing as I cannot find anything related in docs of Angular 2.0 and Router-deprecated (yes I have to use it still in my project).
My service looks like this:
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { AuthHttp , JwtHelper } from 'angular2-jwt';
import { Router } from '#angular/router-deprecated';
import { UMS } from '../common/index';
#Injectable()
export class UserService {
constructor(
private router: Router,
private authHttp: AuthHttp,
private http: Http) {
this.router = router;
this.authHttp = authHttp;
this.http = http;
}
login(v) {
this.http.post(myUrl)
.subscribe(
data => this.loginSuccess(data),
err => this.loginFailure(err)
);
}
}
And my test like this (don't really care about the 'it' part for now):
import { Http } from '#angular/http';
import { AuthHttp, JwtHelper } from 'angular2-jwt';
import { Router } from '#angular/router-deprecated';
import {
beforeEach, beforeEachProviders,
describe, xdescribe,
expect, it, xit,
async, inject
} from '#angular/core/testing';
import { UserService } from './user.service';
describe('User Service', () => {
let service;
beforeEachProviders(() => [
Router,
AuthHttp,
Http,
UserService
]);
beforeEach(inject([
Router,
AuthHttp,
Http,
UserService], s => {
service = s;
}));
it('Should have a login method', () => {
expect(service.login()).toBeTruthy();
});
});
When I run the test I get this error: (btw I'm using angular-cli)
Error: Cannot resolve all parameters for 'Router'(RouteRegistry, Router, ?, Router). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Router' is decorated with Injectable.
Am I so wrong here?
After lots and lots of searching around I found out that I was injecting wrongly the providers.
Based on this GREAT article I manage to solve my problem by changing my service to this:
import { Http } from '#angular/http';
import { provide } from '#angular/core';
import { SpyLocation } from '#angular/common/testing';
import { AuthHttp, JwtHelper } from 'angular2-jwt';
import {
Router, RootRouter, RouteRegistry, ROUTER_PRIMARY_COMPONENT
} from '#angular/router-deprecated';
import {
beforeEach, beforeEachProviders,
describe, xdescribe,
expect, it, xit,
async, inject
} from '#angular/core/testing';
import { UserService } from './user.service';
describe('User Service', () => {
let service = UserService.prototype;
beforeEachProviders(() => [
RouteRegistry,
provide(Location, {useClass: SpyLocation}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: UserService}),
provide(Router, {useClass: RootRouter}),
AuthHttp,
Http,
UserService
]);
it('Should have a login method', () => {
expect(service.login).toBeTruthy();
});
});

Angular 2 RC4: Unit test component that has dependency injection a service that has its own

As Angular team is constantly upgrading/deprecating stuff in Angular 2 RC versions I encountered this problem.
I have a component that has a Dependency Injection (DI), which is actually a service (UserService in this case). This UserService of course has some DIs of its own. After updating to the latest RC4 of Angular 2 I realised that I cannot create similar tests any more.
So as the docs are not mentioning something relative here's my code (simplified for this question).
My component:
import { Component } from '#angular/core';
import { MdButton } from '#angular2-material/button';
import {
MdIcon,
MdIconRegistry
} from '#angular2-material/icon';
import { UserService } from '../../services/index';
#Component({
moduleId: module.id,
selector: 'logout-button',
templateUrl: 'logout-button.component.html',
styleUrls: ['logout-button.component.css'],
providers: [MdIconRegistry, UserService],
directives: [MdButton, MdIcon]
})
export class LogoutButtonComponent {
constructor(public userService: UserService) {}
/**
* Call UserService and logout() method
*/
logout() {
this.userService.logout();
}
}
Component's DI, UserService whic as you can see has some DIs (Router, AuthHttp & Http):
import { Injectable } from '#angular/core';
import {
Http,
Headers
} from '#angular/http';
import {
AuthHttp,
JwtHelper
} from 'angular2-jwt';
import { Router } from '#angular/router';
import { UMS } from '../common/index';
#Injectable()
export class UserService {
constructor(
private router: Router,
private authHttp: AuthHttp,
private http: Http) {
this.router = router;
this.authHttp = authHttp;
this.http = http;
}
/**
* Logs out user
*/
public logout() {
this.authHttp.get(UMS.url + UMS.apis.logout)
.subscribe(
data => this.logoutSuccess(),
err => this.logoutSuccess()
);
}
}
And here's the test for the component:
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import {
beforeEach,
beforeEachProviders,
describe,
expect,
it,
inject,
fakeAsync,
TestComponentBuilder
} from '#angular/core/testing';
import { AuthHttp } from 'angular2-jwt';
import { Router } from '#angular/router';
import { Http } from '#angular/http';
import { LogoutButtonComponent } from './logout-button.component';
import { UserService } from '../../services/index';
describe('Component: LogoutButtonComponent', () => {
beforeEachProviders(() => [
LogoutButtonComponent,
UserService
]);
it('should inject UserService', inject([LogoutButtonComponent],
(component: LogoutButtonComponent) => {
expect(component).toBeTruthy();
}));
});
Don't worry about the (it) for now.
As you can see I;m adding the related providers on the beforeEachProviders.
In this case I'm getting an error when I run the tests:
Error: No provider for Router! (LogoutButtonComponent -> UserService -> Router)
Which is expected let's say.
So in order to don't get those errors I'm adding the service's DIs in the providers also:
beforeEachProviders(() => [
LogoutButtonComponent,
Router,
AuthHttp,
Http,
UserService
]);
But now I'm, getting this error:
Error: Cannot resolve all parameters for 'Router'(?, ?, ?, ?, ?, ?, ?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Router' is decorated with Injectable.
I'm really trying to figure out what's happening so I found some related answers here but ALL are outdated and covers the old router-deprecated or angular2/router but both are deprecated and are not covering this case.
Would love some help on this and maybe some resources as I cannot find anything related to the latest version of Router: "#angular/router": "3.0.0-beta.2", and RC4.
Thanks
UPDATE!
I manage to bypass the two errors above and now I can access the component. Here's the description code:
describe('Component: LogoutButtonComponent', () => {
let component: LogoutButtonComponent;
let router: any = Router;
let authHttp: any = AuthHttp;
let http: any = Http;
let service: any = new UserService(router, authHttp, http);
beforeEachProviders(() => [
LogoutButtonComponent
]);
beforeEach(() => {
component = new LogoutButtonComponent(service);
});
it('should inject UserService', () => {
expect(component.userService).toBeTruthy();
});
it('should logout user', () => {
localStorage.setItem('token', 'FOO');
component.logout();
expect(localStorage.getItem('token')).toBeUndefined();
});
});
But it seems that even that the DI service is injected and accessible the DIs of the service are not. So now I get this error:
TypeError: this.authHttp.get is not a function
Any ideas?
It looks like you were experiencing a dependencies loop problem, because your UserSerivce also need inject AuthHttp, Http, etc... it really will be disturb once if you need test your component.
My way is just create a mock UserSerivce and return the expect mocked value through UserService.logout() method, because you don't have to know what really happened in UserService, all you need is just a return value:
let MockUserService = {
logout() {
// return some value you need
}
}
Then, in test suite:
import { provide } from '#angular/core'
beforeEachProviders(() => [
provide(UserService, {useClass: MockUserService})
])
... detail test code here
I hope this works for you.
And here is a post that helps me a lot:
https://developers.livechatinc.com/blog/testing-angular-2-apps-dependency-injection-and-components/
With RC4, some workarounds are needed to use http in a test. See also this issue (should be fixed in RC5):
https://github.com/angular/angular/issues/9294
Adding this to my unit-tests.html fixed it for me:
System.import('#angular/platform-browser/src/browser/browser_adapter').then(function(browser_adapter) {
browser_adapter.BrowserDomAdapter.makeCurrent();
})

Unit Test Failed: Cannot read property 'componentInstance' of undefined

Unit test works fine with angular2-seed project. The problem is it does not work with my project which resembles angular2-seed project.
Only difference between my project and angular2-seed is that I use gulpfile.ts without using tools directory. I defined all gulp tasks in a single file.
I need some help to give me some hint on this error.
I have this very simplified component
import {Component} from 'angular2/core';
import {RouterLink, Router} from 'angular2/router';
import {CORE_DIRECTIVES} from 'angular2/common';
#Component({
selector: 'cet-login',
moduleId: module.id,
templateUrl: 'apps/common/features/login/login.tpl.html',
directives: [RouterLink, CORE_DIRECTIVES]
})
export class LoginComponent {
constructor(
private router: Router
) {}
}
and I have very simple unit test
import {
TestComponentBuilder,
describe,
expect,
injectAsync,
it
} from 'angular2/testing';
import {Component} from 'angular2/core';
import {LoginComponent} from './login.cmp';
export function main(): void {
'use strict';
describe('Login component', () => {
it('should work',
injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb.createAsync(TestComponent)
.then(rootTC => {
rootTC.detectChanges();
expect(1).toBe(1);
});
}));
});
}
class Mock {}
#Component({
selector: 'test-cmp',
template: '<cet-login></cet-login>',
directives: [LoginComponent]
})
class TestComponent {}
I also have gulpfile.ts test section like the following;
gulp.task('test:buildjs', 'Compile typescript test files', ['test:buildcss'], () => {
var tsProject = tsProjectFn();
var result = gulp.src(PATH.src.ts)
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(inlineNg2Template({base: PATH.src.base}))
.pipe(tsc(tsProject));
return result.js
.pipe(sourcemaps.init())
.pipe(gulp.dest(PATH.dest.test));
});
gulp.task('test:unit', 'Start a karma server and run a unit test', (done: any) => {
return new karma.Server({
configFile: __dirname + '/karma.config.js',
singleRun: true
}).start(done);
});
When I run gulp test, which runs test:buildjs and test:unit, I have the following error
1) should work
Login component
Failed: Cannot read property 'componentInstance' of undefined
TypeError: Cannot read property 'componentInstance' of undefined
at new ComponentFixture_ (C:/repos/FAR/node_modules/angular2/src/testing/test_component_builder.js:38:51)
at C:/repos/FAR/node_modules/angular2/src/testing/test_component_builder.js:204:52
at Zone.run (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1217:24)
at zoneBoundFn (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1194:26)
at lib$es6$promise$$internal$$tryCatch (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:442:17)
at lib$es6$promise$$internal$$invokeCallback (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:454:18)
at lib$es6$promise$$internal$$publish (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:425:12)
at C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:97:10
at Zone.run (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1217:24)
at zoneBoundFn (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1194:26)
at lib$es6$promise$asap$$flush (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:236:10)
karma.config.js is exactly the same as angualr2-seed
test-main.js is the exactly the same as angualr2-seed
Any idea what I miss and what I am doing wrong?
I don't know which version of Angular2 (in my case beta7+) you use but in my unit tests, I need to register TEST_BROWSER_PLATFORM_PROVIDERS and TEST_BROWSER_APPLICATION_PROVIDERS to be able to use the TestComponentBuilder class:
import {
it,
describe,
expect,
beforeEach,
inject,
injectAsync,
TestComponentBuilder,
ComponentFixture,
setBaseTestProviders
} from 'angular2/testing';
import {
TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';
import {MyListComponent} from "./my-list";
import {MyService} from "../services/my-service";
describe('MyList Tests', () => {
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS);
let list:MyListComponent;
beforeEach(() => {
list = new MyListComponent();
});
it('should render list', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb.createAsync(MyListComponent).then((componentFixture: ComponentFixture) => {
const element = componentFixture.nativeElement;
componentFixture.detectChanges();
expect(element.querySelectorAll('li').length).toBe(3);
});
}));
});
See this plunkr: https://plnkr.co/edit/oVBPsH?p=preview.
Found the cause of this problem. The following line should be commented out for successful test.
import {enableProdMode} from 'angular2/core';
enableProdMode();

Trouble unit testing service with the Router injected in the constructor in Angular 2

I'm trying to test a service that has the application router injected in its constructor. Following Julie Ralph's suggestions presented in AngularConnect conf 2015 (and her repository: https://github.com/juliemr/ng2-test-seed),
I'm using Karma and Jasmine.
It follows the example service to be tested:
import { Router } from 'angular2/router';
export class ExampleService {
constructor(router : Router) {
this._router = router;
}
//...
}
Right now, I'm just asserting the truth. It follows the service test:
import { it, describe, expect, inject, beforeEachProviders, MockApplicationRef } from 'angular2/testing';
import { ROUTER_PROVIDERS } from 'angular2/router';
import { provide, ApplicationRef } from 'angular2/core';
import { ExampleService } from 'example-service.js';
describe('ExampleService', () => {
beforeEachProviders(() => [
ROUTER_PROVIDERS, ExampleService,
provide(ApplicationRef, { useClass: MockApplicationRef })
]);
it('should validate the truth', inject([ExampleService], (exService) => {
expect(true).toBeTruthy();
}));
});
when I run the tests ( > karma start karma.config.js ), I get a TypeError: Cannot read property 'length' of null
Looking at the router.js source code, it looks like I should bootstrap at least one component before injecting router. Is there
an easy way to inject the Router dependency in a test?
The Stacktrace:
ORIGINAL EXCEPTION: TypeError: Cannot read property 'length' of null
ORIGINAL STACKTRACE:
TypeError: Cannot read property 'length' of null
at routerPrimaryComponentFactory (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/router.js:2963:27)
at Injector._instantiate (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11920:19)
at Injector._instantiateProvider (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11859:21)
at Injector._new (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11849:19)
at InjectorDynamicStrategy.getObjByKeyId (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11733:42)
at Injector._getByKeyDefault (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12048:33)
at Injector._getByKey (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12002:21)
at Injector._getByDependency (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11990:21)
at Injector._instantiate (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11887:32)
at Injector._instantiateProvider (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11859:21)
at Injector._new (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11849:19)
at InjectorDynamicStrategy.getObjByKeyId (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11733:42)
at Injector._getByKeyDefault (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12048:33)
at Injector._getByKey (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12002:21)
at Injector._getByDependency (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11990:21)
at Injector._instantiate (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11887:32)
at Injector._instantiateProvider (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11859:21)
at Injector._new (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11849:19)
at InjectorDynamicStrategy.getObjByKeyId (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11733:42)
at Injector._getByKeyDefault (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12048:33)
at Injector._getByKey (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12002:21)
at Injector._getByDependency (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11990:21)
at Injector._instantiate (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11887:32)
at Injector._instantiateProvider (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11859:21)
at Injector._new (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11849:19)
at InjectorDynamicStrategy.getObjByKeyId (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11733:42)
at Injector._getByKeyDefault (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12048:33)
at Injector._getByKey (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:12002:21)
at Injector.get (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2.js:11804:19)
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2477:25
at Array.map (native)
at Array.map (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/es6-shim/es6-shim.js:1113:14)
at FunctionWithParamTokens.execute (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2476:33)
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2601:25
at Zone.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/angular2-polyfills.js:138:17)
at Zone.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2544:30)
at runInTestZone (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2588:23)
at Object. (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/angular2/bundles/testing.dev.js:2600:33)
at attemptAsync (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1819:24)
at QueueRunner.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1774:9)
at QueueRunner.execute (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1762:10)
at Spec.Env.queueRunnerFactory (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:627:35)
at Spec.execute (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:353:10)
at Object.fn (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2360:37)
at attemptAsync (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1819:24)
at QueueRunner.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1774:9)
at QueueRunner.execute (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1762:10)
at Env.queueRunnerFactory (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:627:35)
at Object.fn (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2345:13)
at attemptAsync (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1819:24)
at QueueRunner.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1774:9)
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1801:16
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1745:9
at queueRunnerFactory.onComplete (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2348:17)
at QueueRunner.clearStack (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:605:9)
at QueueRunner.run (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1784:12)
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1801:16
at C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1745:9
at complete (C:/Users/LSANTOS/Desktop/ng2-test-seed/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:365:9)
See also https://github.com/angular/angular/issues/6325
Problem solved, just need to provide the ROUTER_PRIMARY_COMPONENT.
import {ROUTER_PRIMARY_COMPONENT} from 'angular2/router';
class MockPrimaryComponent {
}
beforeEachProviders(() => [
ROUTER_PROVIDERS,
provide(ROUTER_PRIMARY_COMPONENT, {useClass: MockPrimaryComponent}),
ExampleService,
provide(ApplicationRef, { useClass: MockApplicationRef })
]);
I know this post is related to the old router, but I thought it might be useful to answer this. Using angular version rc.1 with the new router, I got unit tests with the router, including testing navigateByUrl, by using this test within angular as inspiration: https://github.com/angular/angular/blob/master/modules/%40angular/router/test/integration_spec.ts
saved me a lot of hastle
Here's a working example
import {setBaseTestProviders,beforeEachProviders,inject,it,describe,expect,beforeEach} from '#angular/core/testing'
import { Component,provide} from '#angular/core';
import {Routes,ROUTER_DIRECTIVES,Route} from "#angular/router";
import {ComponentResolver} from '#angular/core';
import {Router,RouterOutletMap,RouteSegment,RouterUrlSerializer,DefaultRouterUrlSerializer} from '#angular/router';
import {SpyLocation} from '#angular/common/testing';
import {Location} from '#angular/common';
import {ComponentFixture, TestComponentBuilder} from '#angular/compiler/testing';
import {TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from '#angular/platform-browser-dynamic/testing';
#Component({
selector: 'some-component',
template: `Blah!`,
directives: [ROUTER_DIRECTIVES]
})
export class SomeComponent {
}
#Component({
selector: 'another-component',
template: `Blah!`,
directives: [ROUTER_DIRECTIVES]
})
export class AnotherComponent {
}
#Component({
selector: 'root-cmp',
template: `<router-outlet></router-outlet>`,
directives: [ROUTER_DIRECTIVES]
})
#Routes([
new Route({path: '/some-path',component:SomeComponent}),
new Route({path: '/another-path',component:AnotherComponent})
])
export class RootCmp {
}
export const PROVIDERS_TESTING = [
provide(RouterUrlSerializer, {useClass: DefaultRouterUrlSerializer}),
RouterOutletMap,
provide(Location, {useClass: SpyLocation}),
provide(RouteSegment, {useFactory: (r) => r.routeTree.root, deps: [Router]}),
provide(Router,{
useFactory: (resolver, urlParser, outletMap, location) => new Router(
"RootComponent", RootCmp, resolver, urlParser, outletMap, location),
deps: [ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location]
}
),
]
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,[TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS,PROVIDERS_TESTING]);
it('some test',inject([Router, TestComponentBuilder, Location], (router:Router, tcb:TestComponentBuilder, location:Location) => {
return new Promise((resolve,reject)=>{
tcb.createAsync(RootCmp).then(fixture=>{
router.navigateByUrl('/some-path').then(()=>{
expect(location.path()).toEqual('/some-path');
resolve()
})
})
})
}))
it('another test',inject([Router, TestComponentBuilder, Location], (router:Router, tcb:TestComponentBuilder, location:Location) => {
return new Promise((resolve,reject)=>{
tcb.createAsync(RootCmp).then(fixture=>{
router.navigateByUrl('/another-path').then(()=>{
expect(location.path()).toEqual('/another-path');
resolve()
})
})
})
}))