DEV Community

Cover image for Intercepting Http Requests-- Using And Testing Angular's HttpClient

Intercepting Http Requests-- Using And Testing Angular's HttpClient

Alisa on August 28, 2017

The HttpClientModule, which debuted in Angular 4.3, is an easy to use API. It automatically expects json as its default response type, builds in th...
Collapse
 
husseinkorly profile image
Hussein Koprly

Great explanation,
I was trying to test my interceptor and I'm acquiring an access token in the interceptor and attach it to the request like this:
`return authService.acquireToken(source).mergeMap(//somecode);
I'm having problem with mergeMap, I'm not sure how to mock this part ?
Any idea ?

Collapse
 
alisaduncan profile image
Alisa

Thanks, I'm glad you liked it.

I'm assuming you are mocking the authService's acquireToken method. If so, you shouldn't need to mock mergeMap.

I don't know your use case, but if the mergeMap is complicated, should it be part of acquireToken (or pulled out differently) so that it can be tested independently? It sounds like you might have a lot going on in the interceptor.

Best wishes on your project!

Collapse
 
husseinkorly profile image
Hussein Koprly

Thank you Alisa,

yes, I'm trying to mock the auth service which calls acquireToken method that is part of the adal.js library. Because of the method returns an Observable, so I'm chaining mergeMap to acquireToken in order to wait to get the token.

I will try to take it out of the interceptor to make the test easier.

Thanks again

Collapse
 
dseelinger profile image
Doug Seelinger

How timely! Need this info for a current customer and besides the Angular docs (which is pretty thin on this particular topic), there's not much else out there on this. You'd think everyone would need to test their services that use the HttpClient.

Collapse
 
alisaduncan profile image
Alisa

Thanks! I agree with Angular docs being thin on testing. There's some info out there and I can look at Angular's repos for guidance but there's not enough examples of tests for applications. Angular's tests are specific to the framework functionality.

Good luck on your project!

Collapse
 
yannbertrand profile image
Yann Bertrand

Thanks, Alisa, for that article.

I really don't like the way we have to do that in Angular. For those who didn't try it out, let me explain what happen in terms of timeline:

  • .subscribe() launch a request and give a callback to be called once we get the response.
  • .expectOne() verify that an endpoint has been called
  • .flush() respond to that request
  • the subscribe callback gets called, and we can finally verify that we have a correct answer.

By the way, the order of the code is really important, if you move just one line of it, the test breaks.

In my sense, we should be able to write it like:

  • describe that when a request to /whatever is sent, we pass a mock answer (or throw if that's what we want to test)
  • launch the request
  • verify the answer

That would be way easier to explain to people and let us put our mocked request => response in a beforeEach!

How do you feel about it?

Collapse
 
alisaduncan profile image
Alisa

Hi there! Sorry it took me so long to respond; I didn't see this comment until now. 😬

I hear what you're saying, it is a lot of steps and I've made the mistake of not calling .flush() when testing myself. However, I do like that Angular's HttpClientTestingModule allows me to verify expected number of times a call is made without using a Jasmine spy. I also like that I can verify the HTTP method used in the call, headers, etc separately from verifying the subscribe portion.

For more complicated service calls (where there's retries, different HTTP methods, or custom headers), being able to assert separately starts making more sense.

For straightforward requests like what I have in this post, having an all-in-one solution like what you propose is a great way to go and definitely helps to make things easier. 🙂

Thank you for taking the time to read and comment! These kinds of discussions are great!

Collapse
 
akojimsg profile image
EI Akoji • Edited

Great post Alisa! I had a hard time working with services that make http request. Your solution is a very good starting point. For services that make multiple http request, I am taking a look at - angular.io/guide/http#handling-mor.... Do you have anything on this?

Collapse
 
mohitvaidh profile image
Mohit

My interceptor is like:

return next.handle(request).catch((error) => {
...
...
...
return Observable.throw(error);
}

in the service test I am unable to assert this error. Any advise?

Collapse
 
sizenineelm profile image
Neil Menzies

Thanks for the article - wanted to unit test an HttpInterceptor, and this provided the perfect template.

Collapse
 
alisaduncan profile image
Alisa

Thank you for your kind words!

Collapse
 
rossler123 profile image
Markus Rossler

I would like to change a successful HttpResponse to an simulated error, returning an HttpErrorResponse. Any hint? I already tried mapping the event to an error. No success...

Collapse
 
alisaduncan profile image
Alisa

Are you trying to simulate an error response in the service or in the interceptor (for intercepting responses)?

Collapse
 
rossler123 profile image
Markus Rossler

Our server api has some special behaviour, in some cases it replies with an http error instead of a http 200 response with a proper body. This is legacy code, but on purpose. Not to break anything we need to handle with that. Since these are rare cases i want to simulate that and reuse it for unit tests as well.

Thread Thread
 
alisaduncan profile image
Alisa

In a unit test you can simulate errors. Does something like this work for you?
github.com/alisaduncan/tutorial-an...

Collapse
 
hndk profile image
G. Más

Thank you so much! This is one of the most helpful articles I found on this topic. Super clear!

Collapse
 
alisaduncan profile image
Alisa

Thank you! I'm glad you found it helpful!