Testing Angular HTTP Communication

Author
Igor Afanasov
Publication Date
10 October 2019

Testing Angular HTTP Communication

Angular has great built-in tools for making web requests. It also contains a great module for testing HTTP communication: HttpClientTestingModule. This module contains full toolbox to ensure web communication happens as intended by the developer. Let’s explore HttpClientTestingModule and get to know how to:

  • test HTTP requests
  • emulate response
  • handle errors
  • test HTTP interceptors

Testing HTTP requests

Let’s make a simple app that shows a list of repositories starred by a GitHub user. It will consist of an input field for the user name, a button to make a request and a table to show results. To make things look pretty, let’s use bootstrap.

We need to make web requests when a user clicks on the “show” button. Let’s set up a test suit and create a test to make sure a web request happens.

Angular is equipped with a great HTTP testing toolbox. HttpClientTestingModule is a ready to go container for all the tools we need for HTTP testing. It provides HttpTestingController - an injectable service to manage HTTP requests. HttpTestingController exposes information about all HTTP requests that happen during the execution of a test. We can inject an instance of it as with any other injectable service.

Let’s do the setup code.

code
Now time to write the first test. The endpoint to retrieve all the repos which are starred by the user is https://api.github.com/users/:userName/starred. When a user clicks on the button we expect this request.

code 2
HttpTestingController contains two expectation methods: expectOne and expectNone. Both have a couple of overloads with different parameters to recognize specific requests. The name of methods perfectly describes what they do - expect none or only one specific request. If an expectation is not met, an exception is thrown. Jasmine requires an “expect” statement. To make the test pass with a green mark we put expect().not.toThrow().

And now the HTML and the request code.

code 3

code4
Emulating response

We have an HTTP request. We need to show the results of this request in a table. First, we need to save the response to a property that will be reachable in the view. Let’s create that property in the component and write a test to check if the response is saved to the newly created property.

Github provides a lot of information about the repo. We will use just a couple of fields. Let’s create a simple typescript interface that knows just the properties we need.

code5

While using HttpClientTestingModule all the responsibility for managing HTTP responses moves to the developer. Unless the response is explicitly sent in the test code, the component or service will not run the code that reacts to the response. To send a response we need to grab a reference to the TestRequest and call the method flush providing the response parameters.

code6

For our scenario, we just need to provide a response body. In other scenarios response could contain headers, files, specific status text or status codes, etc. The flush method has a reach signature providing a developer with the ability to fine grain the response.

Now let’s write a code to make the test pass.

code 7

Test passed and after the simple HTML markup we created, we are able to see some UI.

Error handling

If GitHub does not know the user, the API returns a 404 status code. Let’s handle this situation and show a friendly error message.

To send an error instead of a successful response we need to leverage the error method of TestRequest. Let’s do 2 tests - one to check if the error message is shown when a request fails and one to check if it is hidden when the request succeeds.

code 8

The error method also has a reach signature to fine grain the response. For our scenario we don’t need much - we just need to send any response with an error. Now let’s write the code to make the tests work.

code 9

code 10

HttpInterceptor

HttpInterceptor allows the execution of code when each request happens. It could also modify the HTTP request itself. GitHub API can return different responses depending on the Accept header. Let’s say we want to set the Accept header to “application/vnd.github.v3+json” for all the requests to GitHub API. The best way to do this would be to leverage HttpInterceptor.

To make the interceptor process requests we need to add it into the providers array of the module where the interceptor is needed. That means for testing we need to provide it in the TestingModule configuration.

code 11

Let’s first write the tests. As we need to have Accept header with all the HTTP requests in the test, we will create a simple request to the URL starting from https://api.github.com/ and check if it contains an Accept header. One more test will check if the request to non GitHub API URL does not contain the header.

code 12

Instead of using the expectOne method, we get the request by Verb. It’s more convenient since we don’t care about the URL. Now all that is left is to write our interceptor code.

code 13

Summary

In this article, we learned how to test the HTTP requests, mock HTTP responses and HTTP errors, test HTTP interceptors. Fully equipped to handle the testing of HTTP communication in an Angular app.

Explore the source code used in this article of play with stackblitz.

Author Information

igor1I started to do production software development at university third grade. Right after university I joined Microsoft consulting service and worked with outstanding professionals on big projects in insurance, banking, telecommunication industries. Next step was a Russian product company which name could be translated as “First Forma”. Here I learned the importance of automated tests of software. I joined as a senior full stack engineer and after a year became the manager of RnD department. Year after decided it’s time to travel. I prepared a proper replacement for my position and switched to a frontend development. I worked as a freelancer while traveling the Europe and Asia. It was happy time. I absorbed different cultures. After 1,5 years of nomadic life I decided to built a strong foundation for a life and stopped in the Netherlands, in a multicultural company Mobiquity.

Follow Mobiquity on Medium to receive a notification on the follow up article we will publish soon. 


Follow along!

@brain-bites

@IAfanasov

Let our expertise complements yours

We believe that addressing customer challenges gives you opportunities to delight. Using our proprietary Friction Reports and  strong industry expertise, we dig deep into customer sentiment and create action plans that remove engagement roadblocks. The end result is seamless, relevant experiences that your customers will love.