Guide on mocking a function inside another function imported from a module with TypeScript and Jest

I have a function inside the action directory that I want to test:

import { Action, ActionProgress, ActionStatus, MagicLinkProgress } from '../../interfaces'
import { areSameActions } from '../actionsProgress'

export const findActionProgressToDisplay = (progress: MagicLinkProgress, actions: Array<Action>): ActionProgress => {
  const actionProgressFound = progress.actionsProgress.find(
    (actionProgress) => actionProgress.status === ActionStatus.PENDING && actions.some((action) => areSameActions(actionProgress.action, action))
  )
  if (!actionProgressFound) {
    throw new Error('No action found to display')
  }

  return actionProgressFound
}

The function findActionProgressToDisplay calls another function called areSameActions which is imported from ../actionsProgress.

Here is the function that needs to be mocked :

import { Action } from '../../interfaces'

export const areSameActions = (firstAction: Action, secondAction: Action): boolean =>
  firstAction.origin === secondAction.origin && firstAction.type === secondAction.type && firstAction.url === secondAction.url

Below is the jest test I attempted:

import { mockActions } from './../../mocks/campaigns/index'
import { mockActionsProgress, mockProgress } from './../../mocks/magicLinks/index'
import { findActionProgressToDisplay } from './index'
import { describe, test, expect } from '@jest/globals'
import { ActionStatus } from '../../interfaces'
import * as module from '../actionsProgress/index'

module.areSameActions = jest.fn().mockReturnValue(true)

describe('=== findActionProgressToDisplay ===', () => {
  test('should return true', () => {
    const progress = mockProgress({ actionsProgress: mockActionsProgress() })
    const actions = mockActions()
    const actionFound = findActionProgressToDisplay(progress, actions)

    expect(actionFound.status).toEqual(ActionStatus.PENDING)
  })
})

But I encountered this error: Cannot assign to 'areSameActions' because it is a read-only property. This makes sense since areSameActions is a const.

I also tried the following approach:

import { mockActions } from './../../mocks/campaigns/index'
import { mockActionsProgress, mockProgress } from './../../mocks/magicLinks/index'
import { findActionProgressToDisplay } from './index'
import { describe, test, expect } from '@jest/globals'
import { ActionStatus } from '../../interfaces'
import * as module from '../actionsProgress/index'

jest.spyOn(module, 'areSameActions').mockReturnValue(true)

describe('=== findActionProgressToDisplay ===', () => {
  test('should return true', () => {
    const progress = mockProgress({ actionsProgress: mockActionsProgress() })
    const actions = mockActions()
    const actionFound = findActionProgressToDisplay(progress, actions)

    expect(actionFound.status).toEqual(ActionStatus.PENDING)
  })
})

However, I received this error: TypeError: Cannot redefine property: areSameActions. I am unsure why this issue occurred.

Lastly, I attempted the following solution:

import { mockActions } from './../../mocks/campaigns/index'
import { mockActionsProgress, mockProgress } from './../../mocks/magicLinks/index'
import { findActionProgressToDisplay } from './index'
import { describe, test, expect } from '@jest/globals'
import { ActionStatus } from '../../interfaces'
import { areSameActions } from '../actionsProgress/index'

jest.mock('../actionsProgress/index', () => {
  const original = jest.requireActual('../actionsProgress/index') 
  return {
    ...original,
    areSameActions: jest.fn(),
  }
})
describe('=== findActionProgressToDisplay ===', () => {
  test('should return true', () => {
    areSameActions.mockImplementation(() => (true))

    const progress = mockProgress({ actionsProgress: mockActionsProgress() })
    const actions = mockActions()
    const actionFound = findActionProgressToDisplay(progress, actions)

    expect(actionFound.status).toEqual(ActionStatus.PENDING)
  })
})

Unfortunately, I received an error stating: Property 'mockImplementation' does not exist on type '(firstAction: Action, secondAction: Action) => boolean'. This error seems reasonable considering in the current context, areSameActions is a function and not a mock.

Could you provide guidance on how to mock / stub / spy the function areSameActions to effectively test findActionProgressToDisplay?

Answer №1

It was the closest attempt to the truth.

Indeed, jest.mock mocks a module when it is required. So:

jest.mock('../actionsProgress/index', () => {
  const original = jest.requireActual('../actionsProgress/index') // Step 2.
  return {
    ...original,
    areSameActions: jest.fn(),
  }
})

The mock is created successfully. However, for some unknown reason, typescript interprets that areSameActions is a function instead of a mock. To clarify this, I explicitly specify my function as a Mock.

Here is the solution:

import { mockActions } from './../../mocks/campaigns/index'
import { mockActionsProgress, mockProgress } from './../../mocks/magicLinks/index'
import { findActionProgressToDisplay } from './index'
import { describe, test, expect } from '@jest/globals'
import { ActionStatus } from '../../interfaces'
import * as module from '../actionsProgress/index'

jest.mock('../actionsProgress/index', () => {
  const original = jest.requireActual('../actionsProgress/index')
  return {
    ...original,
    areSameActions: jest.fn(),
  }
})

describe('=== findActionProgressToDisplay ===', () => {
  test('should return the founded action', () => {
    module.areSameActions as jest.Mock
    // @ts-ignore
    module.areSameActions.mockImplementation(() => true)
    const progress = mockProgress({ actionsProgress: mockActionsProgress() })
    const actions = mockActions()
    const actionFound = findActionProgressToDisplay(progress, actions)

    expect(actionFound.status).toEqual(ActionStatus.PENDING)
  })

  test('should throw error because this case is not supposed to happen', () => {
    module.areSameActions as jest.Mock
    // @ts-ignore
    module.areSameActions.mockImplementation(() => false)
    const progress = mockProgress({ actionsProgress: mockActionsProgress() })
    const actions = mockActions()
    expect(() => findActionProgressToDisplay(progress, actions)).toThrowError('No action found to display')
  })
})

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

