Testing Angular: How to Unit-test HttpErrorResponse with custom headers using HttpClientTestingModule

In the code snippet below, I am attempting to find a custom header on error:

login(credentials: Credentials): Observable<any> {
    return this.http.post(loginUrl, credentials)
        .pipe(
            catchError((httpErrorResponse: HttpErrorResponse) => {
                let error = new Error('', httpErrorResponse.status);

                ...
                if (httpErrorResponse.headers.get('customHeaderName')) {
                    error.message = 'Appropriate Response';
                }
                ...
                return throwError(error);
            })
        );
}

While using HttpClientTestingModule, I am trying to test the above code with the following test case:

it('should catch error with custom header', (done) => {
    authService.login(credentials)
        .subscribe({
            next: null,
            error: (error: Error) => {
                expect(error.message).toEqual('Appropriate Response');
            }
        });

    httpMock.expectOne({
        url: apiUrl,
        method: 'POST'
    }).flush([], {status: 403, statusText: 'Forbidden', headers: {'customHeaderName': 'customHeaderValue'}});

    done();
});

One issue I encountered is that while status and statusText are as expected, the headers are not included, so the if block is not activated.

Any thoughts on this?

Answer №1

Everything seems to be functioning correctly. Below is a practical example using angular version 11 and above

For instance:

auth.service.ts:

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

type Credentials = any;

@Injectable()
export class AuthService {
  constructor(private http: HttpClient) {}
  login(credentials: Credentials): Observable<any> {
    const loginUrl = 'http://localhost:3000/login';
    return this.http.post(loginUrl, credentials).pipe(
      catchError((httpErrorResponse: HttpErrorResponse) => {
        let error = new Error('' + httpErrorResponse.status);
        if (httpErrorResponse.headers.get('customHeaderName')) {
          error.message = 'Appropriate Response';
        }
        return throwError(error);
      })
    );
  }
}

auth.service.spec.ts:

import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { AuthService } from './auth.service';

fdescribe('60381453', () => {
  let authService: AuthService;
  let httpMock: HttpTestingController;
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [AuthService],
    });
    authService = TestBed.inject(AuthService);
    httpMock = TestBed.inject(HttpTestingController);
  });
  it('should catch error with custom header', () => {
    const credentials = { password: '123', email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="126677607761733c66777c7552776a737f627e773c717d7f">[email protected]</a>' };
    const apiUrl = 'http://localhost:3000/login';
    authService.login(credentials).subscribe({
      next: null,
      error: (error: Error) => {
        expect(error.message).toEqual('Appropriate Response');
      },
    });

    httpMock.expectOne({ url: apiUrl, method: 'POST' }).flush([], {
      status: 403,
      statusText: 'Forbidden',
      headers: { customHeaderName: 'customHeaderValue' },
    });
  });
});

unit test result:

https://i.sstatic.net/vcal2.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An error occurs when attempting to use object mapping and the rest operator in a return statement due to

I've encountered a type mismatch error in my TypeScript project using Prisma while attempting to return an object with mapped properties in the getPool method. Let's take a look at the code snippet causing the issue: public async getPool({ id, v ...

Avoid unnecessary re-rendering of React Native components with each update of the state

I need my component to display either A or B based on the user's proximity to a specific location. I developed a custom hook to determine if the user is nearby. However, I'm facing an issue where the hook constantly returns a new value of true, ...

Please ensure the subscription has completed before proceeding with the loop

I am currently working on an Angular application that retrieves data from an API and uses one of its parameters from a looped array. The issue I'm facing is that the data is pushed in a random order due to the continuous looping without waiting for th ...

How can the id from a post response be obtained in Angular 7 when using json-server?

When utilizing the http options below: const httpOptions: any = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }), observe: 'response' }; I execute an http post to a json-server endpoint like this: ...

Wait until a svelte store value is set to true before fetching data (TypeScript)

I have implemented a pop-up prompt that requests the user's year group. Since I have databases for each year group, I need to trigger a function once the value of userInfo changes to true. My JavaScript skills are limited, and my experience has been ...

