2
votes

I have an httpService from nestjs/common

and I am using like the following:

const response = await this.httpService.post(`${this.api}/${action}`, data).toPromise();

and in my jest spec file ( unit testing) . i am trying to mock this service

   httpServiceMock = {
      post: jest.fn()
    };

it('should start', async () => {

    const serviceResult = await service.start(data);

});

and I have got this error :

TypeError: this.httpService.post(...).toPromise is not a function

I am also trying to add a promise result like :

 const promise = Promise.resolve('result');
 httpServiceMock.post.mockResolvedValue(promise);

tried also :

it('should start', async () => {

    const mockObservable = Promise.resolve({
        toPromise: () => {
          console.log('toPromise called');
        }
      })

    httpServiceMock.post.mockImplementation(() => mockObservable);

    const serviceResult = await service.start();

});

My question is how can I mock the promise and return a response or exception

2

2 Answers

4
votes

The return value httpService.post needs to return an Observable<AxiosResponse<T>> which includes a property toPromise, which is a function. Your mock returns a resolved promise, whereas it needs to return a fake Observable.

The Observable is returned immediately, so the post implementation can just return a raw value, but the toPromise needs to return a promise.

Return the correct shaped object to get rid of this error:

const mockObservable = {
  toPromise: () => Promise.resolve('result')
}
httpServiceMock.post.mockImplementation(() => mockObservable);
0
votes

I had a similar problem that could not be solved by accepted answer. So I bring here another solution just in case it could help someone else.

If you have jasmine, just use jasmine.createSpyObj(). If not, here is what I needed to do :

First, I implemented a jasmine.createSpyObj() equivalent (based on this answer with little modifications) :

export class TestUtilsService {
  static createSpyObj (baseName:string, methodNames:string[]): SpyObject {
    let obj: any = {};

    for (let i = 0; i < methodNames.length; i++) {
      obj[methodNames[i]] = jest.fn();
    }
    return {[baseName]:()=>obj};
  };
}

export class SpyObject {
  [key: string]: ()=>{[key:string]:jest.Mock} ;
}

Then I used it in my unit test :

const spyHttpClient: SpyObject = TestUtilsService.createSpyObj('get',['toPromise']);

Add it in test module providers :

{provide: HttpClient, useValue: spyHttpClient}

Finally, mock the toPromise implementation in order to return a mocked response :

const mockedResponse = {...};
spyHttpClient.get().toPromise.mockImplementationOnce(()=>Promise.resolve(mockedResponse));
await service.myRealMethodThatCallsHttpClient();
expect(service.someUpdatedProp).toBeTruthy();

Please notice parenthesis after method get.