Mastering the art of mocking modules with both a constructor and a function using Jest

I'm a Jest newbie and I've hit a roadblock trying to mock a module that includes both a Class ("Client") and a function ("getCreds"). The Class Client has a method called Login. Here's the code snippet I want to test:

import * as sm from 'some-client';
const smCli: sm.Client = new sm.Client();

export const getKey = async (): void => {
    const smCreds = await sm.getCreds();
    await smCli.login(smCreds);
};

The issue I'm facing is that while I can mock the getCreds function easily, I'm not sure how to mock the login function of the Client instance in order to properly test the getKey function. I've tried different approaches like the one below, but none seem to work. Can anyone point out where I'm going wrong? Thank you.

import * as sm from 'some-client';
jest.mock('some-client');

const smClientMock = sm.Client as jest.Mock<unknown>
const smGetCredsMock = sm.getCreds as jest.Mock<Promise<unknown>>

smGetCredsMock.mockResolvedValue(1);
smClientMock.mockImplementation(() => {
    return {
        login: () => {
            return 2;
        }
    };
});

Answer №1

To access the mocked instance of the sm.Client class, you can utilize mockFn.mock.instances. This allows you to make assertions on the .login() method of that particular instance.

For example:

some-client.ts:

export class Client {
  async login(creds) {}
}

export const getCreds = async () => ({ pwd: 'real pwd' });

index.ts:

import * as sm from './some-client';
const smCli: sm.Client = new sm.Client();

export const getKey = async () => {
  const smCreds = await sm.getCreds();
  await smCli.login(smCreds);
};

index.test.ts:

import * as sm from './some-client';
import { getKey } from './';

jest.mock('./some-client');

const smClientMock = sm.Client as jest.MockedClass<typeof sm.Client>;
const smGetCredsMock = sm.getCreds as jest.MockedFunction<typeof sm.getCreds>;

describe('74516778', () => {
  test('should pass', async () => {
    smGetCredsMock.mockResolvedValue({ pwd: '123' });
    await getKey();
    expect(smClientMock).toBeCalledTimes(1);
    expect(smGetCredsMock).toBeCalledTimes(1);
    const smClientInstanceMock = smClientMock.mock.instances[0];
    expect(smClientInstanceMock.login).toBeCalledWith({ pwd: '123' });
  });
});

Test outcome:

 PASS  stackoverflow/74516778/index.test.ts (8.48 s)
  74516778
    ✓ should pass (3 ms)

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |   76.92 |      100 |   33.33 |    87.5 |                   
 index.ts       |     100 |      100 |     100 |     100 |                   
 some-client.ts |      50 |      100 |       0 |   66.67 | 2                 
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.278 s, estimated 10 s

Package version used:

"jest": "^26.6.3",

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

Opening and closing a default Bootstrap modal in Angular 2

Instead of using angular2-bootstrap or ng2-bs3-modal as recommended in the discussions on Angular 2 Bootstrap Modal and Angular 2.0 and Modal Dialog, I want to explore other options. I understand how the Bootstrap modal opens and closes: The display pro ...

Using event.target to pass HTML form data to FormData is causing an error stating that the Argument of type 'EventTarget' cannot be assigned to a parameter of type 'HTMLFormElement'

