Mocking a Class Dependency in Jest

I have 4 classes available, and I utilize 3 of them to create an instance of another class. This is how it's done:

 const repo = new PaymentMessageRepository();
 const gorepo = new GoMessageRepository();
 const sqsm = new PaymentMessageQueueManager(process.env.SOME_ENV, process.env.ANOTHER_ENV);
 const systemUnderTest = PaymentProcessorService(repo,gorepo,sqsm);

The test scenario I want to explore involves testing if, in the event that an Error is triggered by a method such as repo.methodOne(), systemUnderTest should return a specific response. To accomplish this, I need to mock the PaymentMessageRepository class. How can I go about doing this?

All my classes are associated with Joi schema. I encountered challenges in this aspect but managed to resolve it using: jest.mock('joi').

In addition, is it possible to apply mocking for only one particular test? Whenever I attempt to implement mocking, it seems like all my tests are affected by the mock. Should I separate them somehow?

Here is what I have implemented thus far:

import { PaymentMessageQueueManager } from '../Queues/PaymentMessageQueueManager';
import { PaymentMessageRepository, PaymentMessageRepository_Schema } from '../Repository/PaymentMessageRepository'
import { GoMessageRepository } from '../Services/GoMessageRepository';
import {PaymentProcessorService} from '../Services/PaymentProcessorService'

jest.mock('joi');

jest.mock('../Repository/PaymentMessageRepository', () => ({
    PaymentMessageRepository : jest.fn().mockImplementation( () => ({
        putItem: jest.fn(),
    })),
    PaymentMessageRepository_Schema: {
        required : jest.fn(),
    },
})); 

jest.mock('../Services/GoMessageRepository', () => ({
    GoMessageRepository: jest.fn().mockImplementation( () => ({
        putItem: jest.fn(),
    })),
    GoMessageRepository_Schema: {
        required: jest.fn(),
    },    
}));

jest.mock('../Queues/PaymentMessageQueueManager', () => ({
    PaymentMessageQueueManager: jest.fn().mockImplementation( () => ({
        sendToQ: jest.fn(),
    })),
    PaymentMessageQueueManager_Schema: {
            required: jest.fn(),
        }
}));


describe('PaymentProcessorService unit tests', () => {
    const env = process.env
    beforeEach(() => {
        jest.resetModules()
        process.env = { ...env }
    });

    test('When a dependency is null, processor service should not be created', () => {
        process.env.PAYMENT_MESSAGE_TABLE_NAME = 'MOCK_TABLE_NAME';
        
        const repo = new PaymentMessageRepository();
        const gorepo = new GoMessageRepository();
        const sqsm = new PaymentMessageQueueManager(process.env.SOME_ENV, process.env.ANOTHER_ENV);
       
        expect ( () => new PaymentProcessorService(repo, undefined, sqsm)).toThrow(Error);
    })
    afterEach(() => {
        process.env = env
    });
    
    test('When mocked dependencies, processor should return no error', () => {
        const repo_mocked = new GoMessageRepository(); // <--- How to mock this so that repo_mocked.some_method() either throws or returns 0?

    })
})

Currently, the issue I am facing is that the first test fails because when mocking 'Joi', it overrides the .assert() method and alters its behavior, causing it to return a different result. As a result, even if there is a missing dependency, the overridden 'Joi' returns okay and causes the assertion to fail. If I remove all mocks, the test functions as intended.

Am I approaching the mocking process incorrectly? My main goal is to be able to mock a specific method to return a certain response or trigger an exception, and then assert the outcome accordingly. Achieving this seamlessly in C# with XUnit is straightforward, but I find it challenging in TS/JS with Jest (my source files are in TypeScript while my test files are in JavaScript).

Answer №1

After thorough investigation and exploration, I have successfully figured out how to mock methods of the injected classes. Although I cannot guarantee that this is the most optimal or elegant solution, it is what I have devised:

test('When a dependency is mocked, and message is ok, proccesor service should be created', async () =>{
        process.env.PAYMENT_MESSAGE_TABLE_NAME = 'MOCK_TABLE_NAME';
        process.env.GO_MESSAGE_TABLE_NAME = 'GO_MSG_TABLE_NAME';
        const repo = new PaymentMessageRepository();
        const sqsm = new PaymentMessageQueueManager(process.env.JAIMITO_SQS_URL_DEPOSIT, process.env.JAIMITO_SQS_URL_WITHDRA);
        const gorepo = new GoMessageRepository();

        const goRepoPutItemMock = jest
        .spyOn(GoMessageRepository.prototype, 'putItem')
        .mockImplementation(() => {
            console.log('Put Item in Go Table');
        }); // comment this line if just want to "spy"

        const repoPutItemMock = jest
        .spyOn(PaymentMessageRepository.prototype, 'putItem')
        .mockImplementation( () => {
            console.log('Put Item in Payment Table');
        });

        const queueManagerPutMessageMock = jest
        .spyOn(PaymentMessageQueueManager.prototype, 'sendToQ')
        .mockImplementation( () => {
            console.log('Sending Payment to Q');
        });

        const message = "<TransferNotification>MESSAGE_HERE</TransferNotification>";
      
        let systemUnderTest = new PaymentProcessorService(repo, gorepo, sqsm);

        let resp = await systemUnderTest.processMessages(  parsePaymentsFromEvent(constructSQSEvent(message)) );
    
        expect(repoPutItemMock).toHaveBeenCalled();
        expect(goRepoPutItemMock).not.toHaveBeenCalled();
        expect(queueManagerPutMessageMock).toHaveBeenCalled();
        expect(resp.batchItemFailures.length == 0).toBe(true);
    });

