4

I try to make a spy on a generic method in typescript,
but cannot get Jasmine to recognise it.


I have code

http: HttpClient <- Not proper code, just showing type.
...
this.http.get<Customer[]>(url);

where I want to mock the get<...> method.

const httpMock = {} as HttpClient;
spyOn(httpMock, 'get')
   .and.returnValue(of({} as Customer[]));

But when I run the test I get

Error: : get() method does not exist
Usage: spyOn(, )

LosManos
  • 7,195
  • 6
  • 56
  • 107
  • Try doing `const httpMock = { get: () => null } as HttpClient;` but you should be using the `HttpTestingController` (https://angular.io/api/common/http/testing/HttpTestingController) for testing HTTP. – AliF50 Jun 18 '20 at 13:30
  • Doesn't `HttpTestingController` solve the problem of making sure a call Has been made? - not that it mocks the answer from it? – LosManos Jun 22 '20 at 08:00
  • 1
    You can also mock the responses with the flush method. https://medium.com/better-programming/testing-http-requests-in-angular-with-httpclienttestingmodule-3880ceac74cf Check that out. – AliF50 Jun 22 '20 at 12:15

2 Answers2

1

The remedy was to not use any generics when mocking.

describe('UserService', () => {
  it('should return proper users', (done) => {

    const returnedUsers = [...];

    const mock = {
      get: (_) => of({returnUsers}),
    } as HttpClient;

    const sut = new UserService(mock);

    //  Act.
    sut.getUser()
        .subsribe(users => {

            //  Assert.
            ...

            done();
        });
  });
});
LosManos
  • 7,195
  • 6
  • 56
  • 107
0

First of all, I am aware of HttpClientTestingModule, but in simple cases it can be an overkill. If you properly mock HttpClient, for example, with MockBuilder, like this:

beforeEach(() => {
  return MockBuilder()
    .keep(YourService)
    .mock(HttpClient);
});

Then your code will work.

spyOn(http, 'get').and.returnValue(of([] as Customer[]));

Notice you need [] instead of {}. However, it is usually a good idea to have a request object instead, which will have an array of items/row + other metadata. This is how most real-world API responses will come back.

If your app doesn't need any metadata, you can map to an array via pipe. But then it's flexible enough to change at any point.

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151