Tips for simulating a getter parameter value from a fake service

Despite referring to this Stack Overflow post, it doesn't seem to be relevant to my situation.

In my scenario, I have a service named AnimationService, which relies on another service called AnimationStateService. The AnimationStateService contains a getter method called state that I want to mock in my test case. Here is how my test is set up:

animation.service.spec.ts

describe("AnimationService", () => {

let animationService: SpyObj<AnimationService>;
let animationStateService: SpyObj<AnimationStateService>;

beforeEach(() => {

    const spyAnimationStateService = createSpyObj("AnimationStateService", ["changeStatus"]);

    TestBed.configureTestingModule({
        providers: [
            AnimationService,
            {provide: AnimationStateService, useValue: spyAnimationStateService}
        ]
    });

    animationStateService = TestBed.get(AnimationStateService);
    animationService = TestBed.get(AnimationService);
});

fit("should call changeStatus if status is AnimationStatus.Stopped", () => {
    // Arrange
    // animationStateService.status.and.returnValue(AnimationStatus.Stopped); - Doesn't work
    // spyOnProperty(animationStateService, "status").and.returnValue(AnimationStatus.Stopped); - Doesn't work
    // animationStateService.status = AnimationStatus.Stopped; - Works, but with TSLint error

    // Act
    animationService.start();

    // Assert
    expect(animationStateService.changeStatus).toHaveBeenCalled();
   });
});

animation-state.service.spec.ts

@Injectable()
export class AnimationStateService {

public get status(): AnimationStatus { return this.state.animation.status; }
...
}

When attempting to mock the getter using:

animationStateService.status.and.returnValue(AnimationStatus.Stopped);

or:

spyOnProperty(animationStateService, "status").and.returnValue(AnimationStatus.Stopped);

It did not work as expected. The getter did not return the value that was set.

This method works:

animationStateService.status = AnimationStatus.Stopped;

however, it triggers a TSLint error:

Cannot assign to 'status' because it is a constant or a read-only property.

Therefore, I am currently unsure of what other approaches I should consider to properly mock the getter without encountering errors.

Answer №1

Utilize the spyOnProperty(obj, propertyName, accessTypeopt) → {Spy} method with the third parameter, accessType, to set up a spy on the getter method.

For example:

animation.service.ts:

import { Injectable } from '@angular/core';
import { AnimationStateService } from './animation-state.service';

@Injectable()
export class AnimationService {
  constructor(private animationStateService: AnimationStateService) {}
  start() {
    return this.animationStateService.status;
  }
}

animation-state.service.ts:

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

export enum AnimationStatus {
  Stopped = 'Stopped',
  Started = 'Started',
}

@Injectable()
export class AnimationStateService {
  state = {
    animation: {
      status: AnimationStatus.Started,
    },
  };
  public get status(): AnimationStatus {
    return this.state.animation.status;
  }
}

animation.service.spec.ts:

import { TestBed } from '@angular/core/testing';
import {
  AnimationStateService,
  AnimationStatus,
} from './animation-state.service';
import { AnimationService } from './animation.service';

fdescribe('53333050', () => {
  let animationStateService: AnimationStateService;
  let animationService: AnimationService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [AnimationService, AnimationStateService],
    });

    animationStateService = TestBed.get(AnimationStateService);
    animationService = TestBed.get(AnimationService);
  });

  it('should call changeStatus if status is AnimationStatus.Stopped', () => {
    // Arrange
    const statusGetterSpy = spyOnProperty(
      animationStateService,
      'status',
      'get'
    ).and.returnValue(AnimationStatus.Stopped);

    // Act
    const actual = animationService.start();
    expect(actual).toEqual(AnimationStatus.Stopped);

    // Assert
    expect(statusGetterSpy).toHaveBeenCalled();
  });
});

Here is the unit test result:

https://i.sstatic.net/qLFF7.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

How is it that in TypeScript, a potential numeric value in an interface can be transformed into an impossible numeric value in a class implementation?

Encountered a surprising behavior from the TypeScript compiler today. Unsure if it's a bug or intentional feature. If it is indeed intentional, I would like to understand the reasoning behind it. The issue arises when declaring an interface method wi ...

Has anyone made the switch from using exports and require in Typescript to consolidating everything into a single file output?

When we first started our TypeScript project, we used external modules with "require Foo = ('./Foo')" which proved to be very organized and useful. However, it required us to use requirejs (AMD modules) or a similar method. While this wasn't ...

a dedicated TypeScript interface for a particular JSON schema

