Having difficulties testing the Angular HTTP interceptor with Karma and Jasmine

Testing an http interceptor has been quite the challenge for me. Despite having my token logged in the console and ensuring that the request URL matches, I still can't figure out why it's not working with the interceptor in place. Interestingly, all my other http services pass without any issues when tested using the same method.

The interceptor class below adds the bearer token to every request successfully. It relies on the Ionic Platform native class, which is mocked during testing:

@Injectable()
export class AddHeaderInterceptor implements HttpInterceptor {

  public constructor(
      private auth: AuthService, private platform: Platform, 
      private config: ConfigurationService
  ) {}

  public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.debug('req', req.url);
    return Observable.fromPromise(this.platform.ready())
      .switchMap(() => Observable.fromPromise(this.auth.getToken()))
      .switchMap((tokens: TokenCacheItem[]) => {
        const baseUrl = new RegExp(this.config.getValue('baseUrl'), 'g');
        if (! req.url.match(baseUrl)) {
          return Observable.of(null);
        }
      
     

The error message "Expected one matching request" keeps popping up no matter what I try. Even when I spy on the `getToken` method from the auth service, it never gets called. This issue persists whether I use absolute or relative URLs in `http.expectOne()`. Any suggestions on how to fix this?

Answer №1

By utilizing the karma done function and directly creating the Addheader object, I was able to find a solution:

fdescribe('AddHeaderInterceptor Service', () => {

  let http: HttpTestingController;
  let httpClient: HttpClient;
  let auth: AuthService;
  let logger: LogService;
  let config: ConfigurationService;
  let platform: Platform;
  let interceptor: AddHeaderInterceptor;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        ConfigurationService,
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AddHeaderInterceptor,
          multi: true,
        },
        { provide: Platform, useClass: PlatformMocked },
        { provide: LogService, useClass: LogServiceMock },
        { provide: AuthService, useClass: AuthServiceMock }
      ],
    });
    config = TestBed.get(ConfigurationService);
    auth = TestBed.get(AuthService);
    logger = TestBed.get(LogService);
    platform = TestBed.get(Platform);
    httpClient = TestBed.get(HttpClient);
    http = TestBed.get(HttpTestingController);
    interceptor = new AddHeaderInterceptor(logger, auth, platform, config);
  });

  fit('should add header to request', (done) => {
    expect((interceptor as any) instanceof AddHeaderInterceptor).toBeTruthy();
    const next: any = {
      handle: (request: HttpRequest<any>) => {
        expect(request.headers.has('Authorization')).toBeTruthy();
        expect(request.headers.get('Authorization')).toEqual('Bearer TESTO');
        return Observable.of({ hello: 'world' });
      }
    };
    const req = new HttpRequest<any>('GET', config.getValue('baseUrl') + 'test');
    interceptor.intercept(req, next).subscribe(obj => done());
  });

});

Answer №2

Encountered a similar situation while implementing the same fromPromise -> switchMap pattern in my interceptor. Testing seemed to be impacted by this, even though the code functioned correctly without any issues. Surprisingly, following your testing solution resolved the issue for me.

The reason behind this behavior remains unknown, but I am grateful for your helpful solution!

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

Executing a function simultaneously in two separate tabs using Angular

