Angular2 DI error in jasmine test - unit-testing

I'm writing some angular2 unit tests using jasmine and working on a unit test for a component. For some reason, when I try to instantiate the component using the TestBed class, I get a dependency injection error.
LoginComponent:
import { Component } from '#angular/core';
import { LoginService } from './login.service';
#Component({
selector: 'login',
template: require('./login.template.pug'),
styles: [require('./style.scss')],
providers: [LoginService]
})
export class LoginComponent {
public username: string;
public password: string;
constructor(private loginService: LoginService) {
}
public login(username, password) {
this.loginService.login(username, password)
.then((token: string) => {
})
}
}
LoginComponentTest:
import { TestBed, inject, async, ComponentFixture } from '#angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { LoginComponent } from './login.component';
import { LoginService } from './login.service';
import { BrowserModule } from '#angular/platform-browser';
describe('LoginComponent', () => {
class MockClass {
get(url): Promise<any> {
throw Error('not implemented');
};
}
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LoginComponent
],
providers: [
LoginComponent,
{ provide: LoginService, useClass: MockClass },
],
imports: [
FormsModule,
BrowserModule,
ReactiveFormsModule
]
})
}));
it('will let user login', async(() => {
TestBed.compileComponents()
.then(() => {
let fixture: ComponentFixture<LoginComponent> = TestBed.createComponent(LoginComponent);
});
}));
});
The line
let fixture: ComponentFixture<LoginComponent> = TestBed.createComponent(LoginComponent);
gives the following error:
Chrome 57.0.2987 (Mac OS X 10.12.3) LoginComponent will let user login
FAILED Error: DI Error
at NoProviderError.ZoneAwareError (webpack:///~/zone.js/dist/zone.js:958:0 <-
config/spec-bundle.js:75553:33)
I have the LoginComponent declared along with its own dependency, LoginService.
Any ideas about what's going on?

Okay, I figured it out, kind of. Apparently the issue has to do with the providers declaration in LoginComponent:
providers: [LoginService]
Once I moved that out of LoginComponent and into AppModule, things started working. Would be interested to know why the test doesn't work with it declared inside the component itself.

Related

App testing return "NullInjectorError: No provider for Location!"

Testing an app in Angular 7 with Karma, I can't remove the error in subj.
I have searched various places (mostly here) but either the solutions don't work or are not relevant to my case.
App.component.html:
<app-header></app-header>
<router-outlet></router-outlet>
Header.component.ts:
import { Component, OnInit, ViewChild, ElementRef, AfterViewInit, EventEmitter, Output } from '#angular/core';
import { Router } from '#angular/router';
import { Location } from '#angular/common';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.less']
})
export class HeaderComponent implements AfterViewInit, OnInit {
constructor(private location: Location, private router: Router) {
setInterval(() => {
this.now = new Date();
}, 1000);
}
...
onKeyDown(event: KeyboardEvent): void {
event.preventDefault();
if (event.which === this.KEY_ESCAPE){
if (this.router.url !== '/'){
this.location.back();
}
}
}
App.component.spec.ts:
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { RouterOutlet } from '#angular/router';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
HeaderComponent,
RouterOutlet
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
AppComponent should create the app
Error: StaticInjectorError(DynamicTestModule)[HeaderComponent -> Location]:
StaticInjectorError(Platform: core)[HeaderComponent -> Location]:
NullInjectorError: No provider for Location!
In my case, I was using the RouterTestingModule already which should not raise this error. I have imported Location from the wrong place so the error has appeared. 'Location' should be imported from here:
import {Location} from '#angular/common';
In your imports you should only import RouterTestingModule like this:
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes(
[
{path: 'add', component: DummyComponent, pathMatch: 'full'}
]
)
],
and then you can use Location like this:
it('Should navigate to / before + button click', () => {
const location: Location = TestBed.get(Location);
expect(location.path()).toBe('');
});
Just don't forget to import Location from #angular/common
Fixed it: all I needed to do was to import RouterModule.forRoot([]), which seems to be a common mistake as it fixes a lot of StaticInjectorError(DynamicTestModule) errors.
An alternative to NullInjectorError: No provider for Location! during the testing is to import RouterTestingModule.
ex. mycomponent.spec.ts:
import { RouterTestingModule } from '#angular/router/testing';
...
beforeEach(() => TestBed.configureTestingModule({
imports: [ RouterTestingModule ]
}));
Can u try to import > CommonModule
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule]
declarations: [
AppComponent,
HeaderComponent,
RouterOutlet
],
}).compileComponents();
}));

How to correctly test Angular4 application with Auth0 integration?