Instructions on how to link a button to display and conceal content when clicked

I'm working on a project with a list of headers and paragraphs, and I want to create a button that will show or hide the paragraph when clicked. However, I'm struggling with getting the paragraph to hide again when the button is clicked a second ...

The exported instance of sequelize is missing in the Module imports

Good evening! I currently have an express server with a main script that includes the following export: export const sequelize = new Sequelize( 'postgres', config.db_user, config.db_password, { host: 'localhost', port: config ...

Why bother specifying types when extending tsconfig?

Having an angular app that utilizes @types and custom typings, I am facing an issue where the app works when served but encounters errors during testing with ng test. It is puzzling to me why this discrepancy exists, and I am struggling to comprehend the r ...

The requested resource on localhost does not have the 'Access-Control-Allow-Origin' header

I'm having trouble connecting to the Ebay API from my local server. Every time I try, I encounter this error message: The requested resource does not have the 'Access-Control-Allow-Origin' header. This means that the origin 'http://l ...

Exploring Data in Angular 2: Examining Individual Records

I am currently learning Angular and facing some challenges in structuring my questions regarding what I want to achieve, but here is my query. Within a component, I am retrieving a single user record from a service. My goal is to display this user's ...

Best practices for utilizing forwardRef and next/dynamic in next.js version 13.4 with the "react-email-editor" component

I've been attempting to utilize the "react-email-editor" library in a Next.js project. My goal is to copy the email content generated within the editor to the clipboard. Since the library relies on browser interaction and the use of the "window" objec ...

The completion of RxJS forkJoin is not guaranteed

After subscribing to getAllSubModules, forkJoin executes all the observables without any errors but fails to complete. Even though forkJoin should only complete after all its observables have completed, I'm seeing '-----' printed 3 times in ...

What is the best way to intentionally make a Node unit test fail when catching a Promise rejection?

When conducting unit tests with Node.js, I encountered a scenario where I needed to intentionally fail a test within a promise's catch block: doSomething() .then(...) .catch(ex => { // I need this test to fail at this point }); ...

What is the best way to implement NgClass on a single iteration within NgFor while utilizing parent/child components?

My goal is to toggle the visibility of tiered buttons when a parent button is clicked. I am using ngFor to generate three buttons on tier 1, but I'm struggling to select only the desired tier when clicked instead of affecting all of them. I've m ...

Adjust the dimensions of an Angular Material 2 dialog by updating the width or height

Is there a way to adjust the dimensions of an open Angular Material 2 dialog, either its width or height? I attempted to modify the size of the dialog by obtaining a reference to it and using the updateSize method within the dialog. Unfortunately, I belie ...

Error in Typescript occurrence when combining multiple optional types

This code snippet illustrates a common error: interface Block { id: string; } interface TitleBlock extends Block { data: { text: "hi", icon: "hi-icon" } } interface SubtitleBlock extends Block { data: { text: &qu ...

Mongoose does not compare BCRYPT passwords that are empty

I'm currently working on incorporating bcrypt into my mongoose model using typescript. Referencing this link as a guide. However, since my project is in typescript, I'm unable to directly use the provided code. I'm confused about how they&a ...

Zod implements asynchronous validation for minimum, maximum, and length constraints

When working with Zod, setting values can be done as shown below: z.string().max(5); z.string().min(5); z.string().length(5); However, in my scenario, the values (e.g., 5) are not predetermined. They are fetched from an API dynamically. How can I create t ...

The functionality of Angular material input fields is compromised when the css backface property is applied

I utilized this specific example to create a captivating 3D flip animation. <div class="scene scene--card"> <div class="card"> <div class="card__face card__face--front">front</div> <div class="card__face card__face--ba ...

Encountering a 500 error code while attempting to send a post request using Angular

Whenever I attempt to send a post request to Django server, I encounter a 500 (Internal Server Error) response. Interestingly, the get and put requests work flawlessly on the same server where Django is connected to PostgreSQL database. Here is a snippet ...