"TypeError: react.useContext is not a function" when mocking context Providers with React Testing Library

"TypeError: react.useContext is not a function" when mocking context Providers with React Testing Library

我正在尝试确定在使用 React Context 进行 Jest 测试时如何最好地模拟 Provider。我发现最有前途的线索是 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 示例,所以我很困惑。欢迎其他模拟Provider的解决方案或建议。

编辑: 为清楚起见添加 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 }

错误 is ambiguous 并且当 useContext 未定义且 useContext 是函数但 return 不是可迭代(数组)时确实会发生。

如果 Jest 配置不正确并且 react 包作为 CommonJS 模块导入并转换为 ES 模块 default 通过模块互操作导入,则可能会发生第一种情况。

第二种情况是最简单的错误解释。上下文提供程序未提供数组值,因此 useContext 不是 return 数组。除非 defaultState 对象包含 value 具有数组值的属性,...defaultState 传播将导致错误的提供者值。

应在测试中以与在应用中相同的方式提供提供商值:

<Provider value={[state, reducer]}>...

如果不想在测试中使用dialogReducer,可以提供一个间谍:

<DialogContext.Provider value={[defaultState, mockedDispach]}>...

否则可以使用 DialogProvider 代替 DialogContext.Provider,因为它已经提供了预期的提供商价值。

jest.mock('react', () => ({
    ...jest.requireActual('react'),
    useContext: jest.fn(),
}))

在配置适配器之前添加此行。

configure({adapter: new Adapter()});