0

I have created this function because for all the requests my application sends out using http.post, this is how different parts handle the response. So rather than duplicating the code, I thought to create a function. But I am unable to figure out how to unit test this function.

private editAnswerSubject: Subject<Result>;
subscribeToReturnedObservable(observable:Observable<any>, subject:Subject<Result>) {
    observable.subscribe((res) => {
        const ev = <HttpEvent<any>>(res);
        if (ev.type === HttpEventType.Response) {
          const isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(ev.body);
          if (isResponseStructureOK) {
            const response: ServerResponseAPI = ev.body;
            subject.next(new Result(response.result, response['additional-info']));

          } else {
            subject.next(new Result(messages.error, messages.invalidStructureOfResponse));
          }
        }
      },
      (error: ServerResponseAPI) => {
        const errorMessage: string = this.helper.userFriendlyErrorMessage(error);
        subject.next(new Result(messages.error, errorMessage));    
      },
      () => { // observable complete
      });
  }

  editAnswer(answer: Answer): any {
    const observable = this.bs.editAnswer(answer)
    this.subscribeToReturnedObservable(observable,this.editAnswerSubject);
  }

The test I have written so far is

  describe('subscribeToReturnedObservable tests:', () => {
    beforeEach(() => {
      TestBed.configureTestingModule({
        imports: [HttpClientTestingModule],
        providers: [QuestionManagementService, HelperService, WebToBackendInterfaceService, AuthService, HttpClient, HttpHandler]
      });
    });

fit('should call send next value for the subject is the response from the server is ok', () => {
  const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
  const body = {"result":"success", "additional-info":"some additional info"};
  const receivedHttpEvent = new HttpResponse({body:body});
  let observable = new Observable();
  spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent);
  spyOn(questionService['editQuestionSubject'],'next');
  questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
  observable.subscribe();
  expect(questionService['editQuestionSubject'].next).toHaveBeenCalled();
});
});

But it get error Expected spy next to have been called.

Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
  • `spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent);` won't work because `subscribe` returns Subscription and `receivedHttpEvent` should be emitted by `observable`. – martin Apr 20 '20 at 07:10
  • thanks martin. I guess my doubt is how do I make `observable.subscribe((res)=>...` run with `receivedHttpEvent.`. I am not able to figure that out. – Manu Chadha Apr 20 '20 at 07:15
  • Have a look at this https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/testing/marble-testing.md or if you can make a stackblitz demo I can have a look – martin Apr 20 '20 at 07:25
  • Thanks martin. I have tried an alternative way. Thanks for introduce me to Marbel testing. I didn't know about it. I also found this article useful - https://medium.com/angular-in-depth/how-to-test-observables-a00038c7faad – Manu Chadha Apr 21 '20 at 05:43
  • Martin =-I thought to try using marbel testing to simulate error scenario but I am stuck. Could you please take a look at https://stackoverflow.com/questions/61337404/unable-to-write-a-test-case-with-marbel-testing – Manu Chadha Apr 21 '20 at 06:44

1 Answers1

0

I did this (hoping that it is the right way). The scope of testing is to check that the Subject's next is called correctly. So create an Observable using of and let the code flow from there.

fit('should call send next value for the subject is the response from the server is ok', () => {
  const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
  const helperService:HelperService = TestBed.get(HelperService);
  const body = {"result":"success", "additional-info":"some additional info"};
  const receivedHttpEvent = new HttpResponse({body:body});
  const expectedResult = new Result('success', 'some additional info');
  spyOn(helperService,'validateServerResponseStructure').and.returnValue(true);
  let observable = of(receivedHttpEvent);
  spyOn(questionService['editQuestionSubject'],'next');
  questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
  expect(questionService['editQuestionSubject'].next).toHaveBeenCalledWith(expectedResult);
});
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184