I am pondering, how can I generate a TypeScript interface for JSON data like this: "Cities": { "NY": ["New York", [8000, 134]], "LA": ["Los Angeles", [4000, 97]], } I'm uncertain about how to handle these nested arrays and u ...

When organizing data, the key value pair automatically sorts information according to the specified key

I have created a key value pair in Angular. The key represents the questionId and the value is the baseQuestion. The baseQuestion value may be null. One issue I am facing is that after insertion, the key value pairs are automatically sorted in ascending ...

Different ways to pass a component function's return value to a service in Angular

On my HTML page, I am presenting job details within Bootstrap panels sourced from a JSON array using an ngFor loop. Each panel showcases specific job information along with a unique job ID. The panel is equipped with a click event which triggers the execut ...

"Encountering a build failure in Next.js when using getStaticProps because a parameter is returning undefined

An unusual error has recently surfaced, causing our builds to fail, Located within the pages directory is a post/[id].tsx file that utilizes getStaticProps and getStaticPaths -- props export const getStaticProps: GetStaticProps = async ({ params }) => ...

What is the best way to shorten text in Angular?

I am looking to display smaller text on my website. I have considered creating a custom pipe to truncate strings, but in my situation it's not applicable. Here's what I'm dealing with: <p [innerHTML]="aboutUs"></p> Due to t ...

How can I retrieve the value of a promise in Promise.map?

I am currently working on a project that involves saving data to a database using Mongoose. One specific field in the database is the 'thumbnail' field, which needs to be filled with a base64 converted file after the file is uploaded to the serve ...

Pagination in Laravel using Angular 5

Currently experiencing pagination issues in an Angular5 and Laravel5 project. The JSON values are as follows: { "products": { "current_page": 1, "data": [ ... ], "first_page_url": "http://localhost:8000/api/ ...

The error message "Error: Unable to access property '_router' when null in NativeScript"

Currently, I am developing an android application using a combination of NativeScript, AngularJS2, and TypeScript. To guide my development process, I have been following the documentation provided by NativeScript, which can be found at this link. However, ...

A guide on retrieving tooltip text from an Angular 7 application through Selenium extraction

I am facing a challenge while trying to read text tooltip in my Angular 7 application using Selenium. The issue is that the getText method is returning a blank result, and the JavaScript executor is returning null. Here is a link to the image of the DOM e ...

Element is missing the necessary "key" property. (React and TypeScript)

Upon running the following code for reactJS and typescript, I encountered the error below: I have also included the import statement import 'bootstrap/dist/css/bootstrap.min.css'; in Index.tsx. Is there a solution to resolve this issue? npm s ...

Angular2 is designed to break down complex applications into smaller, more manageable parts

Need for a Solution Recently, I was given responsibility of overseeing a large, legacy web application at work that involves multiple scrum teams and development teams. One major issue we face with this application is that whenever one team makes updates ...

Tips for Angular4: ensuring ngOnDestroy completion before navigation

My task involves managing a list of objects where the user can choose an object to edit using a child component. However, when the user returns to the list component, the child component needs to clean up in the ngOnDestroy method, which includes making a ...

Azure function indicates a successful status despite receiving a result code of 500

I have an Azure function containing some logic with a basic try-catch structure (code shortened). try { // perform logic here that may fail } catch (ex) { context.log(`Logging exception details: ${ex.message}`); context.res ...

FullCalendar mysteriously missing from SystemJS Builder bundle

I am currently using the SystemJS builder to compile an Angular 2 application with PrimeNg components. The issue arises when trying to integrate the PrimeNg schedule component which relies on FullCalendar. Although the builder runs without errors, when I a ...

Enhancing express.Request in typescript

I have found a method to easily enhance express.Request in typescript, like so: interface CustomRequest extends express.Request { userId: string; } However, when creating a middleware function utilizing this enhancement, for example: const customMiddl ...

Having trouble accessing $scope outside of the constructor in Typescript/AngularJS?

Why is it that I can't access $scope outside of the constructor, unless I use the fat arrow function? Is there a way to access $scope without using the fat arrow function? namespace FooBar { export interface MyScope extends ng.IScope { me ...

Retrieving subcollection data in Firestore using Angular

I am facing the challenge of extracting data from a subcollection within my database structure. Within my main collection products, there are documents that have a nested subcollection called reviews. products/prodID/reviews/reviewID Here is my interface ...

What steps can be taken to prevent a tab click from causing issues?

Within my application, there is a tab group that contains four tabs: <ion-tabs> <ion-tab [root]="tab1Root" tabTitle="Programmes" tabIcon="icon-programmes"></ion-tab> <ion-tab [root]="tab2Root" (ionSelect)="studioCheck()" tabTitle= ...