How to mock components with providers in Angular 4? - Unit test

I have a problem with bullying a component with suppliers in Angular 4. Here is the code:

import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/core/platform-browser'; import { DebugElement } from '@angular/core'; import { FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms'; import { Router, RouterModule } from '@angular/router'; import { Http, ConnectionBackend, BaseRequestOptions } from '@angular/http'; import { MockBackend, async } from '@angular/http/testing'; import { LoginComponent } from './../../../src/app/login/login.component'; import { LoginService } from './../../../src/app/login/login.service'; import { LoginComponent } from './../../../src/app/login/login.component'; import { LoggerService } from './../../../src/app/logger-service'; import { AuthService } from './../../../src/app/pages/auth.service'; describe('LoginComponent', () => { let comp: LoginComponent; let fixture: ComponentFixture<LoginComponent>; let de: DebugElement; let el: HTMLElement; beforeEach(() => { // implement mock class loggerService = { }; class loginService = { }; class authService = { }; class router = { }; TestBed.configureTestingModule({ declarations: [ LoginComponent ], imports: [ ReactiveFormsModule, FormsModule ], providers: [ MockBackend, BaseRequestOptions, AuthService, LoginService, LoggerService, RouterModule, { provide: AuthService, useValue: authService }, { provide: LoginService, useClass: LoginService }, { provide: LoggerService, useValue: loggerService }, { provide: Http, useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => { return new Http(backend, defaultOptions); }, deps: [MockBackend, BaseRequestOptions] }, { provide: Router, useClass: router } ] }).compileComponents().then(() => { fixture = TestBed.createComponent(LoginComponent); comp = fixture.componentInstance; comp.detectChanges(); comp.ngOnInit(); loginService = fixture.debugElement.injector.get(LoginService); loggerService = fixture.debugElement.injector.get(LoggerService); authService = fixture.debugElement.injector.get(AuthService); router = fixture.debugElement.injector.get(Router); }); }); it('should create component', async(() => { expect(comp).toBeDefined(); })); }); 

Here is my mistake:

spec-bundle.js: 9 Unhandled Promise rejection: no AuthService provider !; Zone: ProxyZone; Task: Promise.then; Cost: Error {__zone_symbol__error: error on error .ZoneAwareError ( http: // localhost: 9876 / base / config / spec-bundle.js: 9: 3748709 ) a ......}

Any idea what I'm doing wrong?

Thank you in advance:)

+5
source share
1 answer

So, a couple of things are pulling me out. Although I'm not sure if this is your problem.

You are trying to stub empty classes, use them to simulate an injection into your component instead of a real service, and then assign these embedded services back to stub variables. Instead, I will try to either use legitimate services or cut them out and get a separate link to them.

In the case of AuthService, if you want to provide a real service (even if you later intercept and glance at its parts), you can simply say

 ... providers: [AuthService] ... 

If you want to mock this, you should use:

 class mockAuthService{} beforeEach(() => { TestBed.configureTestingModule({ ... providers: [{provide: AuthService, useClass: mockAuthService}] ... 

or

 let mockAuthService; beforeEach(() => { mockAuthService = {} TestBed.configureTestingModule({ ... providers: [{provide: AuthService, useValue: mockAuthService}] ... 

In addition, I can’t double check to make sure that this is a problem, you did all this inside the beforeEach scope, and not outside it (so you can refer to this variable later if you want). I would move this above your beforeEach () as shown above / below.

Here is an example of what I mean.

 describe('LoginComponent', () => { let comp: LoginComponent; let fixture: ComponentFixture<LoginComponent>; let de: DebugElement; let el: HTMLElement; let authServiceReference; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ LoginComponent ], imports: [ ReactiveFormsModule, FormsModule ], providers: [ MockBackend, BaseRequestOptions, AuthService, LoginService, LoggerService, RouterModule, { provide: Http, useFactory: (backend: ConnectionBackend, defaultOptions: BaseRequestOptions) => { return new Http(backend, defaultOptions); }, deps: [MockBackend, BaseRequestOptions] }, Router ] }).compileComponents().then(() => { fixture = TestBed.createComponent(LoginComponent); comp = fixture.componentInstance; comp.detectChanges(); comp.ngOnInit(); authServiceReference = Testbed.get(AuthService); // get service you injected above }); }); it('should create component', () => { expect(comp).toBeDefined(); }); // this part really doesn't need to be async. 

A few additional things (I am also relatively new, and this is what I took). You may find it easier to clutter up just the link to the injectable services in the test itself. Example:

 it('should have a service', inject([SomeService], (serviceHandle: SomeService) => { expect(serviceHandle).toEqual(sameServiceYouTriedToGrabInInitialSetUp); } 

I hope this makes sense lol. Point, it's much easier to just grab it there. Moreover, you can implement as many services as you want to grab a handle for this particular test.

  it('should have a service', inject([SomeService, SomeOtherService, YetOneMoreService], (serviceHandle: SomeService, otherServiceHandle: SomeOtherService, yetAnotherHandle: YetOneMoreService) => { spyOn(serviceHandle, 'isAuthenticated').and.returnsValue(true); spyOn(otherServiceHandle, 'getUrl').and.returnsValue(/home); let yahSpy = spyOn(yetAnotherHandle, 'doSomething'); //code expect (yahSpy.doSomething).toHaveBeenCalled(); } 

Hope this helps.

+5
source

All Articles