1

Consider the following Http interceptor:

export class BusyIndicatorInterceptor implements HttpInterceptor {
    constructor(private busyIndicatorService: BusyIndicatorService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.busyIndicatorService.show();

        return next.handle(req).pipe(tap((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
                this.busyIndicatorService.hide();
            }
        }, err => {
            console.warn(err);
            this.busyIndicatorService.hide();
        }));
    }
}

I am trying to unit test that the busyIndicatorService.hide is called when an error occurs such as 400, 404 etc. I have written the following test but I think I am not mocking the handler properly.

    it("should set busy indicator visibility to false when HttpResponse is returned", () => {
        mockhandler.handle.and.returnValue(of(new HttpErrorResponse({ error: "Not Found", status: 404 })));
        const result = testee.intercept(mockRequest, mockhandler);
        result.subscribe(() => {
            expect(busyIndicatorService.hide).toHaveBeenCalledTimes(1);
        });
    });

Result:

Expected spy BusyIndicatorService.hide to have been called once. It was called 0 times

The following test works for testing the success block, where I mock the handler to return a new HttpResponse.

it("should set busy indicator visibility to false when HttpResponse is returned", () => {
    mockhandler.handle.and.returnValue(of(new HttpResponse()));
    const result = testee.intercept(mockRequest, mockhandler);
    result.subscribe(() => {
        expect(busyIndicatorService.hide).toHaveBeenCalledTimes(1);
    });
});

Here is the full test class:

describe("BusyIndicatorInterceptor", () => {
    let testee: BusyIndicatorInterceptor;
    let busyIndicatorService: any;
    let mockRequest: any;
    let mockhandler: any;

    beforeEach(() => {
        mockRequest = jasmine.createSpyObj("HttpRequest", [""]);
        mockhandler = jasmine.createSpyObj("HttpHandler", ["handle"]);
        busyIndicatorService = jasmine.createSpyObj("BusyIndicatorService", ["show", "hide"]);
        busyIndicatorService.visibility = jasmine.createSpyObj("BehaviourSubject<boolean>", ["next"]);
        testee = new BusyIndicatorInterceptor(busyIndicatorService);
    });

    it("should be created", () => {
        expect(testee).toBeTruthy();
    });

    describe("intercept", () => {

        it("should set busy indicator visibility to true", () => {
            mockhandler.handle.and.returnValue(of(null));
            testee.intercept(mockRequest, mockhandler);

            expect(busyIndicatorService.show).toHaveBeenCalledTimes(1);
        });

        it("should set busy indicator visibility to false when HttpResponse is returned", () => {
            mockhandler.handle.and.returnValue(of(new HttpResponse()));
            const result = testee.intercept(mockRequest, mockhandler);
            result.subscribe(() => {
                expect(busyIndicatorService.hide).toHaveBeenCalledTimes(1);
            });
        });

        it("should set busy indicator visibility to false when HttpResponse is returned", () => {
            mockhandler.handle.and.returnValue(of(new HttpErrorResponse({ error: "Not Found", status: 404 })));
            const result = testee.intercept(mockRequest, mockhandler);
            result.subscribe(() => {
                expect(busyIndicatorService.hide).toHaveBeenCalledTimes(1);
            });
        });
    });
});
umutesen
  • 2,523
  • 1
  • 27
  • 41
  • You have to inject the DoneFN and call it inside your subscribe. – André Roggeri Campos Jun 20 '19 at 10:34
  • [I have answered a similar question a while back](https://stackoverflow.com/questions/46225164/unit-testing-httpinterceptor-from-angular-4/49176499#49176499). If it can help ... –  Jun 20 '19 at 10:38
  • @AndréRoggeriCampos Do you have an example? – umutesen Jun 20 '19 at 13:31
  • @Maryannah You seem to use `.catch` while I have a tap operator, which I need to mock the error for. Do you have a more specific example? – umutesen Jun 20 '19 at 13:32
  • @uex the implicit point was to make you use `catch` instead of the second callback of the tap operator (which will basically do the same) –  Jun 20 '19 at 13:35
  • @Maryannah Thanks, what namespace is catch from? I get `Property 'catch' does not exist on type 'Observable>'` error – umutesen Jun 20 '19 at 14:10
  • @uex my bad, it's now `.pipe(catchError(...))` from `rxjs/operators` (the answer is a bit outdated as you might have seen) –  Jun 20 '19 at 14:17
  • Thanks! I got the unit test working. It seems that `catchError` requires me to return something so I return `Observable.empty()`. This does not seem to emit the event so the subscribe block on the subscriber does not get called. Any ideas why this may be happening? – umutesen Jun 20 '19 at 15:08

0 Answers0