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

如何用Jest正确模拟函数?ReactErrorBoundary测试求助

问题分析与解决方案

问题根源

  1. ErrorBoundary模拟逻辑不合理:原模拟直接在组件函数执行时同步调用onError和onReset,不符合真实组件的触发逻辑(真实场景下仅在子组件抛出错误时调用onError),且返回非有效React元素可能导致渲染异常。
  2. 测试断言错误:原测试期望console.log接收两个参数,但实际onError中仅输出了"Error caught!"一个参数。
  3. 未处理window.location.reload:onReset中的页面刷新逻辑会干扰测试,需提前模拟。

解决方案代码修改

1. 修正依赖模拟逻辑

import React from 'react';
import { render } from '@testing-library/react';
import ReactErrorBoundary from '../../components/ReactErrorBoundary';
import { ErrorBoundary } from 'react-error-boundary';
import { logger } from '../../services/logService';
import ErrorPage from '../../components/ErrorPage';

// 模拟日志服务
jest.mock('../../services/logService', () => ({
  logger: jest.fn(),
}));

// 模拟ErrorBoundary组件,存储回调供测试手动触发
jest.mock('react-error-boundary', () => {
  const React = require('react');
  const mockErrorBoundary = jest.fn(({ children, onError, onReset, FallbackComponent }) => {
    // 将回调挂载到mock函数上,方便测试调用
    mockErrorBoundary.onError = onError;
    mockErrorBoundary.onReset = onReset;
    // 返回有效React元素,确保组件正常渲染
    return <div data-testid="error-boundary">{children}</div>;
  });

  return {
    ...jest.requireActual('react-error-boundary'),
    ErrorBoundary: mockErrorBoundary,
  };
});

// 模拟页面刷新,避免测试中实际刷新页面
jest.spyOn(window.location, 'reload').mockImplementation(() => {});

2. 完善测试用例(含全覆盖率补充)

describe('ReactErrorBoundary', () => {
  beforeEach(() => {
    // 重置所有mock调用记录,保证测试独立性
    jest.clearAllMocks();
  });

  test('渲染ErrorBoundary并传入正确的FallbackComponent', () => {
    render(<ReactErrorBoundary />);
    expect(ErrorBoundary).toHaveBeenCalledWith(
      expect.objectContaining({
        FallbackComponent: ErrorPage,
        onError: expect.any(Function),
        onReset: expect.any(Function),
        children: undefined,
      }),
      {}
    );            
  });

  test('正确传递子组件给ErrorBoundary', () => {
    const testChildren = <div>Hello World</div>;

    render(<ReactErrorBoundary>{testChildren}</ReactErrorBoundary>);
    expect(ErrorBoundary).toHaveBeenCalledWith(
      expect.objectContaining({
        FallbackComponent: ErrorPage,
        onError: expect.any(Function),
        onReset: expect.any(Function),
        children: testChildren,
      }),
      {}
    );  
  });

  test('触发onError时输出日志并调用logger服务', () => {
    const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
    const testError = new Error("Test error message");

    render(<ReactErrorBoundary><div>Test content</div></ReactErrorBoundary>);
    
    // 手动触发存储的onError回调
    ErrorBoundary.onError(testError);
    
    expect(consoleSpy).toHaveBeenCalledWith('Error caught!');
    expect(logger).toHaveBeenCalledWith(testError);

    consoleSpy.mockRestore();
  });

  test('触发onReset时输出日志并执行页面刷新', () => {
    const consoleSpy = jest.spyOn(console, 'log').mockImplementation();

    render(<ReactErrorBoundary><div>Test content</div></ReactErrorBoundary>);
    
    // 手动触发存储的onReset回调
    ErrorBoundary.onReset();
    
    expect(consoleSpy).toHaveBeenCalledWith('reloading the page...');
    expect(window.location.reload).toHaveBeenCalled();

    consoleSpy.mockRestore();
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:50:53