What is the reason behind Jest v24 mocking classes that have a need for private methods

Currently, I am facing a challenge in creating mock implementations of my Typescript classes using Jest v24+. Specifically, I am trying to create a mock class that will be injected into a constructor and mock the functions to return specific responses.

My main question is: How can I create a mock for each test?

Here is some more information:

Recently, I started a new project and switched to using Jest v24, which has led to difficulties in writing tests that I have been unable to resolve.

In the example below, using Jest v23, I could mock the Randomiser class like this:

const Mock = jest.fn<Randomiser>(() => ({
  getRandom: jest.fn().mockReturnValue(10)
}));

This code used to compile and build successfully.

However, in v24, the 'fn' function now takes an additional generic <T, Y extends any[]>. I'm not sure if this change is affecting the behavior, but now I am encountering an error:

Property 'rand' is missing in type '{ getRandom: Mock; }' but required in type 'Randomiser'.ts(2741)

import "jest";

class Randomiser {
    public getRandom(): number {
        return this.rand();
    }
    private rand(): number {
        return Math.random();
    }
}

class Multiplier {
    private randomiser: Randomiser;
    constructor(randomiser: Randomiser) {
        this.randomiser = randomiser;
    }

    multiplyRandom(factor: number): number {
        return Math.floor(this.randomiser.getRandom() * factor);
    }
}

describe("tests", () => {
    it("10 x 2 = 20", () => {
        const Mock = jest.fn<Randomiser, any>(() => ({
            getRandom: jest.fn().mockReturnValue(10),
            rand: jest.fn() //with this line I get an error because it should be private, without this line I get the error above.
        }));
        expect(new Multiplier(new Mock()).multiplyRandom(2)).toBe(20);
    })
})

I expected to be able to write mocks the same way as in v23, where I could mock the class and only the functions I intended to call. However, now I have to mock all functions, including private ones, which then leads to complaints about them not being private.

Answer №1

Here are two different approaches you can take:

1. Utilize the Partial<Type> method to partially mock your class:

const Mock = jest.fn<Partial<Randomiser>, []>(() => ({
  getRandom: jest.fn().mockReturnValue(10)
}));

You can then cast your mock to your class type for injection, like so:

const mock: Randomiser = new Mock() as Randomiser;
expect(new Multiplier(mock).multiplyRandom(2)).toBe(20);

2. Omit specifying any type for the mock.

Alternatively, you could choose not to specify a type for the mock, resulting in the mock type being any.

const Mock = jest.fn(() => ({
  getRandom: jest.fn().mockReturnValue(10)
}));

With this approach, you can inject your mock directly without typing, though keep in mind it will be untyped:

const mock = new Mock();
expect(new Multiplier(mock).multiplyRandom(2)).toBe(20);

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

Testing Angular with Jasmine: The spy should have been called as expected

Seeking assistance for a persistent issue that has been troubling me. I am currently working on unit tests for a component I developed, and no matter what I try, I can't seem to resolve the recurring problem of an "Expected spy getTopRatedMedia to ha ...

Best practices for effectively managing interface design

My current interface looks like this: export interface Folder { name: string; id: number; date: Date; } However, in the actual scenario, the JSON response provides the date as a string type. How should I handle this data transfer between the back-en ...

Is it possible for a redis client to function without having a redis datastore installed?

