FabioG
FabioG

Reputation: 2986

Unit Testing angular HttpInterceptor retry

this is the first project where I'm trying to have unit test working for angular, so I'm just figuring out how this exactly works. the project is in angular 7 and I have an HttpInteceptorService to retry 2 extra times if an HTTP request fails:

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
    constructor() { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
        return next.handle(request).pipe(retry(2));
    }
}

my tests for this interceptor so far:

describe('HttpInterceptorService', () => {
    beforeEach(() => TestBed.configureTestingModule({
        imports: [
            HttpClientTestingModule
        ],
        providers: [
            HttpInterceptorService,
            {
                provide: HTTP_INTERCEPTORS,
                useClass: HttpInterceptorService,
                multi: true
            }
        ]
    }));

    it('should be created', () => {
        const service: HttpInterceptorService = TestBed.get(HttpInterceptorService);
        expect(service).toBeTruthy();
    });

    it('should get http 404', () => {
        const http: HttpClient = TestBed.get(HttpClient);

        http.get('/fake-route').subscribe((response: any) => {
            expect(response).toBeTruthy();
            expect(response.status).toEqual('404');
        });
    });
});

so I'm testing if i get a 404 successfully but I have no idea how to test if the interceptor is repeating the 2 extra times.

Edit

Actualy I was wrong, not even my 'should get http 404' test is working correctly, it's just always giving a false positive.

Edit 2

I believe I'm getting closer, the 404 is now working properly and I've added a test for the "retrying" but it's still not working as expected I think the interceptor is probably not even being called...

it('should repeat failed request 2 more times', () => {
    const emsg = 'deliberate 404 error';

    jasmine.clock().install();
    spyOn(httpClient, 'get').and.callThrough();

    expect(httpClient.get).not.toHaveBeenCalled();

    httpClient.get(fakeUrl).subscribe(
    (response) => {
      fail('should have failed with the 404 error');
    },
    (error) => {
      expect(error.status).toEqual(404, 'status');
      expect(error.error).toEqual(emsg, 'message');
    });

    jasmine.clock().tick(3000);

    expect(httpClient.get).toHaveBeenCalledTimes(3);

    jasmine.clock().uninstall();
});

and this test fails with "Expected spy get to have been called 3 times. It was called 1 times"

Upvotes: 2

Views: 1358

Answers (1)

FabioG
FabioG

Reputation: 2986

OK, finally figured it out, my latest approach (Edit 2) was not the right one either. Here's my final and working test for the repeating:

it('should handle 404 with retry (2 times)', () => {
    const emsg = 'deliberate 404 error';

    httpClient.get(fakeUrl).subscribe(
    (response) => {
        fail('should have failed with the 404 error');
    },
    (error: HttpErrorResponse) => {
        expect(error.status).toEqual(404, 'status');
        expect(error.error).toEqual(emsg, 'message');
    });

    const retry = 2;
    for (let i = 0, c = retry + 1; i < c; i++) {
        const req = httpTestingController.expectOne(fakeUrl);
        req.flush(emsg, { status: 404, statusText: 'Not Found' });
    }
});

also added an assert to run after every test to make sure that there are no more pending requests:

afterEach(() => {
    httpTestingController.verify();
});

Upvotes: 3

Related Questions