Guidelines for simulating ActivatedRouteSnapshot in observable testing situations

I am currently testing an observable feature from a service in Angular. This particular observable will output a boolean value based on the queryParam provided.

For effective testing of this observable, it is essential to mock the queryParam value.

However, the expectations set up in the test file are returning false for both scenarios because no queryParam value is being received.

Below is the content of the service file:

import { Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class BirdService {
  private readonly _bird$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(this.birdStatus);

  constructor(private route: ActivatedRoute) {}

  public get bird$(): Observable<boolean> {
    return this._bird$.asObservable();
  }

  private get birdStatus(): boolean {
    const isBird = this.route.snapshot.queryParamMap.get('bird') === 'true';
    if (isBird) return true;
    return false;
  }
}

And here is the corresponding test file:


import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';

import { BirdService } from './birdService.service';


describe('BirdService', () => {
  let service: BirdService;
  let route: ActivatedRouteSnapshot;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [BirdService],
    });
    route = new ActivatedRouteSnapshot();
  });

  describe('When there is a bird present', () => {
    it('should activate flying mode', (done) => {
      route.queryParams = {
        bird: 'true',
      };
      service = TestBed.inject(BirdService);

      service.bird$.subscribe((value: boolean) => {
        expect(value).toBe(true);
        done();
      });
    });
  });

  describe('When there is NO bird around', () => {
    it('should NOT activate flying mode', (done) => {
      route.queryParams = {
        bird: 'false',
      };
      service = TestBed.inject(BirdService);

      service.bird$.subscribe((value: boolean) => {
        expect(value).toBe(false);
        done();
      });
    });
  });
});

Answer №1

I managed to find a resolution for the issue at hand, just in case someone stumbles upon this post.

describe('BirdService', () => {
  let service: BirdService;
  let route: ActivatedRoute;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        BirdService,
        {
          provide: ActivatedRoute,
          useValue: {
            snapshot: {
              queryParamMap: {
                get: () => 'true',
              },
            },
          },
        },
      ],
    });
    route = TestBed.inject(ActivatedRoute);
  });

  describe('When a bird exists', () => {
    it('should activate flying mode', (done) => {
      service = TestBed.inject(BirdService);

      service.bird$.subscribe((value: boolean) => {
        expect(value).toBe(true);
        done();
      });
    });
  });

  describe('No birds present', () => {
    it('flying mode should remain inactive', (done) => {
      spyOn(route.snapshot.queryParamMap, 'get').and.returnValue('false');

      service = TestBed.inject(BirdService);

      service.bird$.subscribe((value: boolean) => {
        expect(value).toBe(false);
        done();
      });
    });
  });
});

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

How can we effectively map Typescript Enums using their keys without relying on a Map?

Consider the following Enum instances: export enum TopicCategories { GUIDES = 'Guides', TASKS = 'Tasks', CONCEPTS = 'Concepts', FORMULAS = 'Formulas', BLOGS = 'Blogs' } export enum Top ...

Changing the content of an HTTP response with the help of RXJS