Obtain the total sum from the array of objects that are nested within

In the array of objects below, each object contains a nested object called count. I am looking to calculate the total sum of Closed, Verify, and Analyze For example, the total for Closed is 23, Verify is 3, and Analyze is 20 "byPerson": [ ...

What is the best way to convert a dynamic HTML table with input fields into an Excel spreadsheet?

I have developed a JavaScript function to convert an HTML table into an Excel sheet. However, I am facing an issue where some fields in the table are enclosed in input tags instead of td tags, causing them to not appear in the Excel sheet. function expo ...

Tips for inserting a property into an array of objects when it matches the specified ID

As someone new to Angular, I am encountering an issue and would appreciate some help. Here is an array of objects I am working with: signals = [{ 'signalID': '123' },{ 'signalID': '233' },{ 'signalID': &apo ...

Error message in Vuex4: Unable to access 'state' property because it is undefined

Having trouble with Vue3 and Vuex4, I keep encountering this error: Uncaught TypeError: Cannot read properties of undefined (reading 'state') at ReactiveEffect.eval [as fn] (App.vue?3dfd:36) at ReactiveEffect.run (reactivity.esm-bundler.j ...

The search results fail to show the required information

I am trying to retrieve data from an API based on a search query. When the user enters the name of the film they are looking for and hits enter to submit the form, the matching films should be displayed on the screen. However, my console is showing errors ...

Altering iframe Content with the Help of Selenium Web Driver

I am looking to update the content of an iframe with new material using Selenium WebDriver. Note: I have attempted the following method: driver.swithTo().frame(frame_webelement); driver.findElement(By.xxx).sendKeys("Mycontent"); While I was able to cle ...

Angular ng-repeat with toggle filter

Looking for a way to display data in an angular application using ng-repeat? Want to add and remove filters on the displayed data with a simple click? You're in luck. Implementing a toggle filter functionality is easier than you think. If you've ...

Tips for accessing the most recent embedded document added using the push() method

I'm having difficulty determining the feasibility of this situation. While using the mongoose blog example to illustrate, my specific use case is a bit more complex: var Comments = new Schema({ title : String , body : String , date ...

What should be included in the types field of package.json for TypeScript libraries?

I'm finding it challenging to efficiently develop multiple typescript modules simultaneously with code navigation while ensuring the correct publishing method. What should I include in the "types" field of my package.json? Referring to: Typescriptlan ...

Can an excessive amount of classes cause my Angular application to run sluggishly?

Within my Angular 7 application, I have generated approximately 200 to 300 classes for model types (e.g. component.model.ts) solely for type checking purposes. I have not instantiated any objects from these classes. As I navigate through the application, ...

implementing conditional logic in angularjs expressions

<p>{{isExisted}}</p> Looking to show either "Active" or "Inactive", but the isExisted variable only returns true or false. Need help with setting up a conditional if else statement to change it to the desired value. ...

Angular is using the previous parameter value upon clicking the button

I'm currently working on implementing a button that, when clicked, triggers a function sending a parameter to my server. Here is what I have so far: <table class="table table-hover"> <thead> <tr> <th>Id</th& ...

Tips for mocking the router.navigate function in Jest

As a newcomer to unit testing with Jest in Angular, I find myself facing a challenge when it comes to testing components that utilize the this.router.navigate() method. Previously, I used Jasmine for testing and followed these steps: import { Router } from ...

Combine a string variable and an array object in JavaScript or AngularJS

Hey there! I'm currently attempting to combine an array, a variable, and a "." in between them. The object I receive from json is stored in data, while valuePickup represents a variable. My current approach: self.GetIndex = function (valuePickup) { ...

How can I create a hover effect animation in React?

I am looking to replicate the menu item underline animation demonstrated in this example. In jQuery, I would easily achieve this by obtaining the left position and width of a menu item, then using stop.animation on hover. Attempting this animation with R ...

"Utilizing the power of Angular 6's JSON pipe

Looking for a well-structured formatted JSON, but all I get is confusion and this strange image: Does anyone have any insights on what might be causing the issue? HTML <span style="font-weight: 500;">Payload Data: </span> <pre><co ...

What is the best way to insert a record into the rth column of the nth row in a table

In the table I'm working with, there are 6 columns and only 5 of them have data filled in. The last column is currently empty for all rows. I am now trying to populate the last column of each row with some data. Can someone guide me on how to use a f ...

Integration of Mocha with WebStorm

WebStorm offers a useful feature that adds a small arrow next to describe() and it() keywords when writing tests with Mocha, allowing for easy manual execution. However, there is a challenge: I require additional setup before each test, leading me to use ...

Generate a collection of elements using a different collection as a reference

I am struggling with an array of objects: let data = [{ createdDate: "2222", email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="087c6d7b7c3d487c6d7b7c266b6765">[email protected]</a>", histories: [ ...

Tips for shrinking a sticky header when scrolling using Angular and JavaScript

Looking for a way to modify the header component in an Angular application so that it shrinks as the user scrolls down while maintaining its sticky functionality. How can I adjust the display of the lower half of the header to show no text when the user s ...