Angular 7 | RxJS : Test finalize()
In the following interceptor, I want to test if the method
As you can see this function is called from the
Thanks for sharing...
loaderService.stopLoading()
is properly called :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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...
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
ReplyDeletehttps://codecraft.tv/courses/angular/unit-testing/asynchronous/
Delete