The Jest mock is infiltrating the function logic instead of simply returning a rejected promise

The Issue at Hand

I am currently working on testing the correct handling of errors when a use case function returns a rejected promise along with the appropriate status code.

However, I seem to be encountering an issue where instead of getting a rejected promise, I am facing this error message rather than the expected behavior of the mock function returning a rejected promise:

This is the specific error I'm seeing:

TypeError: Cannot read properties of undefined (reading 'then')

The Script

In my test suite setup, I have the following configuration:

const container = new Container();

describe('Controller Error Tests', () => {
     let reportController: ReportController;
     
     let generateReportUseCase: IGenerateReportUseCase = mock<IGenerateReportUseCase>();

     container.bind<ReportServiceLocator>(TYPES.ReportServiceLocator).to(ReportServiceLocator);
     
     beforeAll(async () => {
        jest.clearAllMocks();
        cleanUpMetadata();
        dotenv.config();
        reportController = new ReportController(container.get<ReportServiceLocator>(Symbol.for("ReportServiceLocator")));
    });

     it('User held shares report use case throws error', async () => {
        let requestObj = httpMocks.createRequest({
            cookies: {
                token: jwt.sign({ id: 'test' }, process.env.JWT_SECRET_KEY!),
            },
            query: {
                report_type: 'CSV'
            }
        });

        let responseObj = httpMocks.createResponse();

        mock(generateReportUseCase).usersHeldShares.mockRejectedValue(new Error('Could not generate report'));

        await reportController.userHeldShares(requestObj, responseObj);
        expect(responseObj.statusCode).toEqual(500);
    })
})

reportController.userHeldShares is an inversify controller structured like this:

@httpGet('/held-shares')
    public async userHeldShares(@request() req: express.Request, @response() res: express.Response){
        let jwtSecretKey = process.env.JWT_SECRET_KEY;
        let ascending: boolean = req.query.ascending === "false" ? false : true;
        let report_type: string = String(req.query.reportformat);
        let cookieData = await <IUserDto>jwt.verify(req.cookies.token, jwtSecretKey!);
            
        if(!cookieData.id){
            return res.status(401).json({error: 'User not authorised'});
        }
        
        return await this.generateReportUseCase.usersHeldShares(cookieData.id!, ascending, report_type)
            .then((userDto: IUserDto) => {
                res.status(200).json(userDto)
            })
            .catch((err: Error) => {
                res.status(500).json(err);
            });
    }

Here are the initial lines of

generateReportUseCase.usersHeldShares
, which triggers the error:

