angular 2 testing mock service - unit-testing

I am trying to mock out a service in my angular 2 test but it just keeps using the real one and giving me loads of errors related to not finding the dependencies of that service
here is my component file
import {Component, Input} from '#angular/core';
import {ClientService} from '../client.service';
#Component({
selector: 'registry',
templateUrl: './registry.component.html',
styleUrls: [
'./registry.component.scss'.toString()
]
})
export class RegistryComponent {
constructor(private clientService: ClientService) {
}
loadResources() {
return this.clientService.getBusinessNetwork()
}
}
And this my test file
import {NO_ERRORS_SCHEMA} from '#angular/core';
import {inject, async, TestBed, ComponentFixture} from '#angular/core/testing';
import {Component} from '#angular/core';
import * as sinon from 'sinon';
import {RegistryComponent} from './registry.component';
import {ClientService} from '../client.service';
describe(`Registry`, () => {
let comp: RegistryComponent;
let fixture: ComponentFixture<RegistryComponent>;
beforeEach(() => {
let MockClientService = {
getBusinessNetwork : sinone.stub()
};
TestBed.configureTestingModule({
declarations: [RegistryComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{provide: ClientService, useValue: MockClientService},
]
})
.compileComponents(); // compile template and css
}));
beforeEach(() => {
fixture = TestBed.createComponent(RegistryComponent);
comp = fixture.componentInstance;
fixture.detectChanges(); // trigger initial data binding
});
it('should have default data', () => {
comp.should.be.true;
});
});
Can anyone help please?

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

Unit testing and mocking a service with DI

I have been struggling with this for a while, and I'm hoping someone can help. I have a component that uses a service to get data. I am attempting to add unit tests to it. My problem is that the tests always fail with "Error: No provider for Http". Here is my code:
Service:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import { Contact } from './contact.model';
#Injectable()
export class ContactsService {
constructor(private http: Http) { }
public getContacts(): Observable<Array<Contact>> {
return this.http.get('assets/contacts.json').map(res => {
let r = res.json().Contacts;
return r;
});
}
}
Component:
import { Component, OnInit, NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { Contact } from '../contact.model';
import { ContactsService } from '../contacts.service';
#Component({
selector: 'app-contacts',
templateUrl: './contacts.component.html',
styleUrls: ['./contacts.component.css'],
providers: [ContactsService]
})
export class ContactsComponent implements OnInit {
contactsAll: Array<Contact>;
contacts: Array<Contact>;
constructor(private contactsService: ContactsService) { }
ngOnInit() {
this.contactsService.getContacts().subscribe((x) => {
this.contactsAll = x;
this.contacts = this.contactsAll;
});
}
}
Tests:
import { async, ComponentFixture, TestBed, inject } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { By } from '#angular/platform-browser';
import { Observable } from 'rxjs/Rx';
import { ContactsComponent } from './contacts.component';
import { ContactsService } from '../contacts.service';
import { Contact } from '../contact.model';
class MockContactsService extends ContactsService {
constructor() {
super(null);
}
testContacts: Array<Contact> = [
new Contact("test1 mock", 12345, 10000),
new Contact("test2 mock", 23456, 20000)
];
public getContacts(): Observable<Array<Contact>> {
return Observable.of(this.testContacts);
}
}
describe('ContactsComponent', () => {
let component: ContactsComponent;
let fixture: ComponentFixture<ContactsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [ContactsComponent],
// providers: [{ provide: ContactsService, useClass: MockContactsService }] // this is needed for the service mock
}).overrideComponent(ContactsService, {// The following is to override the provider in the #Component(...) metadata
set: {
providers: [
{ provide: ContactsService, useClass: MockContactsService },
]
}
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContactsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('1st test', () => {
it('true is true', () => expect(true).toBe(true));
})
});
Let's try this:
First, move your providers array from your component to your NgModule. It's better to provide your services at the module level since it de-couples your providers from your component tree structure (unless you specifically want to have a separate instance of a provider per component, and from your simplified use case, there's no need for a separate instance per component).
so,
#Component({
selector: 'app-contacts',
templateUrl: './contacts.component.html',
styleUrls: ['./contacts.component.css'],
/// providers: [ContactsService] <-- remove this line
})
export class ContactsComponent implements OnInit {
.....
and add it to the NgModule that declares your ContactsComponent
#NgModule({
imports: ..
declarations: ...
providers: [ContactsService] // <-- provider definition moved to here
})
export class ModuleDeclaringContactsComponent
Once you do that, then mocking the ContactsService in your test is easy to implement.
TestBed.configureTestingModule({
imports: [FormsModule],
declarations: [ContactsComponent],
providers: [{ provide: ContactsService, useClass: MockContactsService }] // this is needed for the service mock
});
With that, you should be good to go.
Sorry everyone - turns out it was something completely different.
I modified my code as per snorkpete's answer, and I am going to mark that as the answer, as I believe that is the cleanest approach.
The real problem came from using Angular Cli to create my project. It automatically created tests for my component and my service. This meant the code in the service test was causing the error, not the code in the component. I commented out the code in the service test and everything passed.
Annoyingly, there was no indication in any of the failures that this is where the error was coming from!
In case if component should have Service in providers we can ovverride metadata by TestBed.overrideComponent():
#Component({
selector: 'app-contacts',
templateUrl: './contacts.component.html',
styleUrls: ['./contacts.component.css'],
providers: [ContactsService] // IF YOU NEED IT
})
we need to do next:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
declarations: [ SomeComponent ],
providers: [
{provide: SomeService, useValue: SomeMock},
provideMockStore({system: {userConfig: {viewSettings: {theme: ThemeName.light}}}} as any)
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
TestBed.overrideComponent(SomeComponent , { set: { providers: [{provide: SomeService, useValue: SomeMock}]}})
}));
beforeEach(() => {
fixture = TestBed.createComponent(SomeComponent );
component = fixture.componentInstance;
fixture.detectChanges();
});
more info here https://codecraft.tv/courses/angular/unit-testing/dependency-injection/

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