angularjestjsangular-httpclientangular-test

Angular tests with Jest: How to inject HttpClient: Can't resolve all parameters for xxxx


I'm moving my tests from jasmine/karma to Jest.

I'm struggling to inject HttpClient and its testing controller. I'm following https://angular.io/guide/http-test-requests and I get this dummy test:

import { HttpClient, provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';

describe('Testings tests', () => {
  let httpTestingController!: HttpTestingController;
  let dummyTest: DummyTest;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [DummyTest, provideHttpClient(), provideHttpClientTesting()],
    });
    httpTestingController = TestBed.inject(HttpTestingController);
    dummyTest = TestBed.inject(DummyTest);
  });

  fit('Should request data', async () => {
    const promise = dummyTest.TestRequest();

    httpTestingController.expectOne('https://google.com').flush({});

    await promise;
  });
});

export class DummyTest {
  constructor(private httpClient: HttpClient) {}

  async TestRequest() {
    await this.httpClient.get('https://google.com');
  }
}

but when I do run it, I get an error:

NG0204: Can't resolve all parameters for DummyTest: (?).

  10 |       providers: [DummyTest, provideHttpClient(), provideHttpClientTesting()],
  11 |     });
> 12 |     httpTestingController = TestBed.inject(HttpTestingController);
     |                                     ^
  13 |     dummyTest = TestBed.inject(DummyTest);
  14 |   });

I'm not sure what I'm missing out, because the HttpClient and the HttpClientTesting is provided.

I'm using angular 18 and latest version of jest.


Solution

  • Try add the decorator for service. The providedIn root might be optional.

    When working with observables you can just subscribe to them. Then use fakeAsync and flush from angular testing, to wait for the subscribe to complete.

    Updated my answer, based on Angular Testing Docs

    @Injectable({providedIn: 'root'})
    export class DummyTest {
      constructor(private httpClient: HttpClient) {}
    
      TestRequest() {
        return this.httpClient.get('https://google.com');
      }
    }
    
    describe('Testings tests', () => {
      let httpTestingController!: HttpTestingController;
      let dummyTest: DummyTest;
      beforeEach(waitForAsync(() => {
        TestBed.configureTestingModule({
          providers: [DummyTest, provideHttpClient(), provideHttpClientTesting()],
        }).compileComponents();
      }));
    
      fit('Should request data', () => {
        httpTestingController = TestBed.inject(HttpTestingController);
        dummyTest = TestBed.inject(DummyTest);
        const config$ = dummyTest.TestRequest();
        // `firstValueFrom` subscribes to the `Observable`, which makes the HTTP request,
        // and creates a `Promise` of the response.
        const reqPromise = firstValueFrom(config$);
        // At this point, the request is pending, and we can assert it was made
        // via the `HttpTestingController`:
         const req = httpTestingController.expectOne('https://google.com');
        // We can assert various properties of the request if desired.
        expect(req.request.method).toBe('GET');
        // Flushing the request causes it to complete, delivering the result.
        req.flush({});
        // We can then assert that the response was successfully delivered by the `ConfigService`:
        expect(await reqPromise).toEqual({});
        // Finally, we can assert that no other requests were made.
        httpTesting.verify();
      });
    });