I need to conduct a specific test within my web application that requires opening two separate tabs in my browser and running the application in both tabs simultaneously. My goal is to execute the same function at the exact time in both tabs (for example, ...

Issue encountered while testing the PUT/POST functionalities of $resource with $httpBackend

I am currently facing an issue while trying to test a service that has been configured using $resource, which includes various methods such as GET, PUT, and POST. During my tests, I am utilizing $httpBackend, and while the GET requests are successful, I e ...

There seems to be an issue with the subscription of a subject between two modules in Angular 5

Currently, I am in the process of developing a project using Angular 5. One requirement is to display an app loading spinner frequently. To achieve this, I have created a shared module along with a spinner component within it. Below is the content of my mo ...

Got a value of `false` for an attribute `closable` that is not meant to be a

Here's the code snippet I have: import { Modal } from "antd"; import styled from "styled-components"; export const StANTModal = styled(Modal)` & .ant-modal-content { border-radius: 20px; overflow: hidden; } `; And ...

Combining pixijs with TypeScript in Ionic 2 using npm

To begin, I ran the command npm install -g ionic Followed by ionic start pixiApp blank --v2 Navigated to the pixiApp directory with cd pixiApp Installed necessary dependencies using npm install Added a specific version of pixi.js (4.1.0) with npm install p ...

I want to make my code available as an npm library on GitHub, but when users install it, I want them to only get

When pushing the code to GitHub, I also need to include the dist folder. However, when running the command npm i <github-url>, I want the node_modules files to be downloaded and placed inside the dist folder. ...

What does the "start" script do in the package.json file for Angular 2 when running "concurrent "npm run tsc:w" "npm run lite"" command?

What is the purpose of concurrent in this code snippet? "scripts": { "tsc": "tsc", "tsc:w": "tsc -w", "lite": "lite-server", "start": "Concurrent npm run tsc:w npm run lite" } ...

Type guards do not work properly on a union of enum types in TypeScript

Recently delved into the concept of Type Guards Chapter within the realm of Typescript However, I encountered an issue where my basic type guards failed to differentiate a union of enums. Why is this happening? enum A { COMMA = ',', PLUS = & ...

Setting base URLs for production and development in Angular 6: A step-by-step guide

As a beginner in Angular, I am looking for a way to set different base URLs for production and development environments. I aim to dynamically configure the base URL to avoid hard-coding it in the index.html file every time I switch between these two enviro ...

Error: The property 'children' is not found in type '{ children?: ReactNode; }'

I have been working on implementing the search bar feature from the provided link. Despite my efforts to match the types correctly, I keep encountering a TypeScript error. Homepage.tsx const [searchQuery, setSearchQuery] = useState(query || '' ...

Guide on removing a key from an object in TypeScript

My variable myMap: { [key: string]: string[] } = {} contains data that I need to modify. Specifically, I am trying to remove a specific value associated with a certain key from the myMap. In this case, my goal is to delete value1 from myMap[Key1]. Despit ...

Error: The function 'some' is not recognized in the rawData variable in REACT/ANTDESIGN

I've been grappling with this issue for nearly a full day now. Despite exhausting all possible solutions and conducting extensive searches, I'm still stumped. My task is to create a table using ant design where all the users are displayed upon i ...

Ionic datetime returns default values upon initialization

I'm currently in the process of developing an Ionic-Angular-app. I require a datetime component on a page to set the creation date of an object. I am using formGroup for this purpose, but whenever I choose a different date, it always reverts back to t ...

Verify if a given string exists within a defined ENUM in typescript

I have an enum called "Languages" with different language codes such as nl, fr, en, and de. export enum Languages { nl = 1, fr = 2, en = 3, de = 4 } Additionally, I have a constant variable named "language" assigned the value 'de'. My g ...

Azure Blob - uncovering the secrets of your storage activity

Our Angular App is currently being stored in Azure Blob. We are interested in viewing a list of requests that have been made to Azure Blob in the past few hours/days/... We would like to see details such as client IP, timestamp, requested item, transacti ...

Guide to modifying the root directory when deploying a Typescript cloud function from a monorepo using cloud build

Within my monorepo, I have a folder containing Typescript cloud functions that I want to deploy using GCP cloud build. Unfortunately, it appears that cloud build is unable to locate the package.json file within this specific folder. It seems to be expectin ...

Rearrange the layout by dragging and dropping images to switch their places

I've been working on implementing a photo uploader that requires the order of photos to be maintained. In order to achieve this, I have attempted to incorporate a drag and drop feature to swap their positions. However, I am encountering an issue where ...

What is the best way to create a highlighted navigation bar using Angular 2?

Is there a way to keep the navbar active even after refreshing the page in Angular 2? I am currently using CSS to accomplish this, but the active tab is removed upon page refresh. Any suggestions on how to tackle this? HTML:-- <ul class="nav navbar- ...

In order for the expansion parameter to be successfully used, it must be either of tuple type or passed to the

const myFunction = function(arg1: number, arg2: number, arg3: number) {} const myFunction1 = function() {} const obj = { myFunction, myFunction1 }; type FuncType = typeof obj; function executeFunction<T extends keyof FuncType>(key: ...

Using typescript, encountering an issue with dynamic import and json file integration

When creating a function to retrieve test data for multiple environments, I encountered an issue: export class DataHelper { public static async getTestData(fileName: string): Promise<any> { return await import(`../${fileName}`); } } Running ...