使用 React 测试库模拟上下文提供程序时出现“TypeError:react.useContext 不是函数”
Posted
技术标签:
【中文标题】使用 React 测试库模拟上下文提供程序时出现“TypeError:react.useContext 不是函数”【英文标题】:"TypeError: react.useContext is not a function" when mocking context Providers with React Testing Library 【发布时间】:2021-01-12 19:49:41 【问题描述】:我正在尝试确定在使用 React Context 进行 Jest 测试时如何最好地模拟提供程序。我发现的最有前途的线索是 RTL,它在他们的文档中提供了以下示例:https://testing-library.com/docs/example-react-context
我一直在尝试多种结构,但即使我密切关注他们的示例,我也会遇到上述错误。
在测试我的 Dialog 组件时,我几乎完全按照他们的示例进行操作:
笑话测试
import React from 'react';
import render from '@testing-library/react';
import DialogContext, defaultState from '../../../../store/contexts/dialogContext';
const customRender = (ui, providerProps, ...renderOptions ) =>
return render(
<DialogContext.Provider ...providerProps>ui</DialogContext.Provider>,
renderOptions
);
;
it('Dialog should work', async () =>
const providerProps =
dialogType: 'CANCEL',
...defaultState,
;
const container = customRender(<Dialog />, providerProps );
const results = await axe(container);
expect(results).toHaveNoViolations();
);
对话框组件
import React, useContext from 'react';
import DialogContext from '../../../store/contexts/dialogContext';
export default function Dialog()
const [dialogState, dialogDispatch] = useContext(DialogContext);
//logic
return (
<div id='dialog'/>
);
这是我的对话框组件的简化版本,但在第 2 行调用 useContext() 时我收到以下错误。
Error: Uncaught [TypeError: (0 , _react.useContext) is not a function or its return value is not iterable]
由于“React”在相关文件的范围内,而且我正在密切关注 RTL 示例,所以我很难过。欢迎提供其他模拟提供商方法的解决方案或建议。
编辑: 为清楚起见,添加 dialogContext 文件。当不在 Jest 流中时,组件和上下文可以正常工作。
import React, createContext, useReducer from 'react';
import dialogReducer from '../reducers/dialogReducer';
export const DialogContext = createContext();
const Provider = DialogContext;
export const defaultState =
//state object
export const DialogProvider = ( children ) =>
const [state, reducer] = useReducer(dialogReducer, defaultState);
return <Provider value=[state, reducer]>children</Provider>
当 DialogContext 从 Dialog 组件(前面的行)中记录时,它看起来与预期一样:
'$$typeof': Symbol(react.context),
_calculateChangedBits: null,
_currentValue: undefined,
_currentValue2: ,
_threadCount: 0,
Provider: '$$typeof': Symbol(react.provider), _context: [Circular] ,
Consumer:
'$$typeof': Symbol(react.context),
_context: [Circular],
_calculateChangedBits: null ,
_currentRenderer: ,
_currentRenderer2: null
【问题讨论】:
useContext
是否工作非常特定于您的 Jest 配置,错误是模棱两可的,但更可能的是 useContext 在解构假定时不返回数组。您发布的代码中没有任何内容表明为上下文提供了数组值。
你能给我更多关于 Jest 配置的信息吗?我们用 CRA 设置了一个通用的 Jest,但我可以更改或覆盖它。如果不是很明显,组件和上下文在不在此模拟流程中时可以工作,但为了清楚起见,我将添加上下文文件。
如果您使用 CRA,那么 Jest 配置应该没有问题,至少在这方面是这样。谢谢。是测试代码和生产代码之间的差异导致了这里的问题。
【参考方案1】:
当useContext
未定义并且useContext
是一个函数但不返回可迭代(数组)时,确实会发生错误is ambiguous。
如果 Jest 配置不正确并且 react
包被导入为 CommonJS 模块,该模块通过模块互操作转换为 ES 模块 default
导入,则可能会发生第一种情况。
第二种情况是对错误最简单的解释。上下文提供程序未提供数组值,因此 useContext
不返回数组。除非defaultState
对象包含value
属性和数组值,否则...defaultState
传播将导致错误的提供者值。
在测试中提供的值应与在应用中提供的方式相同:
<Provider value=[state, reducer]>...
如果打算在测试中不使用dialogReducer
,则可以提供一个间谍:
<DialogContext.Provider value=[defaultState, mockedDispach]>...
否则可以使用DialogProvider
代替DialogContext.Provider
,因为它已经提供了预期的提供者价值。
【讨论】:
您说的完全正确,谢谢!当我将原始 reducer 传递给模拟的 Provider<DialogContext.Provider value=[testState, dialogReducer]>ui</DialogContext.Provider>
并修复了当我将 state 传递给 customRender customRender(<Dialog />, testState )
时的语法,它工作得很好----谢谢!!【参考方案2】:
jest.mock('react', () => (
...jest.requireActual('react'),
useContext: jest.fn(),
))
在配置适配器之前添加这一行。
configure(adapter: new Adapter());
【讨论】:
以上是关于使用 React 测试库模拟上下文提供程序时出现“TypeError:react.useContext 不是函数”的主要内容,如果未能解决你的问题,请参考以下文章
在 React Native 中使用 axios 时出现网络错误
在 react native 中使用 jest 和 Storybook 快照测试时出现问题
尝试在模拟器或设备上构建 React Native 项目时出现 Xcode 错误