Issue with Angular 18 and Jest: Unable to mock signal set method

I have a situation with a component that modifies the value of a signal declared within a service during its initialization. I've been attempting to test this behavior using Jest by spying on the set method of the signal, but unfortunately, I haven't had any success so far. Utilizing Angular 18.2.8 in conjunction with Jest 29.7.0.

Objective: To confirm that the component indeed sets the loading signal to true within its ngOnInit method.

service.ts

import { signal, Injectable } from '@angular/core';

@Injectable()
export class CardStateService {
loading = signal<boolean>(false);
}

component.ts

import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UntilDestroy } from '@ngneat/until-destroy';
import { CardStateService } from './card-state.service';

@UntilDestroy()
@Component({
selector: 'component-card',
templateUrl: './component.html',
styleUrls: ['./component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule],
providers: [CardStateService],
})

export class Component implements OnInit {

stateService = inject(CardStateService);


ngOnInit(): void {
this.stateService.loading.set(true);
}

}

component.spec.ts

import { signal } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MockProvider } from 'ng-mocks';
import { CardStateService } from '../../shared/card-state.service';
import { Component } from './component';

describe('Component', () => {
  let component: Component;
  let fixture: ComponentFixture<Component>;
  let cardStateServiceMock: CardStateService;

  let mockStateService = {
    loading: signal(false),
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [Component],
      providers: [
        MockProvider(CardStateService, mockStateService),
      ],
    });

    fixture = TestBed.createComponent(Component);
    component = fixture.componentInstance;
    cardStateServiceMock = TestBed.inject(CardStateService);
    fixture.detectChanges();
  });

  it('should set loading to true when initializing component', () => {
    const loadingSpy = jest.spyOn(mockStateService.loading, 'set')
    component.ngOnInit();

    expect(loadingSpy).toHaveBeenCalledWith(true);
  });
});

Test result

 Component› should set loading to true when initializing component                                                                                                                                                                                                    

 expect(jest.fn()).toHaveBeenCalledWith(...expected)

 Expected: true

 Number of calls: 0

Answer â„–1

To pass the testcase successfully, we can utilize the whenStable method which returns a promise.

In order to validate our testcase, we should place it within the then block.

it('should set loading to true when initializing App', () => {
  const loadingSpy = jest.spyOn(mockStateService.loading, 'set');
  component.ngOnInit();
  fixture.whenStable().then(() => {
    expect(loadingSpy).toHaveBeenCalledWith(true);
  });
});

Currently, the test case only passes if the expect block is placed inside an asynchronous code block. By using a setTimeout, the test will pass since the asynchronous delay allows for success, whereas synchronous execution causes failure.

it('should set loading to true when initializing App', () => {
  const loadingSpy = jest.spyOn(mockStateService.loading, 'set');
  component.ngOnInit();
  setTimeout(() => { // <- this also passes
    expect(loadingSpy).toHaveBeenCalledWith(true);
  });
});

However, methods such as flushEffects, async await, fakeAsync flush, and detectChanges do not seem to work in this scenario.

Check out the Stackblitz Demo

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

Using Typescript to import a JSON file

Having trouble importing a JSON file into a typescript file using the import statement. I keep receiving the following error message: Error: C:\Users\Treycos\Documents\Personal\Web extensions\LocalTube\src\backgro ...

The Angular single-spa.js framework is altering the URLs of deep imports to localhost

I am currently utilizing the single-spa library (version 5.8.2) in conjunction with multiple Angular projects. Upon attempting to import ngx-quill (a library that itself imports another library, quill.js), I encountered an issue where the single spa librar ...

React TypeScript throws an error when a Socket.IO object is passed to a child component and appears as undefined

Currently, I'm developing a simple chat application as part of my university course. The code below represents a work-in-progress page for this project. While I am able to get the socket from the server and use it in the main component without any is ...

Formatting the Return Values of Ionic Select

Having an issue with Ionic 3. Using an <ion-select> element with ngModel="x". When attempting to display the value in the console, it shows with extra spaces and line breaks. I tried replacing line breaks with 'e' and spaces with 'a&ap ...

