Ways to simulate a dependent class in TypeScript & JEST without modifying constructor parameters to optional

Currently, I am attempting to replicate a well-known process in Java development using TypeScript and JEST for practice. In this scenario, there is a Controller class that relies on a Service class. The connection between the two is established through the constructor of the Controller, making the presence of the Service mandatory.

To manage dependencies at runtime, I utilize a Dependency Injection (DI) library called tsyringe. This ensures that the DI container handles the instantiation of the Service and its injection into the Controller when required.

Here is the source code for the Controller:

import { scoped, Lifecycle } from "tsyringe";
import { RouteService } from "./RouteService";
import { RouteDTO } from "./view/RouteDTO";

@scoped(Lifecycle.ContainerScoped)
export class RouteController {

    constructor(private routeService: RouteService) {}

    public createRoute(route: RouteDTO): RouteDTO {
        // business logic - meant for testing
        if (isBusinessLogicValid) {
            return this.routeService.saveRoute(route);
        } else {
            throw Error("Invalid business logic");
        }
    }
}

And here is the source code for the Service:

import { scoped, Lifecycle } from "tsyringe";
import { UserSession } from "../user/UserSession";
import { RouteDTO } from "./view/RouteDTO";

@scoped(Lifecycle.ContainerScoped)
export class RouteService {

    constructor(
        private userSession: UserSession
    ) {}

    public saveRoute(route: RouteDTO): RouteDTO {
        // contains business logic and handling persistence
        return route;
    }

}

I am striving to mock the RouteService class in a manner that eliminates the need for manual creation of an instance for unit testing purposes with the RouteController. If done manually, it would involve resolving all underlying dependencies (i.e., RouteController depends on RouteService, RouteService depends on UserSession, and so forth).

In Java, utilizing Mockito allows me to achieve something similar as shown below:

RouteService routeServiceMock = mock(RouteService.class); 
// defining mock behavior on routeServiceMock
RouteController controller = new RouteController(routeServiceMock);
RouteDTO newDTO = createRouteDTO();
RouteDTO savedDTO = controller.save(newDTO);
assertThat(savedDTO).isEqualTo(newDTO);
//... other assertions

Upon reviewing Jest documentation, I have not found an equivalent approach. Is there a way to accomplish this? If yes, could someone provide guidance on how to proceed?

Answer №1

After much trial and error, I believe I have stumbled upon a viable solution for the time being. However, I must admit, I am not entirely satisfied with the way this solution is structured. Essentially, I find myself having to perform a double cast using as unknown as RouteService.

Here is what I can do:

