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

Vitest中Mock React子组件时栈溢出问题及测试方法

解决Vitest测试中Mock子组件导致的栈溢出问题

我想要测试父组件中的子组件在被Mock后是否能携带正确的props被调用,但运行测试时出现错误:RangeError: Maximum call stack size exceeded

我的Vitest配置

import svgr from 'vite-plugin-svgr'
import { defineConfig } from 'vitest/config'
import type { UserConfig } from 'vitest/config'

import { resolve } from 'path'

export default defineConfig({
  test: {
    environment: 'jsdom',
    setupFiles: ['./tests/setup.ts'],
    environmentMatchGlobs: [['./src/**/*.tsx', 'jsdom']],
    globals: true,
  },
  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
  },
  plugins: [svgr()],
} as UserConfig)

我的测试代码

import { render, screen } from '@testing-library/react'
import { vi } from 'vitest'
import Input from '@/components/Input/Input'

import Login from './Login'

vi.mock('@/components/Input/Input', () => ({
  default: vi.fn(),
}))

describe('ConfirmEmail', () => {
  it('renders correctly', () => {
    render(<Login />)

    expect(screen.getByRole('heading', { name: /Login to your account/i }))

    expect(Input).toHaveBeenCalledWith({
      label: 'email',
    }) // error: RangeError: Maximum call stack size exceeded
  })
})

问题原因

你把Input组件Mock成了一个空的Vitest函数,但React组件在渲染时必须返回有效的React元素,空函数返回undefined会导致React渲染流程异常,进而触发无限递归调用,最终引发栈溢出。

解决方案

1. 修复Mock组件的返回值

确保Mock的Input组件返回一个有效的React元素,同时保留对调用参数的追踪:

vi.mock('@/components/Input/Input', () => ({
  default: vi.fn(() => <div data-testid="mock-input" />),
}))

2. 修正断言逻辑

React会自动给组件传递额外参数(如key、ref或上下文),直接用toHaveBeenCalledWith全量匹配props会失败,改用expect.objectContaining做部分匹配:

expect(Input).toHaveBeenCalledWith(
  expect.objectContaining({
    label: 'email',
  }),
  expect.anything() // 匹配React自动传递的第二个参数
)

3. 补全断言方法

第一个expect缺少断言方法,需要添加.toBeInTheDocument()完成断言。

修改后的完整测试代码

import { render, screen } from '@testing-library/react'
import { vi } from 'vitest'
import Input from '@/components/Input/Input'

import Login from './Login'

vi.mock('@/components/Input/Input', () => ({
  default: vi.fn(() => <div data-testid="mock-input" />),
}))

describe('Login', () => { // 修正描述名称,与组件对应
  it('renders correctly and passes correct props to Input', () => {
    render(<Login />)

    // 验证标题存在
    expect(screen.getByRole('heading', { name: /Login to your account/i })).toBeInTheDocument()

    // 验证Input组件被调用时携带正确的label props
    expect(Input).toHaveBeenCalledWith(
      expect.objectContaining({
        label: 'email',
      }),
      expect.anything()
    )
  })
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 16:42:30