My API response includes a payload with various details about the queue and its customers. Here is an example of the payload: { "uid": "string", "queue": { "size": 0, "averageWait ...

Strategies for transferring ngModel data from child components to parent components (child to parent to grandparent)

I am currently working on multiple parent components that utilize template-driven forms: user-data.components.ts admin-data.components.ts customer-data.components.ts Each of these parent components have form elements that are child components utilizing NG ...

Differentiating Typescript will discard attributes that do not adhere to an Interface

Currently, I am working with an API controller that requires a body parameter as shown below: insertUser(@Body() user: IUser) {} The problem I'm facing is that I can submit an object that includes additional properties not specified in the IUser int ...

ESLint has issued a warning indicating that the selector must be utilized as an element

Running Angular 12 and ESLint together has raised some issues for me. Whenever I run ng lint, ESLint reports a problem with the selector below. 10:13 error The selector should be used as an element (https://angular.io/guide/styleguide#style-05-03) @an ...

Troubleshooting TypeScript compatibility with SystemJS when encountering problems with the .js extension

Initializing my TypeScript file with the import statement below. It's important to note that the lack of a .ts extension indicates that I am importing a TypeScript module: import githubService from './github.service'; Through transpilation ...

How can I update a dropdown menu depending on the selection made in another dropdown using Angular

I am trying to dynamically change the options in one dropdown based on the selection made in another dropdown. ts.file Countries: Array<any> = [ { name: '1st of the month', states: [ {name: '16th of the month&apos ...

Why are the inputs and dropdowns not disabled until you press the Edit button as intended?

My HTML file: <div class="main-wrapper" fxLayout="row" fxLayoutAlign="center center"> <mat-card class="box"> <mat-card-header> <mat-card-title>Register</mat-card-title> & ...

The items in the Bootstrap dropdown are not displaying

I am currently working on a project using Angular 12, and I encountered an issue with my Bootstrap dropdown menu not displaying any items. Below is the HTML code snippet causing the problem: <nav class="navbar navbar-expand navbar-dark"> ...

IonInput and IonLabel are not adjacent to each other

I'm encountering an issue with this code snippet <ion-list> <ion-list-header> Input list: </ion-list-header> <ion-item *ngFor="let att of anArray; let idx = index"> <ion-label color="primary" flo ...

Verify user using Cognito user pool log-in information

Is it possible to authenticate a user using only user pool credentials without an identity pool/IdentityPoolId? Check out this link for more information: https://github.com/aws/amazon-cognito-identity-js The example provided in the link above specifically ...

Removing buttons from a table row dynamically

Below is how I am adding the Button to Element: (this.sample as any).element.addEventListener("mouseover", function (e) { if ((e.target as HTMLElement).classList.contains("e-rowcell")) { let ele: Element = e.target as Element; let ro ...

Issue with Angular Route Guard - Incorrect redirection to login page

I'm encountering an issue with my Angular app where even after the JWT token has expired, I am still able to navigate within the application without any API data being accessible. I've double-checked my setup and it seems right, but for some reas ...

Combining conditions with concatenation in [ngClass]: A step-by-step guide

My dilemma involves a div that I want to blur or reduce opacity on mouse enter. To achieve this, I've defined two CSS classes: .blur and .less-opacity CSS Stylesheet .blur { -webkit-filter: blur(10px); -moz-filter: blur(10px); -o-filter ...

Retrieving data from an Array

I've encountered a peculiar issue while working on a test project. It seems that I am unable to access values in an array. pokemonStats$: Observable<PokemonStats[]>; getPokemonStats(id: number): any { this.pokemonStats$ .pipe(take(1)) .subscrib ...

Angular 2 wrap-up: How to seamlessly transfer filter data from Filter Component to App Component

A filtering app has been created successfully, but there is a desire to separate the filtering functionality into its own component (filtering.component.ts) and pass the selected values back to the listing component (app.ts) using @Input and @Output functi ...

Error message: "Declared app-routing module in Angular 2 is encountering routing declaration

Currently, I am immersing myself in learning Angular 2 through the official tutorial available at https://angular.io/docs/ts/latest/tutorial/toh-pt5.html. However, I have encountered an issue related to routing. The error message displayed states: Type Das ...

Angular 2: Capturing scroll events from the parent element within a Directive

One of the challenges I encountered is with a directive called [appInvalidField] that functions like a custom tooltip for validation purposes. To ensure it appears above everything else within dialogs, I attach it to the body and position it near the relev ...

Tips for creating a test to check if an HTML element is passed as a prop to a component and a function is triggered from it

What is the process for unit testing the code provided below and how can a test be written for it? I am looking to trigger the handler function in order to simulate a click from the Button that is passed to the footer prop of the Popover component. impor ...