Search code examples
angularunit-testingjasmineangular-httpclientangular11

Angular 11: Wrong Typecheck for UnitTest Spy on HttpClient.get()


When unit testing Angular's HttpClient.get(...) function, it seems that TypeScript cannot check types correctly when spying on HttpClient.get(...) with given responseType.

This error appeared after upgrading to Angular 11.

beforeEach(async () => {
  await TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
    declarations: [AppComponent],
  }).compileComponents();
});

it('should check HttpClient.get()', () => {
  const http = TestBed.inject(HttpClient);
  const httpGetSpy = spyOn(http, 'get').and.returnValue(of('Test result.'));
  http.get('/test/url', { responseType: 'text' });
  
  expect(httpGetSpy).toHaveBeenCalledWith(
    '/test/url',
    { responseType: 'text'}
    // ^^^ Error:
    // "Type '"text"' is not assignable to type '"json" | undefined'.
  );
});

Besides the simple reproducer above here is a more reasonable example as it appears in my production code:

// example.service.ts
@Injectable({ providedIn: 'root' })
export class ExampleService {
  constructor(private http: HttpClient) { }

  doSomething(): Observable<any> {
    return this.http.get('/some/url', { responseType: 'text' });
  }
}

// example.service.spec.ts
describe('ExampleService', () => {
  let service: ExampleService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule]
    });
    service = TestBed.inject(ExampleService);
  });

  it('should be created', () => {
    const http = TestBed.inject(HttpClient);
    const httpGetSpy = spyOn(http, 'get').and.returnValue(of('Test result.'));
    service.doSomething().subscribe();
    expect(httpGetSpy).toHaveBeenCalledWith('/some/url', { responseType: 'text' });
  });
});


Solution

  • Okay, so the reason you are getting this error is because Angular is moving in the direction of stronger type checking. This will allow for better build optimizations. Angular 11 fixed a lot of 'lose' typing's. You need to add a type to the spy you created.

    const httpGetSpy: jasmine.Spy<(arg0: string, {}) => Observable<string>> = spyOn(http, 'get').and.returnValue(of('Test result.'));
    

    or you can just make it simple and do this

    const httpGetSpy: jasmine.Spy<any> = spyOn(http, 'get').and.returnValue(of('Test result.'));