Looking to extract data from a form and store it in FormData: const handleSubmit = (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); const formData = new FormData(e.target as HTMLFormElement); const value = formData.get(' ...

The error message indicates that the 'aboutData' property is not found within the 'never[]' data type

What is the correct method for printing array elements without encountering the error message "Property 'post_title' does not exist on type 'never[]'?" How can interfaces be used to define variables and utilize them in code for both ab ...

Ways to assign unpredictable values (such as ids, dates, or random numbers) to a Domain Entity or Aggregate Root when it has been injected as dependencies

I am currently developing a frontend repository that follows an innovative hexagonal architecture approach with domain-driven design principles, and it utilizes Redux Toolkit. The development process involves Test-Driven Development (TDD) where I employ c ...

Is there a way to customize the default MuiCheckbox icon in theme.ts?

How can I customize the icon default prop for Mui checkbox? I followed the instructions provided here and used a snippet from the documentation: const BpIcon = styled('span')(({ theme }) => ({ borderRadius: 3, width: 16, height: 16, .. ...

Using a custom TypeScript wrapper for Next.js GetServerSideProps

I developed a wrapper for the SSR function GetServerSideProps to minimize redundancy. However, I am facing challenges in correctly typing it with TypeScript. Here is the wrapper: type WithSessionType = <T extends {}>( callback: GetServerSideProps&l ...

Ways to eliminate duplicate objects from an array using Angular 6

I'm having trouble removing duplicate value objects in an array and it's not working as expected. I believe the duplicate function is functioning correctly, but the changes are not being reflected in the li list. Can you pinpoint where I need to ...

​Troubleshooting findOneAndUpdate in Next.js without using instances of the class - still no success

After successfully connecting to my MongoDB database and logging the confirmation, I attempted to use the updateUser function that incorporates findOneAndUpdate from Mongoose. Unfortunately, I ran into the following errors: Error: _models_user_model__WEBPA ...

Attempting to successfully upload this Angular 7 form to my TypeScript code. Making use of ngForm and [(ngModel)] to achieve this

I am having trouble passing form information using the onSubmit() function. It seems to be undefined when I try to execute it initially. Could there be a syntax error that I'm missing? <form class="gf-formbox" name="credentials" (ngSubmit)="onSubm ...

Disable the functionality of the device's back button to prevent it from going back to the

For my project, I utilize popups to display important information to the user. When a popup is displayed, how can I override the functionality of the device's back button so that instead of navigating to the previous route, it will close the popup? ...

I am on the hunt for actual instances of React testing using Jest and Enzyme in real-world scenarios

My question may be a bit abstract, but I'm finding it challenging to determine what should or shouldn't be tested in a React app. I am seeking something along the lines of a Git repository containing a popular project with advanced React, Jest, ...

how to verify if a variable exists in TypeScript

Is there a recommended method for verifying if a variable has a value in TypeScript 4.2? My variable may contain a boolean value. I'm thinking that using if(v){} won't suffice as the condition could be disregarded if it's set to false. ...

The program is throwing an error stating that the property 'user' is not found on the data type 'DefaultRootState'

Issue Encounter I am currently encountering the error message 'user' does not exist on type 'DefaultRootState'. I have attempted to resolve it without success so far. Here is the link to my GitHub repository. Error Details C:/Users/t ...

Tips on excluding node_modules from typescript in Next.js 13

I am constructing a website in the next 13 versions with TypeScript, using the src folder and app directory. When I execute `npm run dev`, everything functions correctly. However, upon building, I encounter this error... ./node_modules/next-auth/src/core/l ...

Exploring Appsetting Configuration in AppModule of Angular 8

I'm looking to update my configuration in the appsettings file by replacing a hardcoded string with a reference to the appsetting. Currently, I have this hardcoded value in appmodule.ts: AgmCoreModule.forRoot({ apiKey: 'testtesttest', li ...

How come the information I receive when I subscribe always seems to mysteriously disappear afterwards?

I've been working on a web project using Angular, and I've run into an issue with my code that's been causing problems for a while now. The problem lies in fetching data from a server that contains translations: getTranslations(): Observab ...

The FaceBook SDK in React Native is providing an incorrect signature when trying to retrieve a token for iOS

After successfully implementing the latest Facebook SDK react-native-fbsdk-next for Android, I am facing issues with its functionality on IOS. I have managed to obtain a token, but when attempting to use it to fetch pages, I keep getting a "wrong signature ...

Having trouble adjusting the appearance of the dropdown menu in Angular Material's Select component

I've been attempting to adjust the style of the overlay panel within an Angular Material's MdSelect component in order to change the default max-width property of 280px. I have tried various methods, such as using '!important' to overr ...

React with Typescript - Type discrepancies found in Third Party Library

Recently, I encountered a scenario where I had a third-party library exporting a React Component in a certain way: // Code from the third party library that I cannot alter export default class MyIcon extends React.Component { ... }; MyIcon.propTypes = { ...

An issue has occurred: The function _co.deleteConsulta is not recognized as a valid function

While following a tutorial on creating a CRUD application using Firestore, I encountered an issue when trying to delete data from Firestore. Every time I attempt to delete a user from my Firestore database, I receive an error stating that ._co.deleteConsul ...