angularunit-testingjasminekarma-jasmineangular-test

Jasmine test Observable


I have a service class in an Angular application that I need to write tests for. The service class works well, but I am unable to write the Jasmine unit test.

The service class subscribes to an observable in a websocket class with a class method, and upon execution of this local method, calls the next on a class observable with the result and return that observable. This next never gets called.

To illustrate

class MyServiceClass {
   constructor() {
     this.websocketSubject.subscribe(this.funProcessing);
   }
   results = new Subject<MyType>();
   signalEnd = new Subject<void>();
   private _funProcessing(responseFromSocket) {
     if (resonseFromSocket == likeTheResponse) {
       results.next(responseFromSocket);
     
   getResponse(query) {
     this.websocketSubject.send(query);
     return this.results;
   }
}

Some things that I've tried with tests

it('should process a message ', (done) => {
    /* service = createSpyFromClass(MyServiceClass, {
      observablePropsToSpyOn: ['results'],
    }); */
    service = TestBed.inject(MyServiceClass);
    const envv = jasmine.getEnv();
    envv.allowRespy(true);

    let actual: Response | undefined;
    service.results.subscribe((value) => {
      actual = value;
      done();
    });
    spyOn(service, 'getResponse').withArgs(1).and.callThrough();
    //service.getResponse(1);
    expect(actual?.index).toEqual(1);

  });

This service works well, it's only the test that don't work. If I log to console from tests, I can see that the funProcessing gets called, but results.next never triggers.

I've tried many things, spies, callbacks done/done(), fakeasync, jasmine-auto-spies, absolutely nothing works.


Solution

  • I think expect blocks should be placed before done is executed.

    it('should process a message ', (done) => {
        /* service = createSpyFromClass(MyServiceClass, {
          observablePropsToSpyOn: ['results'],
        }); */
        service = TestBed.inject(MyServiceClass);
        const envv = jasmine.getEnv();
        envv.allowRespy(true);
    
        let actual: Response | undefined;
        service.results.subscribe((value) => {
          actual = value;
          expect(actual?.index).toEqual(1);
          done();
        });
        spyOn(service, 'getResponse').withArgs(1).and.callThrough();
        service.getResponse(1);
    
    });