This approach allows me to mock goRepoPutItemMock, for instance, to throw specific errors or return customized values that can be handled within my systemUnderTest implementation.

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

What sets apart async.map from the async library and Promise.map from bluebird?

Allow me to clarify: My goal is to utilize async/await functionality with either the async or bluebird library. I'm puzzled as to why this code snippet works as expected: const promises = Promise.map (someArray, async item => { ...

The success function is not being triggered despite receiving data from Jquery ajax request

Here is the ajax code snippet I am using: $.ajax({ type: 'POST', url: '/Module/findByType', dataType: 'json', data: { request: 'ajax', type_id: id } ...

Mongoose fails to add an object to an array

I am facing an issue with my express application where comments are not being inserted into posts. Even though there are no errors displayed, the comments are not being added when posting via Postman. I have tried various solutions like this and this, but ...

What is the best way to extract the value from a JSON URL?

Using AngularJS, I am looking to dynamically retrieve the price value from a URL's JSON data. Is this feasible? Here is the URL JSON: link Below is my controller: angular.module("myApp",['zingchart-angularjs']).controller('MainContro ...

Exclude the node_modules directory when searching for files using a global file pattern

I'm facing some challenges setting up a karma configuration file because I am having difficulty creating a glob that correctly matches my files. Within my lerna repository, there may be node_modules folders inside the packages, and it's importan ...

When users click on the tiles, they will act as interactive objects that will direct them to a different page within the Angular framework,

output Here is the code for my app component: <H1>AI API DEMOS</H1> <div> <ul> <li class="active"><a routerLink="/market">Market Size</a></li> <li role="presentation&qu ...

`Unveil the hidden edges of the Google timeline chart`

Does anyone know how to remove the chart border from a Google timeline chart using this script? <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> google.charts.load ...

What is the best way to utilize eslint in Vue components?

I'm facing an issue with my .vue file that defines a component. Other .vue files are unable to see it properly due to linter errors. I keep getting ES Lint errors like: Cannot find module '../components/LinkButton'. I have tried several st ...

Is your Scrollmagic failing to function once your website is uploaded to the server?

My website incorporates Scrollmagic to dynamically load sections (changing opacity and adding movement) as users scroll through it. Everything functions perfectly fine when I preview the HTML file on my computer, but once I uploaded it to my hosting serv ...

How do I ensure my object is fully constructed before sending it in the response using NodeJS Express?

Currently, I am in the process of constructing a result_arr made up of location objects to be sent as a response. However, my dilemma lies in figuring out how to send the response only after the entire array has been fully constructed. As it stands, the re ...

I am unable to reach my pages through their URL directly, I can only access them through links within Next.js

My next JS application runs smoothly during development, but encounters an issue when published online. I can only access the pages through links on the home page that direct to those specific pages. For instance, trying to navigate directly to www.examp ...

What is the best way to make text appear as if it is floating in Jade or HTML?

Currently, I am facing an issue with a Jade file that displays an error message when a user tries to log in with incorrect credentials. The main problem is that this error message disrupts the alignment of everything else on the page, as it is just a regul ...

Steps to implement a print modal with JavaScript, jQuery and more

Imagine having a print button on several pages that, when clicked by the user, triggers a modal to pop up with the content for printing. Any suggestions or ideas would be greatly appreciated. I have multiple pages with a print button. When the user clicks ...

Creating a semicircle shape using three.js extrusion

I am trying to create half of an extruded circle using this code, but it only draws a cube. How can I modify it to achieve the desired shape? // Drawing half of an extruded circle var rightfootgeo = new THREE.CubeGeometry(2, 2, 2); for(var i = 0; i < ...

Convert parameterized lambdas for success and failure into an observable using RxJS

There is a function exported by a library that I am currently using: export function read( urlOrRequest: any, success?: (data: any, response: any) => void, error?: (error: Object) => void, handler?: Handler, httpClient?: Object, ...

JavaScript: Implementing a seamless spinning effect for an image [Compass needle]

I have been working on developing a compass app for mobile devices and have successfully created a function that returns the change-values for the compass-needle rotation (e.g. 20). However, I have noticed that setting the 'image-transform' to &a ...

Invoking a JavaScript function from iterated elements when the page loads

Hey there, I'm looking to make my progress bars dynamic using Javascript. I am currently working with Django and a Postgres DB. So far, I've been able to style them with a JS function, but now I want this function to trigger when the page loads. ...

In Promise.race(), what is the fate of promises that don't come out on top

Promise.race(promise1, promise2, ...) function returns a promise that resolves or rejects based on the fastest promise from the input list. But what happens to the promises that do not win the race? My experiments with Node.js suggest that they keep runn ...

Can someone guide me on how to use contract.on() in ethers.js to listen to events from a smart contract in a node.js application?

I've been working on a node.js application using ethers.js to listen to events emitted from the USDT contract Transfer function. However, when I run the script, it exits quickly without displaying the event logs as expected. I'm unsure of what st ...

Tips for speeding up the transition time of a floating header while scrolling

On this website , I am interested in adjusting the timing of the transition effect on the header background when hovering on scroll. Currently, the transition begins between two scrolls, but I would like it to start immediately after the first scroll. Can ...