Logo

dev-resources.site

for different kinds of informations.

How to Unit Test Error Response Handling in Angular

Published at
9/13/2023
Categories
testrequest
httptestingcontrolle
angular
unittesting
Author
seanbh
Author
6 person written this
seanbh
open
How to Unit Test Error Response Handling in Angular

In this post we’ll quickly see how to mock an error response in order to test that an HttpInterceptor is redirecting to a login page when a 401 status code is returned.

Testing the Redirect

First, in order to test a redirect, we create a redirect method:

redirect(href: string) {
  // don't redirect if localhost:9876 (for unit tests)
  if (window.location.href.indexOf('http://localhost:9876') === -1) {
    window.location.href = href;
  }
}
Enter fullscreen mode Exit fullscreen mode

This is so that we can monitor when a redirect is requested and also not actually redirect during the unit test. You would need to change the port to whatever you are using, but 9876 is the default for Karma.

Testing for the Error Response

Now we need to setup the beforeEach for the tests:

const redirectFunctionName = 'redirect';
const user = getTestUser();
let httpTestingController: HttpTestingController;
let httpClient: HttpClient;
let appConfig: AppConfig;
let globalErrorHandlerService: GlobalErrorHandlerService;

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
    providers: [
      AuthInterceptor,
      { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
      { provide: APP_CONFIG, useValue: { apiHost: 'https://mockhost/api' } },
      provideMockStore({
        initialState: { user: { currentUser: user } },
      }),
    ],
  });
  httpTestingController = TestBed.inject(HttpTestingController);
  httpClient = TestBed.inject(HttpClient);
  appConfig = TestBed.inject(APP_CONFIG);
  globalErrorHandlerService = TestBed.inject(GlobalErrorHandlerService);
});
Enter fullscreen mode Exit fullscreen mode

I’ve covered most of this code in detail in a previous post. The only significant change here is the injecting of the GlobalErrorHandlerService, which is just the service where I put the redirect method.

Now we implement the test to see if the redirect method is called when a 401 response is received.

First we arrange the test by setting the URL and a creating a spy for the GlobalErrorHandlerService, so that we can check whether or not the redirect method was called.

it('should redirect to login when 401 response received', () => {
  //arrange
  const url = `${appConfig.apiHost}/mockendpoint`;
  const redirectSpy = spyOn(globalErrorHandlerService, redirectFunctionName);

  //act

  //assert
});
Enter fullscreen mode Exit fullscreen mode

Next we perform the action to be tested. We make the call using httpClient.get, but it’s not actually going anywhere across the wire because we imported the HttpClientTestingModule, so that all HTTP requests will hit the HttpClientTestingBackend.

//act
httpClient.get(url).subscribe();
Enter fullscreen mode Exit fullscreen mode

Now comes the important part and the crux of this post, which is simulating the error response.

By calling httpTestingController.expectOne(url), we are doing two things. We are getting the mock test request while also setting the expectation that the (mock) call will be made exactly one time. If it is not made exactly one time the test will fail.

const mockRequest = httpTestingController.expectOne(url);
Enter fullscreen mode Exit fullscreen mode

Now that we have the mock test request we can simulate a response. This can be done with the flush method or in our case, the error method, since the error is all we are interested in.

The error method expects a ProgressEvent which takes a type argument which is not important for our purposes. We’re interested in the second argument to the error method which is of type TestRequestOptions. In those options we can specify that the status of the response is 401.

mockRequest.error(new ProgressEvent('error'), { status: 401 });
Enter fullscreen mode Exit fullscreen mode

Finally, we assert using our spy that the redirect method was called with the URL to the login page, which is where we want to direct our users when we receive a 401.

// assert
expect(redirectSpy).toHaveBeenCalledWith('/login');
Enter fullscreen mode Exit fullscreen mode

Here’s the test in full:

//arrange
const url = `${appConfig.apiHost}/mockendpoint`;
const redirectSpy = spyOn(globalErrorHandlerService, redirectFunctionName);

//act
httpClient.get(url).subscribe();

const mockRequest = httpTestingController.expectOne(url);
mockRequest.error(new ProgressEvent('error'), { status: 401 });

// assert
expect(redirectSpy).toHaveBeenCalledWith('/login');
Enter fullscreen mode Exit fullscreen mode

Finally we add an afterEach function to verify that there are no outstanding requests after each test.

afterEach(() => {
  httpTestingController.verify();
});
Enter fullscreen mode Exit fullscreen mode

I’ll leave as homework adding a test to make sure the redirect method does not get called if the status is not 401.

That’s it! I hope you found this useful.

Bibliography

unittesting Article's
30 articles in total
Favicon
Unit Test vs. Integration Test
Favicon
Improving Productivity with Automated Unit Testing
Favicon
Unit Testing Clean Architecture Use Cases
Favicon
Mastering Unit Testing in PHP: Tools, Frameworks, and Best Practices
Favicon
How to name Unit Tests
Favicon
Choosing the Right Testing Strategy: Functional vs. Unit Testing
Favicon
How To Improve Flutter Unit Testing
Favicon
Introduction to Jest: Unit Testing, Mocking, and Asynchronous Code
Favicon
Unit Testing React Components with Jest
Favicon
How to add E2E Tests for Nestjs graphql
Favicon
Effective Unit Testing Strategies
Favicon
Part 2: Unit Testing in Flutter
Favicon
Part 1: Unit Testing in Flutter: Your App's Unsung Hero
Favicon
Python unit testing is even more convenient than you might realize
Favicon
The Complete Guide to Integration Testing
Favicon
Elevating Game Performance: Comprehensive Guide to Unity Game Testing
Favicon
Python: pruebas de unidad
Favicon
How to Measure and Improve Test Coverage in Projects?
Favicon
Flutter Widget Testing: Enhancing the Accuracy and Efficiency of Your App Testing
Favicon
How to Test a Functional Interceptor in Angular
Favicon
Unit testing with OCaml
Favicon
How to Unit Test Error Response Handling in Angular
Favicon
Unit Testing with Mocha: A Hands-On Tutorial For Beginners
Favicon
🧪 **Demystifying Kotlin Unit Testing**: Your Odyssey to Code Confidence! 🚀
Favicon
How to Unit Test an HttpInterceptor that Relies on NgRx
Favicon
The power of the unit tests
Favicon
Explain Unit testing techniques in software testing
Favicon
Node.js Unit Testing for the Fearless Developer: A Comprehensive Guide
Favicon
JEST Started with Unit Testing
Favicon
Testing Redux with RTL

Featured ones: