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

React Testing Library测试依赖AppContext的组件报错如何解决

问题现象

测试报错截图
测试ServiceRequestDetails组件时抛出运行时错误:TypeError: Cannot read properties of undefined (reading 'darkMode')。
报错原因:组件依赖的Layout布局组件需要读取AppContext提供的全局状态(比如darkMode主题字段),但当前测试用例渲染组件时只包裹了Router,没有提供AppContext上下文,导致读取上下文属性失败。

相关代码

业务组件:ServiceRequestDetails.js

export function ServiceRequestDetails(props) {
    const ctx = useContext(AppContext);
  
    return (
        <>
            <Layout
                page="servicerequestdetails"
                title={navigationLinks()}
                subTitle={pageSubTitle()}
                showHelp={true}
                helpText="Help"
                helpIcon={<QuestionCircleOutlined />}
                onHelpClick={() => setShowHelpModal(!showHelpModal)}
                helpToggle={showHelpModal}
                helpTemplate={<ViewServiceRequest />}
            >

                <div className="flex items-center">
                    <div className="pr-2">
                      <img src="/images/icons/services.svg" alt="filter" />
                    </div>
                    <h3 className="text-lg font-medium">Service Request Details</h3>
                </div>

          </Layout>
        </>
    )
}

初始测试用例:ServiceRequestDetails.test.js

test('Testing For title', () => {
  render(
    <Router>
      <ServiceRequestDetails/>
    </Router>
  )
  expect(screen.getByText("Service Request Details")).toBeInTheDocument();
})
解决方法

核心逻辑:和生产环境渲染逻辑保持一致,测试时给被测试组件包裹AppContext.Provider,传入符合预期的mock上下文值即可,根据测试用例规模可以选两种实现方式:

  • 单测试用例直接包裹Provider
    适合只有少量组件依赖AppContext的场景,直接修改测试用例,在包裹层加入AppContext.Provider,传入Layout组件依赖的所有上下文字段:
// 注意替换成你项目中AppContext的实际引入路径
import AppContext from '@/context/AppContext';

test('Testing For title', () => {
  // 按项目AppContext的实际结构,补全Layout组件会用到的所有字段
  const mockAppContext = {
    darkMode: false, // 本次报错缺失的字段
    // 其他Layout依赖的字段也一并补全mock值,比如用户信息、全局方法等
  };

  render(
    <AppContext.Provider value={mockAppContext}>
      <Router>
        <ServiceRequestDetails/>
      </Router>
    </AppContext.Provider>
  )
  expect(screen.getByText("Service Request Details")).toBeInTheDocument();
})
  • 封装自定义render方法全局复用
    适合项目中大量组件依赖Router、AppContext等全局Provider的场景,避免每个测试用例重复写包裹逻辑:
    1. 先新建测试公共工具文件(比如src/test-utils.js),封装带全局Provider的自定义render方法:
import { render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
// 替换成项目中AppContext的实际引入路径
import AppContext from '@/context/AppContext';

// 默认mock的上下文值,可根据测试需求传入自定义值覆盖
const defaultMockContext = {
  darkMode: false,
  // 补全其他全局默认mock字段
};

const GlobalProviders = ({ children, mockContext }) => {
  return (
    <AppContext.Provider value={{...defaultMockContext, ...mockContext}}>
      <Router>
        {children}
      </Router>
    </AppContext.Provider>
  )
};

const customRender = (ui, options = {}, mockContext = {}) => {
  return render(ui, {
    wrapper: (props) => <GlobalProviders {...props} mockContext={mockContext} />,
    ...options
  })
};

// 导出@testing-library/react的所有原有方法,替换原有render
export * from '@testing-library/react';
export { customRender as render };
  1. 后续所有测试文件从公共工具文件引入render,不需要再重复包裹Router和AppContext.Provider:
// 替换成你项目中test-utils的实际路径
import { render, screen } from '@/test-utils';
import ServiceRequestDetails from '@/pages/ServiceRequestDetails';

test('Testing For title', () => {
  render(<ServiceRequestDetails />)
  expect(screen.getByText("Service Request Details")).toBeInTheDocument();
})

注意:如果后续运行测试还报其他AppContext相关的undefined错误,说明mock的上下文值缺少对应字段,对照项目里AppContext的默认值把缺失字段补到mock值里即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:39:29