【问题标题】:Failed to read initial state with useContext in Jest无法在 Jest 中使用 useContext 读取初始状态
【发布时间】:2023-02-23 13:10:51
【问题描述】:

我有一个组件,我想使用 Jest/React 测试库对其进行单元测试。它从useContext() 解构初始状态。但是,我收到以下错误:

错误:未捕获 [类型错误:无法读取未定义的属性 (阅读'initialState')]

显然,StateProvider 包装 Component 不适用于该错误。谁能告诉我如何解决这个问题?这里有相关文件。

// reducer.ts
export const initialState: IInitialStateContext = {
  initialState: [],
};

const reducer = (state: any, action: any) => {
  switch (action.type) {
    ...
  }
};

export default reducer;
// StateProvider.tsx
interface StateProvierProps {
  reducer: any;
  initialState: IInitialStateContext;
  children: React.ReactNode;
}

interface IStateContext {
  state: IInitialStateContext | unknown;
  dispatch: ({ type }: { type: string }) => void;
}

export const StateContext = createContext({} as IStateContext);

export const StateProvider = ({
  reducer,
  initialState,
  children,
}: StateProvierProps) => {
  return (
    // @ts-ignore
    <StateContext.Provider value={useReducer(reducer, initialState)}>
      {children}
    </StateContext.Provider>
  );
};
export const useStateValue = () => useContext(StateContext);
// Component.tsx
const Component: React.FC<IProps> = ({
  prop1,
  prop2,
  prop3,
}: IProps): JSX.Element => {
  const [{ initialState }, dispatch] = useStateValue(); // The error occurs here
  ...
// Component.test.tsx
describe("Component", () => {
  it("should render correctly", () => {
    const prop1 = "prop1";
    const prop2 = "prop2"
    const prop3 = "prop3"
    const mockReducer = jest.fn();
    const mockContext = {
      initialState: [{
      id: "",
      }]
    }
      render(
    <StateProvider initialState={mockContext} reducer={mockReducer}>
      <Component
        prop1={mockProp1}
        prop2={mockProp2}
        prop3={mockProp3}
      />
    </StateProvider>
  );
});

【问题讨论】:

    标签: reactjs typescript react-hooks jestjs react-testing-library


    【解决方案1】:

    useReducer勾签名:

    function useReducer<R extends Reducer<any, any>>(
        reducer: R,
        initialState: ReducerState<R>,
        initializer?: undefined
    ): [ReducerState<R>, Dispatch<ReducerAction<R>>];
    

    IStateContext 类型应该是元组类型:

    type IStateContext = [IInitialStateContext, ({ type }: { type: string }) => void];
    

    完整示例:

    StateProvider.tsx:

    import React, { createContext, Reducer, useContext, useReducer } from 'react';
    import { IInitialStateContext } from './reducer';
    
    interface StateProvierProps {
      reducer: Reducer<any, any>;
      initialState: IInitialStateContext;
      children: React.ReactNode;
    }
    
    type IStateContext = [IInitialStateContext, ({ type }: { type: string }) => void];
    
    export const StateContext = createContext({} as IStateContext);
    
    export const StateProvider = ({ reducer, initialState, children }: StateProvierProps) => {
      return <StateContext.Provider value={useReducer(reducer, initialState)}>{children}</StateContext.Provider>;
    };
    export const useStateValue = () => useContext(StateContext);
    

    reducer.ts:

    export type IInitialStateContext = {
      initialState: any[];
    };
    export const initialState: IInitialStateContext = {
      initialState: [],
    };
    
    const reducer = (state: any, action: any) => state;
    
    export default reducer;
    

    Component.tsx:

    import { useStateValue } from './StateProvider';
    
    export type IProps = {
      prop1: any;
      prop2: any;
      prop3: any;
    };
    export const Component = ({ prop1, prop2, prop3 }: IProps) => {
      const [{ initialState }] = useStateValue();
      console.log("? ~ file: Component.tsx:10 ~ Component ~ initialState:", initialState)
      return null;
    };
    

    Component.test.tsx:

    import { render } from '@testing-library/react';
    import React from 'react';
    import { Component } from './Component';
    import reducer from './reducer';
    import { StateProvider } from './StateProvider';
    
    describe('Component', () => {
      it('should render correctly', () => {
        const prop1 = 'prop1';
        const prop2 = 'prop2';
        const prop3 = 'prop3';
        const mockContext = { initialState: [{ id: '' }] };
        render(
          <StateProvider initialState={mockContext} reducer={reducer}>
            <Component prop1={prop1} prop2={prop2} prop3={prop3} />
          </StateProvider>
        );
      });
    });
    

    测试结果:

     PASS  stackoverflow/75531868/Component.test.tsx (8.661 s)
      Component
        ✓ should render correctly (30 ms)
    
      console.log
        ? ~ file: Component.tsx:10 ~ Component ~ initialState: [ { id: '' } ]
    
          at Component (stackoverflow/75531868/Component.tsx:10:11)
    
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        9.142 s
    

    【讨论】:

      猜你喜欢
      • 2021-09-11
      • 1970-01-01
      • 2016-02-18
      • 2021-06-04
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 2020-01-31
      • 2019-08-06
      相关资源
      最近更新 更多