How can I upload multiple images in one request using Typescript?

HTML: <div> <input type ="file" (change)="selectFiles($event)" multiple="multiple" /> </div> Function to handle the change event selectFiles(event) { const reader = new FileReader(); if (event.target.files & ...

Disabling `no-dupe-keys` in ESLint does not seem to be effective

Currently, I am working on a project where I have incorporated Typescript and ESLint. However, I have encountered an issue with the error message stating: An object literal cannot have multiple properties with the same name. I am looking to disable this s ...

The mystery of the undefined return value in my Ionic v4 get function

I attempted to retrieve my location by saving the latitude and longitude, but my declared variable isn't returning anything. Take a look at my code snippet: public device_location: any = {}; constructor(private geolocation: Geolocation) { this.s ...

A guide on using tsc to build a local package

Unique Project Structure I have a unique monorepo structure (utilizing npm workspaces) that includes a directory called api. This api directory houses an express API written in typescript. Additionally, the api folder relies on a local package called @mya ...

Retrieving the component's values when utilizing the `<ng-content>` directive

Seeking a technique for accessing the values of a component when utilizing <ng-content>: import {Component} from '@angular/core'; @Component({ selector: 'home-page', template: `<person-box>{{name}}</person-box> & ...

What is the process for transforming a key-value object from JavaScript to TypeScript?

I am currently facing a challenge in converting a JavaScript object into a TypeScript version as part of our code refactoring process :( I am struggling to figure out how to properly migrate a JS JSON object into a correct TS format. For instance, consider ...

Sharing packages within nested scopes

Using @organization-scope/package/sub-package in npm is what I want to achieve. Here is my package.json configuration:- { "name": "@once/ui", ... ... } If I try the following:- { "name": "@once/ui/select-box", ... ... } An error pops up st ...

Using Angular 7 shared service to allow sibling components to exchange data between each other

In my Angular 7 application, I have two sibling components - a configurator component and a custom stepper component. The configurator component is responsible for fetching data from the API and performing calculations on it. I would like to display the ca ...

Issues may arise in TypeScript when you are working with an array of objects along with other properties within a type

I am encountering an issue with an object structure similar to the one below: let Obj = { ['0'] : { mode: 'x' }, getMode: () => 'x' } The problem arises when I attempt to create a type definition as shown here: type Obj = ...

Distribute information to every recipient components using observables in Angular2

I am facing an issue where I want to send data to all elements named 'modal', but only one of them is receiving the message. Here is my service: @Injectable() export class ModalService { private _isOpen = new Subject(); isOpen$ = this._isOpen. ...

What is the best way to convert JSON into a complex object in Typescript and Angular?

In my Typescript class for an Angular version 5 project, I have a JavaScript function that generates a style object. Here is the function: private createCircle(parameters: any): any { return new Circle({ radius: parameters.radius, ...

An issue has occurred: TransformError SyntaxError: Unexpected keyword 'const' was encountered

While practicing programming with React-Native, I encountered a problem that I couldn't figure out how to solve. I attempted to use solutions from various forums, but none of them worked. import { StyleSheet, Text, View, Image } from 'react-nativ ...

Tips on extracting a base64 image from a canvas

I have successfully developed a function that is capable of reading an uploaded image and extracting imageData from the canvas. However, I am encountering difficulty in obtaining the base64 image from that imagedata. Here is my code snippet: function han ...

Altering the insides of a shallow-rendered functional component with React Enzyme

I need to modify a property value within a React component for an enzyme unit test. Specifically, I want to change the ready attribute without rendering any child components using the shallow method. Below is the simplified code for the component: import ...

Uh oh! An issue occurred: Cannot access values of an undefined property (reading 'valueOf')

I am attempting to loop through the JSON data and extract the start time and end time keys. I have tried two different methods in my API code to achieve this. The console.log is not showing any errors, but the other loop method is causing an error to appea ...

After compilation, any variables declared within a module remain undefined

I have declared the following files app.types.ts /// <reference path="../../typings/tsd.d.ts"/> module App{ export var Module = "website"; //---------------Controller Base Types--------------- export interface IScope extends ng.ISco ...