Currently in my node web server, I am utilizing the npm module known as redis. Upon executing my code... const client = redis.createClient(); client.on("error", function (err) { console.log("Error " + err); }); client.hmset(["key", "test keys 1", "t ...

What is the purpose of the @NgModule annotation in Angular Material?

I've been struggling with using Angular-Material Components in different components. Despite watching and reading various tutorials, I still can't seem to get them to work. The error message I keep encountering is: compiler.js:2430 Uncaught Erro ...

Retrieve content from my Tumblr API posts

Looking to retrieve my tumblr posts through an api. Successfully set up the api key using Angular2 and typescript. Utilizing jsonp to avoid any cross origin problems. Here is my current code snippet: var config = { params: { action: "query" ...

Troubleshooting: Unable to filter reducers in Redux when using the remove

I'm attempting to eliminate an element from an array using the filter method in this manner: removeDisplate: (state, action: PayloadAction<string>) => { console.log(action.payload); state.map((item) => { console.log(item.name); } ...

Navigating an object in TypeScript: the right approach

Curious if there might be a bug in TypeScript? Just seeking clarification on whether my code is incorrect or if there is an actual issue with the language. interface Something { key1: string; key2: number; key3: boolean; } const someObject: S ...

The attribute 'tableName' is not found within the 'Model' type

Currently in the process of converting a JavaScript code to TypeScript. Previously, I had a class that was functioning correctly in JS class Model { constructor(input, alias) { this.tableName = input; this.alias = alias; } } Howev ...

What is the process to enable mandatory validation after a change in input in Angular 4?

Currently, I am working on a project using Angular 4. One of the tasks I need to achieve is validation. <input [(ngModel)]="someModel" required placeholder="some placeholder"/> The validation triggers immediately, but I want it to only trigger aft ...

What is the best way to extract multiple records from an Array?

Below is a simple filter function that filters Rec_pagedItems in an array called allItems. someval(value){ if(value.length>=5){ this._pagedItems= this.allItems.find(e=>e.uniqueid == value || e.name == value ); if(this._pagedItem ...

How can we leverage mapped types in TypeScript to eliminate properties and promisify methods?

Below is the provided code snippet: class A { x = 0; y = 0; visible = false; render() { return 1; } } type RemoveProperties<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : never//; }; type JustMethodKe ...

Issue with Typescript - Node.js + Ionic mobile app's Angular AoT build has encountered an error

Currently, I am in the process of developing an Android application using Node.js and Ionic framework. The app is designed to display random text and images stored in separate arrays. While testing the app on Chrome, everything works perfectly fine. Upon ...

Unable to choose Typescript as a programming language on the VSCode platform

Recently, I encountered an issue while using Visual Studio Code with TypeScript. Even though TypeScript is installed globally, it is not showing up in the list of file languages for syntax highlighting. Despite trying various troubleshooting methods such a ...

What is the reason for TypeScript's refusal to accept this task?

In my attempt to create a type that can be A, B, or an object with a key containing an array of 2 or more items that are either A, B, or another similar object (thus allowing for recursive definition). This is the solution I came up with: type A = { p ...

What is the best way for me to access a certain web address?

I am working on setting up a routing mechanism in my Angular project, but I'm encountering a URL routing error. The application is unable to locate the specified URL. Below is the routing setup: navigation.ts { id: 'documentation-manag ...

Exporting Typescript to Javascript files

I have created a sample TypeScript object with the following code: declare const S3 = "https://s3.amazonaws.com/xxx/icons"; declare const SVG = "svg-file-icons"; declare interface MyIcons { "image/jpeg": string; "image/jpg": string; } export const F ...

TypeScript encountered an error with code TS2305, stating that the module "constants" does not have any exported members

My Vite + React + TypeScript application has the following structure: src constants a.ts b.ts index.ts components Comp.tsx tsconfig file with "baseUrl": "src" The content of a.ts is as follows: export const ARRAY = ...

Issue: Module 'stylelint' not found in Angular Project

I've been attempting to execute this command to validate all of the .scss files (and even tried with .css files) and I keep encountering this error. $ stylelint "apps/**/*.scss" It worked once before but not anymore, even after restarting my compute ...

Unable to implement multiple draggable inner objects using Angular 5 and dragula library

After struggling for the past few days, I can't seem to get it to work... Here is a brief explanation of my issue: In this example, I have an array of objects structured like this: public containers: Array<object> = [ { "name": "contain ...

An error occurred while trying to access properties of null, specifically the `_rawValidators` property

I recently upgraded an app from angular 8 to angular14 and encountered a problem with a form array. The error message I'm seeing is cfs-detail.component.html:13 ERROR TypeError: Cannot read properties of null (reading '_rawValidators'). It ...