0

I am trying to test a simple component that has a dependency. I am trying to mock that dependency, but the real service is still being constructed. Could somebody spot what am I missing?

Here is my component:

import { Component } from "@angular/core";
import { AuthService } from "src/app/services/auth.service.js";

@Component({
  selector: "app-auth-form",
  template: ""
})
export class AuthFormComponent {
  constructor(private authService: AuthService) {}
}

That depends on this AuthService:

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { UserModule } from "../user/user.module";

@Injectable({
  providedIn: "root"
})
export class AuthService {
  constructor(private http: HttpClient) {}

  registerUser(email: string, password: string): Promise<UserModule> {
    return null;
  }
}

Notice it in turn depends on HttpClient.

Now my test looks like this:

import { async, TestBed } from "@angular/core/testing";
import { AuthFormComponent } from "./auth-form.component";
import { AuthService } from "src/app/services/auth.service";

describe("AuthFormComponent", () => {
  beforeEach(async(() => {
    const authServiceSpy = jasmine.createSpyObj("AuthService", [
      "registerUser"
    ]);

    TestBed.configureTestingModule({
      declarations: [AuthFormComponent],
      providers: [{ provide: AuthService, useValue: authServiceSpy }]
    }).compileComponents();
  }));

  it("should create", () => {
    let component = TestBed.createComponent(AuthFormComponent)
      .componentInstance;
    expect(component).toBeTruthy();
  });
});

Here please see the line { provide: AuthService, useValue: authServiceSpy }, therefore I expect real AuthService to not be constructed. But when I run the test I get following error:

Chrome 78.0.3904 (Windows 10.0.0) AuthFormComponent should create FAILED
        NullInjectorError: StaticInjectorError(DynamicTestModule)[HttpClient]: 
          StaticInjectorError(Platform: core)[HttpClient]: 
            NullInjectorError: No provider for HttpClient!
        error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ Function ], ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 33603585, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 49152, directChildFlags: 49152, childMatchedQueries: 0, matchedQueries: Object({  }), matchedQueryIds: 0, references: Object({  }), ngContentIndex: null, childCount: 1, bindings: [  ], bindingFlags: 0, outputs: [  ], element: Object({ ns: '', name: 'app-auth-form', attrs: [  ], template: null, componentProvider: Object({ nodeIndex: 1, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 49152, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, childCount: 0 ...
            at <Jasmine>
            at NullInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:855:1)
            at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
            at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
            at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
            at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
            at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
            at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
            at resolveNgModuleDep (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:30393:1)
            at NgModuleRef_.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:31578:1)
            at injectInjectorOnly (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:734:1)
Chrome 78.0.3904 (Windows 10.0.0): Executed 3 of 3 (1 FAILED) (0 secs / 0.077 secs)
Chrome 78.0.3904 (Windows 10.0.0) AuthFormComponent should create FAILED
        NullInjectorError: StaticInjectorError(DynamicTestModule)[HttpClient]: 
          StaticInjectorError(Platform: core)[HttpClient]: 
            NullInjectorError: No provider for HttpClient!
        error properties: Object({ ngTempTokenPath: null, ngTokenPath: [ Function ], ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 33603585, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 49152, directChildFlags: 49152, childMatchedQueries: 0, matchedQueries: Object({  }), matchedQueryIds: 0, references: Object({  }), ngContentIndex: null, childCount: 1, bindings: [  ], bindingFlags: 0, outputs: [  ], element: Object({ ns: '', name: 'app-auth-form', attrs: [  ], template: null, componentProvider: Object({ nodeIndex: 1, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 49152, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, childCount: 0 ...
            at <Jasmine>
            at NullInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:855:1)
            at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
            at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
            at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
            at resolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17514:1)
            at tryResolveToken (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17440:1)
            at StaticInjector.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:17266:1)
            at resolveNgModuleDep (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:30393:1)
            at NgModuleRef_.get (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:31578:1)
Chrome 78.0.3904 (Windows 10.0.0): Executed 3 of 3 (1 FAILED) (0.096 secs / 0.077 secs)

This to me seem that it tries to construct the real AuthService, but doesn't have its dependencies. Any pointers would be great!

EDIT

I recreated the scenario in StarBlitz - https://angular-wrk4yi.stackblitz.io, but it works fine there. So it must be on my end somewhere.

Pavel Schoffer
  • 492
  • 1
  • 3
  • 11
  • I don't know:) They don't seem to be necessary. I can do `console.log(authServiceSpy)` after it was created and get some object there. Should I explicitly add some? – Pavel Schoffer Dec 22 '19 at 12:59
  • could you please tell did my answer help? – Pallamolla Sai Dec 22 '19 at 13:32
  • Oh now I see you did provide an answer bellow. Sorry didn't realize it's the same person. – Pavel Schoffer Dec 22 '19 at 13:34
  • try to import HttpClientTestingModule & add in imports. Then check what output is coming?? – Pallamolla Sai Dec 22 '19 at 13:50
  • @PALLAMOLLASAI is right, try to import HttpClientTestingModule and add in imports inside TestBed.configureTestingModule – David Lasry Dec 22 '19 at 15:28
  • Buut, why should my test care about httpClient? Which is a dependency of dependency that I am trying not to use. BTW I also tried to mock HttpClient (which is what that module does as well), which results in code running. BUT my httpMock actually being used and still only my real authService called (instead of its stub) – Pavel Schoffer Dec 23 '19 at 12:10

1 Answers1

0

EDIT

Finaly figured it out! The issue was in import. In my component i had:

import { AuthService } from "src/app/services/auth.service.js";

instead of :

import { AuthService } from "src/app/services/auth.service";

So then I assume it loads the javascript version from dist folder and then the typed base providing doesnt work.


I couldn't figure out what provides the original Service, but found this workaround:

TestBed.overrideProvider(AuthService, { useValue: authServiceSpy})

This as per name overrides wherever the real service provider was comming from. And I no longer need to support real AuthService dependencies + mainly the class under test actually uses my spy here!

Pavel Schoffer
  • 492
  • 1
  • 3
  • 11