usersHeldShares(user_id: string, ascending: boolean, report_type: string): Promise<IUserDto> {
        return new Promise(async (resolve, reject) => {
            this.tradeReadOnlyRepository.fetch({user_id: user_id}, false)
            .then(async trades => {

Expected Outcome

My expectation is that when reaching the line

return await this.generateReportUseCase.usersHeldShares(cookieData.id!, ascending, report_type)
in the inversify controller, it should simply return a rejected promise without executing the actual function logic.

Answer №1

After some investigation, I discovered that I was still relying on a service locator for the correct functioning of the report generator. To address this issue, I introduced a new TestServiceLocator which will now handle all mock return values.

The code snippet for this implementation is as follows:

container.bind<TestServiceLocator>(TYPES.ReportServiceLocator).to(TestServiceLocator);

@injectable()
export default class TestServiceLocator {
    constructor(@inject(TYPES.IStockReadOnlyRepository) private stockReadRepository: IStockReadOnlyRepository,
                @inject(TYPES.IStockWriteOnlyRepository) private stockWriteRepository: IStockWriteOnlyRepository,
                @inject(TYPES.IUserWriteOnlyRepository) private userWriteRepository: IUserWriteOnlyRepository,
                @inject(TYPES.IUserReadOnlyRepository) private userReadRepository: IUserReadOnlyRepository,
                @inject(TYPES.ITradeReadOnlyRepository) private tradeReadRepository: ITradeReadOnlyRepository,
                @inject(TYPES.ITradeWriteOnlyRepository) private tradeWriteRepository: ITradeWriteOnlyRepository){}

    public GetGenerateReportUseCase(): IGenerateReportUseCase {
        let generateReportUseCase: IGenerateReportUseCase = mock<IGenerateReportUseCase>();
        mock(generateReportUseCase).completeStockValues.mockRejectedValue(new Error('Could not generate report'));
        mock(generateReportUseCase).selectedCompanyDetails.mockRejectedValue(new Error('Could not generate report'));
        mock(generateReportUseCase).usersHeldShares.mockRejectedValue(new Error('Could not generate report'));
        return generateReportUseCase;
    }

    public GetDownloadReportUseCase(): IDownloadReportUseCase {
        let downloadReportUseCase: IDownloadReportUseCase = mock<IDownloadReportUseCase>();
        mock(downloadReportUseCase).invoke.mockRejectedValue(new Error('Could not get report data'));
        return downloadReportUseCase;
    }
}

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 steps can I take to prevent encountering a Typescript Error (TS2345) within the StatePropertyAccessor of the Microsoft Bot Framework while setting a property?

During the process of constructing a bot in Typescript, I encountered TS2345 error with Typescript version 3.7.2. This error is causing issues when attempting to create properties dynamically, even if they are undefined, or referencing them in the statePro ...

Limit the allowable React Component prop type in Typescript

To promote composition within our codebase, we utilize passing components as props. Is there a way to enforce type checking for the components passed as props? For instance, let's consider a commonly used Typography component throughout the codebase, ...

What could be causing the issue of opacity and list reordering not functioning properly in react-dnd and react-virtualization?

I'm currently setting up a react-dnd sortable list within a react-virtualized List. I've been referencing an example from react-dnd which can be found here. Most of it is working as expected, but I'm encountering an issue where the items I ...

"Inserting" a fresh key-value pair into a JavaScript Object

I know that with arrays, only array elements can be added using the .push() method. My goal is to achieve a similar functionality for objects. I am familiar with both dot and bracket notation, so this is not a basic question for me. However, I need to do ...

Error: Interface declaration for _.split is missing in the Lodash.d.ts file

For my current typescript project that heavily relies on Lodash with lodash.d.ts, I've encountered an issue with the _.split function not being implemented yet. It's listed under the 'Later' section in the .ts file. I need to find a wo ...

Utilizing Http to Retrieve JSON Data in Ionic 3

Struggling with Ionic, trying to fetch data from a JSON File using HTTP, but encountering a strange error. https://i.sstatic.net/L2nVo.png Below are the relevant code snippets : src/pages/subhome/line/line.ts (The Subhome consists of multiple nested pag ...

Positioning an Element on a Web Page in Real-Time

Trying to implement an Emoji picker in my React application, I have two toggle buttons on the page to show the picker. I want it to appear where the Toggle button is clicked - whether at the top or bottom of the page. The challenge is to ensure that the pi ...

Exploring face detection with Three.js

When I utilize an octree, I am able to generate an array of faces that are in close proximity to an object. However, I am unsure how to perform a ray cast to these faces. All the resources I have found only explain how to ray cast to a mesh, line or poin ...

Why is it necessary to include 'export' when declaring a React component?

When working with React (ES6), there seems to be two variations that I encounter: class Hello extends React.Component { ... } and sometimes it looks like this: export class Hello extends React.Component { ... } I'm curious about the significance o ...

Evaluating two arrays and adding elements if the criteria are satisfied

In my attempt to filter out emails that already exist in the userData, the current issue is that my code continuously adds the same data as long as the email is not the same. Below is the code snippet: userData:[ {email: "<a href="/cdn-cgi/l/email ...

Managing numerous requests simultaneously without causing one to delay or block the others

I am facing challenges when it comes to managing multiple client requests. Ideally, each route should be handled asynchronously, but I am struggling to handle one request after another without the previous one interfering with the next one. In the code sni ...

VSCode is experiencing issues with recognizing .env* files for markup purposes and is also failing to recognize .env.local.* files

Current Environment: Utilizing NextJs, React, and VsCode Noticing a problem with syntax highlighting in my VSCODE editor. I have installed the following extensions: ENV DotEnv As per suggestions, I updated my json configuration file as follows: " ...

Guide on how to gather values into a variable from the DOM using jQuery

Trying to make this function: The current issue I'm facing is that when changing a digit (by clicking on a hexagon), I want to save the selected number as the value of a hidden input field next to the digit in the DOM. Any ideas on how to achieve th ...

Exploring the Depths of Web Scraping: A Guide to Scraping Within a Scraped Website

I have successfully scraped data from a specific page, but now I need to follow another href link in order to gather more information for that particular item. The problem is, I am unsure of how to do this. Here is an excerpt of what I have accomplished s ...

Adding an item to the collection

When I log my cartProducts within the forEach() loop, it successfully stores all the products. However, if I log my cartProducts outside of the loop, it displays an empty array. var cartProducts = []; const cart = await CartModel .fin ...

The variable is unable to transfer successfully from JavaScript to PHP using ajax

I have a code that is designed to pass the values of all checked checkboxes to a PHP file in order to delete corresponding rows from a CSV file. The checkbox values are dynamic. <tr><td><span class="custom-checkbox"><input ty ...

Verifying input for Numeric TextField

The text field being used is: <TextField variant="outlined" margin="normal" id="freeSeats" name="freeSeats" helperText={touched.freeSeats ? errors.freeSeats : ''} error={touched.freeSeats && Boolean(errors.fre ...

I'm encountering an issue where my query parameter is not being accepted by the tRPC query request

I encountered an issue when I tried sending a request to http://localhost:5000/trpc/test?val=teststring using the minimal reproducible example below. The response message received was "Invalid input: undefined," indicating that the value 'val' is ...

Customize div styles according to the website domain

I want to dynamically change the header of my website based on whether it is in dev QA or production environment. Below is the HTML code: <div id="wrapper"> <form id="form1" runat="server"> <div class="wrapper"> <div> ...

What is the process of utilizing jQuery to hover over a relevant cell?

I'm interested in learning how to implement jQuery to highlight related tables. Initially, I explored this JS fiddle and discovered a method for highlighting both vertically and horizontally. I conducted several searches to find a similar approach, ...