I am currently working on an Angular4 web application which uses Auth0 for authentication.
While the authentication works as expected the integration of Auth0 has broken (lets fail) the default tests (Karma unit tests) of my application.
My code looks as follows:
// app.component.ts
/*
* Angular 2 decorators and services
*/
import {
Component,
ViewEncapsulation
} from '#angular/core';
import { Auth } from './auth.service';
/*
* App Component
* Top Level Component
*/
#Component({
selector: 'app',
providers: [ Auth ],
encapsulation: ViewEncapsulation.None,
styleUrls: [
'./app.component.scss'
],
template: `
<div class="container-fluid">
<router-outlet></router-outlet>
</div>
`
})
export class AppComponent {
public angularclassLogo = 'assets/img/ExampleApp_smallLogo.png';
public name = 'ExampleApp';
public url = 'https://www.example.com/';
constructor(private auth: Auth) {
this.auth.handleAuth();
}
}
// auth.service.ts
import { Injectable } from '#angular/core';
import { tokenNotExpired } from 'angular2-jwt';
import { Router } from '#angular/router';
import { Http, Headers, RequestOptions, RequestMethod, Response } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/filter';
import Auth0Lock from 'auth0-lock';
import Auth0 from 'auth0-js';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { myConfig, postConfig, necessaryRoles } from './auth.config';
// Avoid name not found warnings
// declare var auth0: any;
#Injectable()
export class Auth {
public lock = new Auth0Lock(myConfig.clientID, myConfig.domain, myConfig.lock);
public userProfile: any;
public idToken: string;
public signUpIncomplete: boolean;
// Configure Auth0
private auth0 = new Auth0.WebAuth({
domain: myConfig.domain,
clientID: myConfig.clientID,
redirectUri: myConfig.redirectUri,
responseType: myConfig.responseType
});
// Create a stream of logged in status to communicate throughout app
private loggedIn: boolean;
private loggedIn$ = new BehaviorSubject<boolean>(this.loggedIn);
constructor(private router: Router, private http: Http) {
// Set userProfile attribute of already saved profile
this.userProfile = JSON.parse(localStorage.getItem('profile'));
}
...
}
// app.component.spec
import { NO_ERRORS_SCHEMA } from '#angular/core';
import {
async,
TestBed,
ComponentFixture
} from '#angular/core/testing';
import {
BaseRequestOptions,
HttpModule,
Http,
XHRBackend,
} from '#angular/http';
import { RouterTestingModule } from '#angular/router/testing';
import { MockBackend } from '#angular/http/testing';
// Load the implementations that should be tested
import { AppComponent } from './app.component';
import { AppState } from './app.service';
import { Auth } from './auth.service';
describe(`App`, () => {
let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
// async beforeEach
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AppComponent ],
imports: [RouterTestingModule, HttpModule],
schemas: [NO_ERRORS_SCHEMA],
providers: [
AppState,
Auth,
MockBackend,
BaseRequestOptions,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory:
(backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
]
})
.compileComponents(); // compile template and css
}));
// synchronous beforeEach
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
fixture.detectChanges(); // trigger initial data binding
});
it(`should be readly initialized`, () => {
expect(fixture).toBeDefined();
expect(comp).toBeDefined();
});
it(`should be ExampleApp`, () => {
expect(comp.url).toEqual('https://www.example.com/');
expect(comp.angularclassLogo).toEqual('assets/img/ExampleApp_smallLogo.png');
expect(comp.name).toEqual('ExampleApp');
});
});
The problem is that both App: should be readly initialized and App: should be MyApp fail with Cannot read property 'WebAuth' of undefined although WebAuth is defined in auth.service.ts which is then imported in app.component.spec.
Am I missing any import or declaration?
I finally solved the questions by myself.
I had to create a mock for the Auth service.
Further, I had to override the App component so that it uses that mock object instead of the real Auth service.
Therefore the solution looks as follows:
import { NO_ERRORS_SCHEMA } from '#angular/core';
import {
async,
TestBed,
ComponentFixture
} from '#angular/core/testing';
import {
BaseRequestOptions,
HttpModule,
Http,
XHRBackend,
} from '#angular/http';
import { RouterTestingModule } from '#angular/router/testing';
import { MockBackend } from '#angular/http/testing';
// Load the implementations that should be tested
import { AppComponent } from './app.component';
import { Auth } from './auth.service';
// Mock our Auth service
export class MockAuthService {
public handleAuth(): void {
return;
}
}
describe(`App`, () => {
let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
// async beforeEach
beforeEach(async(() => {
TestBed
.configureTestingModule({
declarations: [ AppComponent ],
imports: [RouterTestingModule, HttpModule],
schemas: [NO_ERRORS_SCHEMA],
providers: [
MockBackend,
BaseRequestOptions,
{
provide: Http,
deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
]
})
.overrideComponent(AppComponent, {
set: {
providers: [{ provide: Auth, useValue: new MockAuthService() }]
}
})
.compileComponents();
}));
// synchronous beforeEach
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
fixture.detectChanges(); // trigger initial data binding
});
it(`should be readly initialized`, () => {
expect(fixture).toBeDefined();
expect(comp).toBeDefined();
});
it(`should be ExampleApp`, () => {
expect(comp.url).toEqual('https://www.example.com/');
expect(comp.angularclassLogo).toEqual('assets/img/ExampleApp_smallLogo.png');
expect(comp.name).toEqual('ExampleApp');
});
});

