Angular 7 | RxJS : Test finalize()

In the following interceptor, I want to test if the method loaderService.stopLoading() is properly called :

import { Injectable } from "@angular/core";
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Observable } from "rxjs";
import { LoaderService } from "../services/loader.service";
import { finalize } from "rxjs/operators";
@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
/**
* Way to deal with multi request
*/
private activeRequests: number = 0;
constructor(private loaderService: LoaderService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//first request
if (this.activeRequests === 0) {
this.loaderService.startLoading();
}
//increment each request
this.activeRequests++;
return next.handle(request).pipe(
finalize(() => {
//decrement each request
this.activeRequests--;
//stop when last request
if (this.activeRequests === 0) {
this.loaderService.stopLoading();
}
}));
}
}


As you can see this function is called from the finalize() RxJS operator. The unit test for this interceptor is as follow:

import { TestBed, async } from '@angular/core/testing';
import {
HttpClientTestingModule,
HttpTestingController
} from '@angular/common/http/testing';
import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { LoaderInterceptor } from './loader.interceptor';
import { LoaderService } from '../services/loader.service';
import { MockLoaderService } from './../../testing/services/loader.service.mock';
import { Data } from './../../testing/data/util.data';
import { finalize } from 'rxjs/operators';
const testUrl = '/data';
describe('LoaderInterceptor', () => {
describe('intercept', () => {
let loaderService: LoaderService;
let httpClient: HttpClient;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [LoaderInterceptor,
{ provide: LoaderService, useClass: MockLoaderService },
{
provide: HTTP_INTERCEPTORS,
useClass: LoaderInterceptor,
multi: true,
}
],
imports: [HttpClientTestingModule]
});
httpClient = TestBed.get(HttpClient);
httpMock = TestBed.get(HttpTestingController);
loaderService = TestBed.get(LoaderService);
spyOn(loaderService, 'startLoading');
spyOn(loaderService, 'stopLoading');
});
it('When request starts the loader starts and ends as expected', async(() => {
// Make an HTTP GET request
httpClient.get<Data>(testUrl)
.pipe(
finalize(() => expect(loaderService.stopLoading).toHaveBeenCalledTimes(1))
).subscribe(
res => {
expect(loaderService.startLoading).toHaveBeenCalledTimes(1);
});
}));
});
});


Thanks for sharing...

Comments

  1. This test will still be green, even if startLoading and stopLoading are not called. This is because the stuff that happens in the subscribe and finalize block happen after the test is finished. You should use either async or a done-function

    ReplyDelete
    Replies
    1. https://codecraft.tv/courses/angular/unit-testing/asynchronous/

      Delete

Post a Comment

Popular posts from this blog

Spring JPA : Using Specification with Projection

Chip input using Reactive Form