How to mock function with callback and return type in Jasmine

Viewed 228

I'm trying to mock function that has a stream return type and callback as arg. I get timeout because the call back function never get called.

This is the function I'm trying to test:

 public setServerUrls(): Observable<void> {
    const obs: Observable<void> = new Observable((observer: Observer<void>) => {
      const stream: ClientWritableStream<Util.Server> = this.fileTransferClient.setURLs((error: ServiceError, response) => {

        if (error) {
          observer.error(`TransferManager Electron: unable to set server urls error: ${error.message}.`);
        }
        observer.next();
        observer.complete();
        logger.info(`TransferManager Electron: setting URLs completed.`);
      });

      const transferRequest = new Util.Server();
      transferRequest
        .setIp('localhost')
        .setTransferport('9092')
        .setUuid('4020a522-81fe-4996-b637-0620ae656d29');
      stream.write(transferRequest);
      stream.end();
    });

    return obs;
  }

My jasmine setup:

 const settingStream = {
      write: () => { },
      end: () => { }
    };

    const callBack = () => {
      return;
    };

    const f = function (callback: Function): any {
      return settingStream;
    };

    mockFileTransferClient = jasmine.createSpyObj('FileTransferClient', {
      subscribe: () => mockFileTransferStream,
      uploadFile: () => duplexStream,
      setURLs: f(callBack)
    });

    mockFileTransferClientWrapper.createNewFileTransferClient.and.returnValue(mockFileTransferClient as any);

// Question here... does not work!
mockFileTransferClient.setURLs.and.returnValue(settingStream);

test:

   it('should set urls', done => {
      transferManager.setServerUrls()
        .subscribe(
          x => {
            expect(x).toBeDefined();
            done();
          }
        );
    });

This is Elctron + grpc functionality test. Test timeout because it never gets into the callback and observable never completes. I'm not sure how to mock setURLs with return value AND callback.

1 Answers

You have to first mock your setUrls to return a resolved observable.

I think what you need here is to use fakeAsync() functionality as you are dealing with async test. Using Tick with fakeAsync ensures that all pending asynchronous activities will finish. In your case it will wait for setTimeout.

Note that you should also inject the setServerUrls using TestBed.inject...

So I think your tests should look like this

it("should .....", fakeAsync(() => {

 // Arrange - mock functions

 // Act - Make a call to the function

 // Use tick() after making call to the function which will flush your setTimeouts

// Assert 
}));

For more information, see the fakeAsync documentation

Related