describe('Route controller test', () => {

    beforeEach(() => {
        let routeServiceMock: RouteService = {
            saveRoute: jest.fn(async route => route)
        } as unknown as RouteService
        routeController = new RouteController(routeServiceMock);
    })

   // ...
}

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

Is it possible for FormArray to return null?

Hello there. I've attempted various methods, but none of them seem to be effective. Currently, I am working on this task where I need to start a formArray for emails. email: [testestest] However, what I have is: email: [testestest] I'm encoun ...

The child element is triggering an output event that is in turn activating a method within the parent

I am currently utilizing @Output in the child component to invoke a specific method in the parent component. However, I am encountering an issue where clicking on (click)="viewPromotionDetails('Learn more')" in the child component is al ...

One should refrain from loading the API in Angular when there is no data present, by utilizing the global.getData method

Check out this code snippet: loadNextBatch() { console.log('scrolldown'); this.pageIndex = this.pageIndex + 1; this.global.getData(`/conditions/latest?start=${this.pageIndex}&length=${this.pageSize}`) .pipe(take(1)).subscr ...

Tips for reorganizing the files within a directory using Visual Studio Code

Is there a way to reformat an entire project folder at once, rather than just one document? I know that I can use the shortcut key Alt+Shift+F or right click on a document and select Format Document. My projects consist of Typescript files in the Angular ...

Angular Material Table displaying real-time information

Recently, I've delved into Angular and have been experimenting with creating a dynamic table to showcase data. Currently, I have managed to get it partially working with static data. I drew inspiration from this particular example: https://stackblit ...

Show all span elements in a map except for the last one

Within my ReactJS application, I have implemented a mapping function to iterate through an Object. In between each element generated from the mapping process, I am including a span containing a simple care symbol. The following code snippet demonstrates t ...

Unit testing the error function within the subscribe method in Angular

I've been working on a unit test for the subscribe call, but I'm struggling to cover the error handling aspect of the subscribe method. The handleError function deals with statusCode=403 errors and other status codes. Any assistance would be grea ...

What is the process of determining if two tuples are equal in Typescript?

When comparing two tuples with equal values, it may be surprising to find that the result is false. Here's an example: ➜ algo-ts git:(master) ✗ ts-node > const expected: [number, number] = [4, 4]; undefined > const actual: [number, number] ...

Adjusting the audio length in React/Typescript: A simple guide

I'm currently developing a web app with React and TypeScript. One of the components I created is called SoundEffect, which plays an mp3 file based on the type of sound passed as a prop. interface ISoundEffectProps { soundType: string, // durat ...

The clash between the definitions of identifiers in this file and another (@types/jasmine) is causing error TS6200

While trying to build my project with Angular CLI, I am encountering the following error message: ERROR in ../my-app/node_modules/@types/jasmine/index.d.ts(18,1): error TS6200: Definitions of the following identifiers conflict with those in another file: ...

Expanding the width of an MUI Button smoothly using transitions

I am currently working on a custom ToggleButton that changes its text based on certain state changes. However, I am facing an issue where the width of the button abruptly grows when the text changes. How can I smoothly transition this change in width? Bel ...

The specified 'Object' type does not match the required 'Document' constraint

I need assistance with running a MERN application to check for any issues, but I keep encountering this error across multiple files. Error: The 'CatalogType' type does not meet the requirements of 'Document'. The 'CatalogType&apo ...

When transferring the code to the src folder, tRPC encounters issues and stops functioning

Currently, I am working on developing a basic Twitter clone using Next and TRPC. While tRPC is up and running smoothly, I am looking to streamline my code by consolidating it all within the src directory. However, upon moving everything, I encountered an i ...

Tips for incorporating moment.js library into an Angular 2 TypeScript application

I attempted to utilize TypeScript bindings in my project: npm install moment --save typings install moment --ambient -- save test.ts file content: import {moment} from 'moment/moment'; I also tried without using TypeScript bindings: npm inst ...

Ways to specify a setter for a current object property in JavaScript

Looking to define a setter for an existing object property in JavaScript ES6? Currently, the value is directly assigned as true, but I'm interested in achieving the same using a setter. Here's a snippet of HTML: <form #Form="ngForm" novalida ...

An Unexpected ER_BAD_FIELD_ERROR in Loopback 4

I encountered an unusual error: Unhandled error in GET /managers: 500 Error: ER_BAD_FIELD_ERROR: Unknown column 'role_id' in 'field list' at Query.Sequence._packetToError (/Users/xxxx/node_modules/mysql/lib/protocol/se ...

Nuxt3 - TS2339: The 'replaceAll' property is not found on the 'string | string[]' type in Nuxt3

Hey there! I've been experimenting with the replaceAll() method within my Nuxt3 project and encountered a strange error. Folder Structure ───pages │ └───Work │ │ index.vue │ │ [Work].vue Template <templat ...

Differences between Typescript Import and JavaScript import

/module/c.js, attempting to export name and age. export const name = 'string1'; export const age = 43; In b.ts, I'm trying to import the variables name and age from this .ts file import { name, age } from "./module/c"; console.log(name, ...

Struggling to locate a suitable mock server that can deliver JSON responses for a specific URL that has been predetermined

I have encountered a challenge in my frontend app development using vue.js. I need to find a mock backend server (without mocking it on the front end). My app is capable of making HTTP requests, specifically GET and PATCH are the methods of interest. I am ...

Obtain a union type in TypeScript based on the values of a field within another union type

Is it feasible in Typescript to derive a union type from the values of a field within another union type? type MyUnionType = | { foo: 'a', bar: 1 } | { foo: 'b', bar: 2 } | { foo: 'c', bar: 3 } // Is there an automati ...