You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Testing Library与Jest测试useContext自定义Hook传值失败排查

问题根源:你创建了不相关的Context实例

你的测试代码里犯了一个典型的错误——你在测试中重新调用了createContext()生成了一个全新的ConfigurationContext,但你的ComponentA里的useConfigurationContext Hook,用的是你自定义Hook文件里一开始就创建好的那个原始Context对象。这两个Context完全是独立的,所以测试里的Provider根本没给组件传递任何值,组件自然还是拿到Context的默认空对象。


修正方案1:直接使用你的ConfigurationProvider(推荐)

既然你的应用里是用ConfigurationProvider来包裹组件的,测试时也应该完全模拟这个真实场景,这样测试结果会更贴近实际运行情况。

第一步:优化你的原始Provider(可选但更灵活)

先给ConfigurationProvider添加一个初始化配置的props,让测试可以直接传入初始值:

// 修改你的Context Hook代码
import React, { createContext, useContext, useState } from 'react';
const Context = createContext({});

export const ConfigurationProvider = ({ children, initialConfig = {} }) => {
  // 用传入的initialConfig初始化state
  const [configuration, setConfiguration] = useState(initialConfig);
  return (
    <Context.Provider value={{ configuration, setConfiguration }} >
      {children}
    </Context.Provider>
  );
};

export const useConfigurationContext = () => useContext(Context);
export const { Consumer: ConfigurationConsumer } = Context;

第二步:修改测试代码

直接用ConfigurationProvider包裹组件,传入测试用的配置:

import React from 'react';
import { render } from '@testing-library/react';
import ComponentA from 'componentA';
// 导入你自定义的ConfigurationProvider
import { ConfigurationProvider } from './path-to-your-context-hook';

const testConfig = { propertyA: 'hello' };

test('renders the config', () => {
  const { queryByText } = render(
    <ConfigurationProvider initialConfig={testConfig}>
      <ComponentA />
    </ConfigurationProvider>
  );
  
  expect(queryByText('hello')).toBeInTheDocument();
});

修正方案2:导入原始Context对象(不推荐但可行)

如果你一定要手动用Context.Provider测试,必须导入自定义Hook里已经创建好的那个Context,而不是重新创建:

import React from 'react';
import { render } from '@testing-library/react';
import ComponentA from 'componentA';
// 导入Hook里的原始Context,而非自己新建
import { Context as ConfigurationContext } from './path-to-your-context-hook';

const config = { propertyA: 'hello' };

test('renders the config', () => {
  const { queryByText } = render(
    // 注意要和原始Provider的value结构保持一致
    <ConfigurationContext.Provider value={{ configuration: config }}>
      <ComponentA />
    </ConfigurationContext.Provider>
  );
  
  expect(queryByText('hello')).toBeInTheDocument();
});

注意:这里必须保持value的结构和原始Provider一致——原始Provider传递的是{ configuration, setConfiguration },所以测试里的value也要包含configuration字段,否则组件里拿到的configuration会是undefined。


关键总结

  • Context的匹配是基于对象引用的:只有同一个Context实例的Provider和Consumer(或useContext)才能关联传递值。
  • 测试时尽量模拟真实的组件层级(比如用你已经写好的Provider),这样测试更可靠,也避免手动维护Context的结构。

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

火山引擎 最新活动