如何在 Jest/Enzyme 中模拟 React 上下文?

How to mock React context in Jest/Enzyme?

我正在尝试学习如何使用 Jest/Enzyme,并且一直坚持为我的单元测试提供上下文分派功能。第一个状态上下文似乎有效,但调度函数的第二个状态上下文无效。 我知道我可以通过上下文将第二个参数传递给浅函数,但我也无法让它以这种方式工作。

错误:

 FAIL  src/components/SearchBar.test.js
  SearchBar.jsx
    × should show search bar (4 ms)

  ● SearchBar.jsx › should show search bar

    TypeError: Cannot destructure property 'asyncReducer' of '(0 , _Provider.useCocktailDispatch)(...)' as it is undefined.

       7 | const SearchBar = () => {
       8 |     const state = useCocktailState()
    >  9 |     const { asyncReducer, dispatch } = useCocktailDispatch()
         |             ^
      10 |     const [modalShow, setModalShow] = useState(false)
      11 |     const [searchTerm, setSearchTerm] = useState(state.searchTerm)
      12 |

      at SearchBar (src/components/SearchBar.jsx:9:13)
      at ReactShallowRenderer.render (node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:829:32)
      at renderElement (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:643:26)
      at fn (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:707:46)
      at withSetStateAllowed (node_modules/enzyme-adapter-utils/src/Utils.js:100:18)
      at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:707:20)
      at new ShallowWrapper (node_modules/enzyme/src/ShallowWrapper.js:411:22)
      at shallow (node_modules/enzyme/src/shallow.js:10:10)
      at Object.<anonymous> (src/components/SearchBar.test.js:13:25)

SearchBar.test.js 片段:

Enzyme.configure({adapter: new Adapter()})
jest.mock('../state-provider/Provider')

describe('SearchBar.jsx', () => {
    it('should show search bar', () => {
        // shallow renders react component to memory instead of DOM
        // it wraps component in wrapper to give us functions to examine component
        const wrapper = shallow(<SearchBar />) // <- line where error occurs
        const searchBar = wrapper.find('InputGroup FormControl') // searchBar also a wrapper
        expect(searchBar.exists()).toBe(true)
    })
})

Provider.js:

import React, { useContext, useReducer } from 'react'
import { asyncReducer, reducer, initialState } from './reducer';

export const StateContext = React.createContext();
export const DispatchContext = React.createContext();

export const useCocktailState = () => {
    const context = useContext(StateContext)
    if (context === undefined) {
        throw new Error(`useCocktailState must be used within a Provider`);
    }
    return context;
}

export const useCocktailDispatch = () => {
    const context = useContext(DispatchContext)
    if (context === undefined) {
        throw new Error(`useDispatch must be used within a Provier`);
    }
    return context;
}


const Provider = ({children}) => {
    const [state, dispatch] = useReducer(reducer, initialState)
    return (
        <DispatchContext.Provider value={{asyncReducer:asyncReducer(dispatch),dispatch}}>
            <StateContext.Provider value={state}>
                {children}
            </StateContext.Provider>
        </DispatchContext.Provider>
    )
}

export default Provider

在此处查看完整代码:https://github.com/robert-levy/cocktail-finder

jest.mock('../state-provider/Provider', () => ({
 useCocktailDispatch: () => ({
  asyncReducer: //your implementation of mock method or jest.fn() for dummy one
  dispatch: //your implementation of mock or jest.fn() for dummy one
 })
}))