How to correctly test Angular4 application with Auth0 integration? - unit-testing

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');
});
});

Related

jasmine test cases dependency in angular 2 with stub

Here I'm new to angular 2 test cases with jasmine + karma and I'm following this testing guide I tried to write test case but unable to write correctly and getting routing error as test cases are going to server while running, although it should not.
There is a question similar to this but didn't help me to solve the problem. Please guide me.
Here is my component
import { Component, OnInit, ViewChild } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { Checklist } from './checklist';
import { Job } from '../+job/job';
import { OriginalService } from './original.service';
import { UserService } from '../core/user/user.service';
import { ModalDirective } from 'ng2-bootstrap/ng2-bootstrap';
#Component({
selector: 'app-selector',
templateUrl: './original.component.html',
providers: [OriginalService]
})
export class OriginalComponent implements OnInit {
items = []
job: Job;
checklist: Checklist;
user: any;
shopId: any;
jobId: any;
constructor ( private orgService: OriginalService, private route: ActivatedRoute, private router: Router, userService: UserService) {
this.user = userService.user();
}
ngOnInit() {
this.route.params
.map(params => params['job_id'])
.subscribe(
job_id => this.jobId = job_id
);
this.getChecklist();
this.getJob();
}
getChecklist() {
this.orgService.getChecklists({
jobId: this.jobId
})
.then(checklist=> {
this.gotJobdata = true;
this.checklist = checklist.response})
.catch(error => this.error = error);
}
getJob(){
this.orgService.getJob({
jobId: this.jobId
})
.then(job => this.job = job.response)
.catch(error => this.error = error);
}
}
Here's my service
import { Injectable, ViewChildren } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { environment } from '../../environments/environment'
import 'rxjs/add/operator/toPromise';
import { Checklist } from './checklist';
import { Job } from '../+job/job';
import { UserService } from '../core/user/user.service';
#Injectable()
export class OriginalService {
shopId: any;
constructor(private http: Http, private userService: UserService ) {
this.shopId = userService.shopId();
}
getChecklists(svc): Promise<Checklist> {
return this.http.get(environment.apiUrl + this.shopId + '/jobs/' + svc.jobId + '/checklists_path/' + 'check_item.json')
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
getJob(svc): Promise<Job> {
return this.http.get(return environment.apiUrl + this.shopId + '/jobs/' + svc.jobId + '.json')
.toPromise()
.then(response => response.json())
.catch(this.handleError);
}
}
Here's the spec what I've tried:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { SharedModule } from '../shared/shared.module';
import { ModalModule } from 'ng2-bootstrap/ng2-bootstrap';
import { HttpModule } from '#angular/http';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { ComponentLoaderFactory } from 'ng2-bootstrap/component-loader';
import { Subject } from 'rxjs/Subject';
import { UserService } from '../core/user/user.service';
import { OriginalService } from './original.service';
import { OriginalComponent } from './original.component';
describe('OriginalComponent', () => {
let component: OriginalComponent;
let fixture: ComponentFixture<OriginalComponent>;
let params: Subject<Params>;
let userService, orgService;
let userServiceStub = {
isLoggedIn: true,
user: { name: 'Test User'}
};
beforeEach(async(() => {
params = new Subject<Params>();
TestBed.configureTestingModule({
imports: [ ModalModule.forRoot(), SharedModule, HttpModule ],
declarations: [ OriginalComponent ],
providers: [ OriginalService, UserService, ComponentLoaderFactory,
{ provide: Router, useValue: userServiceStub }, {provide: ActivatedRoute, useValue: { params: params }} ]
})
.compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(ChecklistComponent);
component = fixture.componentInstance;
fixture.detectChanges();
it('should create', () => {
expect(component).toBeTruthy();
});
});
Please correct me how to properly use routing in test cases or stubs where I'm doing wrong.

unit testing a component which is injected by a service which is using angular2-jwt AuthHttp call instead of http call

I have been using HTTP to call API to do my stuff, later introduced angular2-jwt to intercept the http calls and pass the jwt tockens. Unit testing was working fine until AuthHttp was used. I have created 'mockuserdata' model to return the mock values
Every unit test cases where failing until I added the providers for http and AuthHttp as follows
{provide: Http, useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) =>
{ return new Http(backendInstance, defaultOptions);},
deps: [MockBackend, BaseRequestOptions] },
{ provide: AuthHttp, useExisting: Http, deps: [Http] }
After introducing above providers 'should instantiate UsersComponent' got passed but 'It checks loadUserList() is binding datasource' ís failing
/* User Operations Service*/
import {Headers,RequestOptionsArgs,Response,URLSearchParams, RequestMethod,RequestOptions }from '#angular/http';
import { Injectable, Optional }from '#angular/core';
import { Observable}from 'rxjs/Observable';
import * as models from '../models';
import { AuthHttp }from 'angular2-jwt';
import 'rxjs/Rx';
# Injectable()
export class UserOperationsApi {
protected basePath = '/api';
public defaultHeaders: Headers = new Headers();
constructor(protected http: AuthHttp, # Optional()basePath: string) {
if (basePath) {
this.basePath = basePath;
}
}
/**
* Returns all users
* Returns list of all users
*/
public getAllUsers(extraHttpRequestParams ? : any): Observable < Array < models.User >> {
const path = this.basePath + '/users';
let queryParameters = new URLSearchParams();
let headerParams = this.defaultHeaders;
let requestOptions: RequestOptionsArgs = {
method: 'GET',
headers: headerParams,
search: queryParameters
};
return this.http.request(path, requestOptions)
.map((response: Response) => {
if (response.status === 204) {
return undefined;
} else {
return response.json();
}
});
}
}
/* User List Component*/
import {Component,OnInit}from '#angular/core';
import {Router } from '#angular/router';
import {UserOperationsApi }from '../services';
import {DialogService }from '../services';
import { Subscription }from 'rxjs';
# Component({
selector: 'my-app',
templateUrl: './list-users.component.html',
providers: [UserOperationsApi]
})
export class UsersComponent implements OnInit {
public userData: any;
constructor(private api: UserOperationsApi, private router: Router) {
this.loadUserList();
}
// loading user list
loadUserList() {
// To get data from api
this.busy = this.api.getAllUsers()
.subscribe(
data => this.handleConfiguredUsers(data),
error => {
throw ({
message: 'Error occured! while retreiving data from server.'
});
});
}
// users list to be loaded
handleConfiguredUsers(data) {
this.userData = data;
}
}
** * User component unit testing ** ** **
import {async,TestBed,inject}from '#angular/core/testing';
import {Response,ResponseOptions, XHRBackend } from '#angular/http';
import { MockBackend, MockConnection}from '#angular/http/testing';
import { HttpModule}from '#angular/http';
import { Router, ActivatedRoute}from '#angular/router';
import { MockRouter}from '../mock/router.mock';
import { usersData}from '../data/mockData/users';
import { UsersComponent}from './list-users.component';
describe('list-users.component.ts', () => {
beforeEach(() => {
TestBed.configureTestingModule(
{
declarations: [UsersComponent],
imports: [HttpModule, DevExtremeModule],
providers: [MockBackend, BaseRequestOptions,
{ provide: XHRBackend, useClass: MockBackend },
{ provide: Router, useClass: MockRouter },
{ provide: ActivatedRoute, useClass: MockRouter },
{
provide: Http, useFactory: (backendInstance: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backendInstance, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
},
{ provide: AuthHttp, useExisting: Http, deps: [Http] }
]
});
});
it('should instantiate UsersComponent', () => {
const fixture = TestBed.createComponent(UsersComponent);
let compInstance: UsersComponent = fixture.componentInstance;
expect(compInstance instanceof UsersComponent).toBe(true, 'should create UsersComponent');
});
it('It checks loadUserList() is binding datasource',
async(inject([XHRBackend],
(mockBackend: MockBackend) => {
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(new Response(
new ResponseOptions({
body: usersData
})));
});
const fixture = TestBed.createComponent(UsersComponent);
let instance: UsersComponent = fixture.componentInstance;
instance.instance.loadUserList();;
expect(instance.userData.length).toEqual(usersData.length);
expect(instance.userData).toBe(usersData);
})));
}
1) Whats wrong with the unit test which is returning null values.
The following worked for me. instruct to use Http instead of AuthHttp using
{ provide: AuthHttp, useExisting: Http }
so my unit testing file has the following change.
describe('list-users.component.ts', () => {
beforeEach(() => {
TestBed.configureTestingModule(
{
declarations: [UsersComponent],
imports: [HttpModule, DevExtremeModule],
providers: [MockBackend, BaseRequestOptions,
{ provide: XHRBackend, useClass: MockBackend },
{ provide: Router, useClass: MockRouter },
{ provide: ActivatedRoute, useClass: MockRouter },
{ provide: AuthHttp, useExisting: Http }
]
});
});
Hope it will be useful for someone someday, Cheers :)

Angular2 DI error in jasmine test

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.

"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();
});
});