Angular2 Unit testing Uncaught Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'

Having problems runnign my unit test code, getting this error message when trying to run the test:
Uncaught Error: Error in package:454:50:17 caused by: Invalid argument '[object
Object]' for pipe 'AsyncPipe'
at ViewWrappedError.ZoneAwareError
dashboard.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { Router, ActivatedRoute } from "#angular/router";
import { MockAF } from "../../providers/mockAf";
import { AF } from "../../providers/af";
import { DashboardComponent } from './dashboard.component';
import { SortOnLikePipe } from '../sort-on-like.pipe'
import { EditMessageModalComponent } from '../edit-message-modal/edit-
message-modal.component';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/observable/of';
import { MockModal } from '../edit-course-modal/mockEdit-course-
modal.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
let routerStub;
beforeEach(async(() => {
routerStub = {
navigate: jasmine.createSpy('navigate')
};
TestBed.configureTestingModule({
declarations: [
DashboardComponent,
SortOnLikePipe,
EditMessageModalComponent,
],
imports: [
FormsModule,
],
providers: [
{ provide: AF, useClass: MockAF },
{ provide: Router, useValue: routerStub },
{ provide: EditMessageModalComponent, useClass: MockModal },
{ provide: ActivatedRoute, useValue: { queryParams: Observable.from([{
course: "TDT4001" }]) }},
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
This is where i use pipes in my code
dashboard.component.html
<div *ngFor="let message of afService.messages | async |
sortOnLike:'votes':false">
.....
</div>
dashboard.component.ts
import { Component, OnInit, AfterViewChecked, ElementRef, ViewChild } from
'#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { AF } from '../../providers/af';
import { FirebaseListObservable, AngularFire } from 'angularfire2';
import { Bubble } from './bubble';
import { EditMessageModalComponent } from '../edit-message-modal/edit-
message-modal.component';
#Component({
moduleId: module.id.toString(),
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit, AfterViewChecked {
constructor(public afService: AF, private router: Router, private route:
ActivatedRoute) {
}
ngOnInit(): void {
var sub = this.route
.queryParams
.subscribe(params => {
// Defaults to error if no query param provided.
this.afService.setCourse(params['course'] || "error");
});
}
I have no clue on how to fix this problem, the funny thing is that it all worked. But when i got home to continue testing i got this error. All help is appreciated :)

"Can't resolve all parameters for MdDialogRef: (?)" Error when testing NG2 Material Dialog component

I have a login component as follows:
import { Component, OnInit } from '#angular/core';
import { MdDialogRef } from '#angular/material';
import { AuthService } from '../../core/services/auth.service';
#Component({
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginDialogComponent implements OnInit {
model: {
email: string,
password: string
};
error;
constructor(
private authService: AuthService,
private dialogRef: MdDialogRef<LoginDialogComponent>
) { }
ngOnInit() {
this.model = {
email: '',
password: ''
};
}
signin() {
this.error = null;
this.authService.login(this.model.email, this.model.password).subscribe(data => {
this.dialogRef.close(data);
}, err => {
this.error = err.json();
});
}
}
And I have a test spec for this component as follows:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { MdDialogRef, OverlayRef } from '#angular/material';
import { AuthService } from '../../core/services/auth.service';
import { LoginDialogComponent } from './login.component';
describe('Component: Login', () => {
let component: LoginDialogComponent;
let fixture: ComponentFixture<LoginDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
LoginDialogComponent
],
imports: [],
providers: [
AuthService,
MdDialogRef,
OverlayRef
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
I've tried a million different things, and no matter what I do, I get the following error:
Can't resolve all parameters for MdDialogRef: (?)
Here's the code for MdDialogRef, which only has 1 parameter, OverlayRef. What am I missing?
import { OverlayRef } from '../core';
import { Observable } from 'rxjs/Observable';
/**
* Reference to a dialog opened via the MdDialog service.
*/
export declare class MdDialogRef<T> {
private _overlayRef;
/** The instance of component opened into the dialog. */
componentInstance: T;
/** Subject for notifying the user that the dialog has finished closing. */
private _afterClosed;
constructor(_overlayRef: OverlayRef);
/**
* Close the dialog.
* #param dialogResult Optional result to return to the dialog opener.
*/
close(dialogResult?: any): void;
/** Gets an observable that is notified when the dialog is finished closing. */
afterClosed(): Observable<any>;
}
EDIT: taking a clue from #Ryan's comment, I tried removing the MdDialogRef provider entirely and got the following error:
Can't resolve all parameters for OverlayRef: (?, ?, ?)
This leads me to believe that the problem is actually w/MdDialogRef trying to resolve OverlayRef, not w/MdDialogRef itself.
WORKING EXAMPLE The code below is the actual working code, per Yurzui's suggestion.
/* tslint:disable:no-unused-variable */
import { NgModule } from '#angular/core';
import { async, TestBed } from '#angular/core/testing';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { MaterialModule, MdDialogModule, MdToolbarModule, MdDialog, MdDialogRef } from '#angular/material';
import { CoreModule } from '../../core/core.module';
import { LoginDialogComponent } from './login.component';
#NgModule({
declarations: [
LoginDialogComponent
],
entryComponents: [
LoginDialogComponent
],
exports: [
LoginDialogComponent
],
imports: [
CommonModule,
CoreModule,
FormsModule,
MaterialModule.forRoot(),
MdDialogModule.forRoot(),
MdToolbarModule.forRoot()
]
})
class LoginDialogSpecModule { }
describe('Component: Login Dialog', () => {
let component: LoginDialogComponent;
let dialog: MdDialog;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
LoginDialogSpecModule
]
});
});
beforeEach(() => {
dialog = TestBed.get(MdDialog);
let dialogRef = dialog.open(LoginDialogComponent);
component = dialogRef.componentInstance;
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
There is an issue ComponentFactoryResolver is not aware of components compiled via TestBed
According to this problem angular2 team offers workaround by creating real module with entryComponents property
https://github.com/angular/material2/blob/2.0.0-beta.1/src/lib/dialog/dialog.spec.ts#L387-L402
So your test could write like this:
import { MdDialog, MdDialogModule } from '#angular/material';
#NgModule({
declarations: [TestComponent],
entryComponents: [TestComponent],
exports: [TestComponent],
})
class TestModule { }
describe('Component: Login', () => {
let component: TestComponent;
let dialog: MdDialog;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [TestModule, MdDialogModule]
});
});
beforeEach(() => {
dialog = TestBed.get(MdDialog);
let dialogRef = dialog.open(TestComponent);
component = dialogRef.componentInstance;
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Plunker Example
I was getting the same error when running my code normally, i.e. I did not write a test case.
I found that the line provides: [ MdDialogRef ]in my main component was giving this exact same error, and everything worked without it.

"Error: No provider for router" while writing Karma-Jasmine unit test cases

We have done one angular2 project set up and inside that created one module (my-module) and inside that module created one component (my-new-component) using following cmd commands:
ng new angular2test
cd angular2test
ng g module my-module
ng generate component my-new-component
After creating the set up and all components, we ran ng test command from cmd inside angular2test folder.
The below file is our my-new-component.component.ts file:
import { Component, OnInit } from '#angular/core';
import { Router, Routes, RouterModule } from '#angular/router';
import { DummyService } from '../services/dummy.service';
#Component({
selector: 'app-my-new-component',
templateUrl: './my-new-component.component.html',
styleUrls: ['./my-new-component.component.css']
})
export class MyNewComponentComponent implements OnInit {
constructor(private router : Router, private dummyService:DummyService) { }
ngOnInit() {
}
redirect() : void{
//this.router.navigate(['/my-module/my-new-component-1'])
}
}
The below file is our my-new-component.component.spec.ts file:
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import {NgbModule} from '#ng-bootstrap/ng-bootstrap';
import { DummyService } from '../services/dummy.service';
import { MyNewComponentComponent } from './my-new-component.component';
describe('MyNewComponentComponent', () => {
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, NgbModule.forRoot(), DummyService],
declarations: [ MyNewComponentComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
We are getting the below cmd error while running the ng test command:
Chrome 54.0.2840 (Windows 7 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.593 secs / 2.007 secs)
Chrome 54.0.2840 (Windows 7 0.0.0) MyNewComponentComponent should create FAILED
Failed: Unexpected value 'DummyService' imported by the module 'DynamicTestModule'
Error: Unexpected value 'DummyService' imported by the module 'DynamicTestModule'
We have updated the component file and the spec file. Pleased find below the code snippet.
The below file is our my-new-component.component.ts file:
import { Component, OnInit } from '#angular/core';
import { Router, Routes, RouterModule } from '#angular/router';
import { DummyService } from '../services/dummy.service';
#Component({
selector: 'app-my-new-component',
templateUrl: './my-new-component.component.html',
styleUrls: ['./my-new-component.component.css']
})
export class MyNewComponentComponent implements OnInit {
constructor(private router : Router, private dummyService:DummyService, public fb: FormBuilder) {
super(fb);
}
ngOnInit() {
}
redirect() : void{
//this.router.navigate(['/my-module/my-new-component-1'])
}
}
The below file is our my-new-component.component.spec.ts file:
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { FormsModule, FormGroup, FormBuilder, Validators, ReactiveFormsModule} from '#angular/forms';
import { SplitPipe } from '../../common/pipes/string-split.pipe';
import { RouterTestingModule } from '#angular/router/testing';
import { DummyService } from '../services/dummy.service';
import { MyNewComponentComponent } from './my-new-component.component';
describe('MyNewComponentComponent', () => {
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, DummyService ,HttpModule, FormBuilder],
declarations: [ MyNewComponentComponent, SplitPipe]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
But while running the ng test command, we are getting the below error.
09 12 2016 09:13:48.987:WARN [karma]: No captured browser, open http://localhost:9876/
09 12 2016 09:13:49.008:INFO [karma]: Karma v1.2.0 server started at http://localhost:9876/
09 12 2016 09:13:49.010:INFO [launcher]: Launching browser Chrome with unlimited concurrency
09 12 2016 09:13:49.420:INFO [launcher]: Starting browser Chrome
09 12 2016 09:13:58.642:INFO [Chrome 54.0.2840 (Windows 7 0.0.0)]: Connected on socket /#QZ9LSSUVeK6KwNDlAAAA with id 46830907
Failed: Unexpected value 'FormBuilder' imported by the module 'DynamicTestModule'
Error: Unexpected value 'FormBuilder' imported by the module 'DynamicTestModule'
You need to import RouterTestingModule when setting up the test module.
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { MyNewComponentComponent } from './my-new-component.component';
describe('MyNewComponentComponent', () => {
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [ MyNewComponentComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Edit: example with mock DummyService
/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { MyNewComponentComponent } from './my-new-component.component';
// import the service
import { DummyService } from '../dummy.service';
// mock the service
class MockDummyService extends DummyService {
// mock everything used by the component
};
describe('MyNewComponentComponent', () => {
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [MyNewComponentComponent],
providers: [{
provide: DummyService,
useClass: MockDummyService
}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Add RouterTestingModule for configureTestingModule testCase
==> imports: [RouterTestingModule],
import {RouterTestingModule} from '#angular/router/testing';
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule], // <====
providers: [],
declarations: [],
});
});
I get the same kind of error and I want to share my solution to help others
The Error I get in Karma
error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ 'RouterModule', 'Router', 'Function', 'Function' ] })
NullInjectorError: R3InjectorError(DynamicTestModule)[RouterModule -> Router -> Function -> Function]:
NullInjectorError: No provider for Function!
inventory-view.component.ts
#Component({
selector: 'app-inventory-view',
templateUrl: './inventory-view.component.html',
styleUrls: ['./inventory-view.component.scss'],
animations: []
})
export class InventoryViewComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(
public router: Router, // <--- here was the problem
public activatedRoute: ActivatedRoute
) { }
In my test file
inventory-view.component.spec.ts
import { HttpClientModule } from '#angular/common/http';
import { waitForAsync, ComponentFixture, TestBed } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { ActivatedRoute, convertToParamMap, Router } from '#angular/router';
const ActivatedRouteSpy = {
snapshot: {
paramMap: convertToParamMap({
some: 'some',
else: 'else',
})
},
queryParamMap: of(
convertToParamMap({
some: 'some',
else: 'else',
})
)
};
const RouterSpy = jasmine.createSpyObj(
'Router',
['navigate']
);
describe('InventoryViewComponent', () => {
let component: InventoryViewComponent;
let fixture: ComponentFixture<InventoryViewComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
RouterTestingModule,
],
declarations: [ InventoryViewComponent ],
providers: [
{ provide: ActivatedRoute, useValue: ActivatedRouteSpy },
{ provide: Router, useValue: RouterSpy }
]
})
.compileComponents();
}));
beforeEach(waitForAsync(() => {
fixture = TestBed.createComponent(InventoryViewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});