You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用TypeScript与Jest Mock模块中被调用的函数

正确Mock Jest中const导出函数的方法

要测试的函数(action目录下)

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
}

该函数findActionProgressToDisplay依赖从../actionsProgress导入的areSameActions函数。

待Mock的函数

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

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

三次失败的尝试及报错

第一种尝试

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)
  })
})

报错信息:Cannot assign to 'areSameActions' because it is a read-only property(符合预期,因为areSameActions是const导出的常量)

第二种尝试

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)
  })
})

报错信息:TypeError: Cannot redefine property: areSameActions

第三种尝试

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') // Step 2.
  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)
  })
})

报错信息:Property 'mockImplementation' does not exist on type '(firstAction: Action, secondAction: Action) => boolean'(TypeScript类型推断认为areSameActions是普通函数,而非Mock函数)

正确的解决方案

针对TypeScript环境下Mock const导出函数的问题,推荐以下两种可靠方式:

方式一:类型断言处理Mock函数

修改第三种尝试的导入和Mock调用逻辑,通过类型断言明确告诉TypeScriptareSameActions是Jest Mock函数:

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

// 用jest.mock替换原模块,保留其他导出的同时替换目标函数为Mock
jest.mock('../actionsProgress/index', () => {
  const original = jest.requireActual('../actionsProgress/index')
  return {
    ...original,
    areSameActions: jest.fn(),
  }
})

describe('=== findActionProgressToDisplay ===', () => {
  test('should return the pending action progress', () => {
    // 通过类型断言将普通函数类型转为Jest Mock类型
    const mockAreSameActions = actionsProgressModule.areSameActions as jest.Mock
    mockAreSameActions.mockReturnValue(true)

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

    expect(actionFound.status).toEqual(ActionStatus.PENDING)
    // 额外验证Mock函数是否被调用
    expect(mockAreSameActions).toHaveBeenCalled()
  })
})

方式二:spyOn开启可写选项(可选)

如果不想使用jest.mock,可以在jest.spyOn中添加{ writable: true }选项,允许重写const导出的函数(注意:严格模式下可能受限):

import * as actionsProgressModule from '../actionsProgress/index'

// 开启writable选项允许修改只读属性
jest.spyOn(actionsProgressModule, 'areSameActions', { writable: true }).mockReturnValue(true)

此方式更适合快速临时Mock,长期来看第一种方式的类型安全性和可维护性更好。


内容的提问来源于stack exchange,提问作者Damien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 07:25:36