Angular 2 Unit test Error: Cannot resolve all parameters for 'RequestOptions'

I want to test a simple component that have some Dependencies. So among others I have to provide some providers.
/* tslint:disable:no-unused-variable */
import { By } from '#angular/platform-browser';
import { DebugElement, provide } from '#angular/core';
import {
beforeEach,
beforeEachProviders,
describe,
expect,
it,
inject,
fakeAsync,
TestComponentBuilder
} from '#angular/core/testing';
import { AuthHttp, AuthConfig } from 'angular2-jwt';
import { Router, provideRouter } from '#angular/router';
import { Http, ConnectionBackend, RequestOptions, HTTP_PROVIDERS } from '#angular/http';
import { LogoutButtonComponent } from './logout-button.component';
import { UserService } from '../../services/index';
describe('Component: LogoutButtonComponent', () => {
let component: LogoutButtonComponent;
beforeEachProviders(() => [
LogoutButtonComponent,
Http,
provide(AuthHttp, { useFactory: Http }),
provide(AuthConfig, { useValue: new AuthConfig() }),
ConnectionBackend,
RequestOptions,
UserService
]);
beforeEach(inject([AuthHttp, UserService, LogoutButtonComponent],
(comp: LogoutButtonComponent) => {
component = comp;
}));
it('should inject UserService', () => {
// My test here
});
});
Though I'm getting the following error:
Error: Cannot resolve all parameters for 'RequestOptions'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'RequestOptions' is decorated with Injectable.
Am I missing something oin the beforeEachProviders function?
Note: This question is related only with the Unit Testing of Angular 2 with Jasmine. I'm not searching infos relate bootstraping app as this is already ok in my app and there are other related questions here.
You have to import HttpModule into your TestBed configuration.
import { HttpModule } from "#angular/http";
TestBed.configureTestingModule({
imports: [
HttpModule
]
});
After that unit testing should work 👌🏻
RequestOptions is not an injectable, you don't inject this into classes. Instead, you instantiate one as needed when making an HTTP request. So you can remove it from the beforeEachProviders, and instantiate one in the beforeEach if you actually need it in the tests:
let options: RequestOptions;
beforeEach(inject([AuthHttp, UserService, LogoutButtonComponent],
(comp: LogoutButtonComponent) => {
component = comp;
options = new RequestOptions({method: RequestMethod.Post});
}));
I've fixed my error by importing HttpModule and Http from #angular/http :
import {HttpModule, Http} from "#angular/http";
...
TestBed.configureTestingModule({
imports: [HttpModule], // <!-- HTTP module
providers: [HttpService, SourceService, Http] // <!-- HTTP
});
Might be better to mock out the user service then you don't have to worry about the RequestOptions or the HttpModule, here's my approach to problem above:
import { RouterTestingModule } from '#angular/router/testing';
import { TestBed } from '#angular/core/testing';
import { LogoutButtonComponent } from './logout-button.component';
import { UserService } from '../../services/index';
describe('Component: LogoutButtonComponent', () => {
let component: LogoutButtonComponent;
let fixture: ComponentFixture<LogoutButtonComponent>;
let mockUserService;
beforeEach(() => {
// Provide array of user service methods used in LogoutButtonComponent to the createSpyObj
mockUserService = jasmine.createSpyObj(['exampleUserServiceMethod']);
TestBed.configureTestingModule({
declarations: [ LogoutButtonComponent ],
providers: [
{ provide: UserService, useValue: mockUserService }
],
// Only if your component uses routing
imports: [
RouterTestingModule
]
});
fixture = TestBed.createComponent(LogoutButtonComponent);
component = fixture.componentInstance;
})
it('should inject UserService', () => {
// My test here
});
});