【问题标题】:Testing custom hook: Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>测试自定义钩子:不变违规:找不到 react-redux 上下文值;请确保组件包装在 <Provider>
【发布时间】:2020-04-16 00:24:19
【问题描述】:

我有一个想要测试的自定义钩子。它接收一个 redux store 调度函数并返回一个函数。为了得到我想要做的结果:

const { result } = renderHook(() => { useSaveAuthenticationDataToStorages(useDispatch())});

但是,我收到一个错误:

Invariant Violation:找不到 react-redux 上下文值;请确保组件被包裹在一个

这是因为useDispatch 并且没有连接商店。但是,我这里没有任何组件可以与提供程序一起包装。我只需要测试挂钩,它只是将数据保存到商店。

我该如何解决?

【问题讨论】:

    标签: reactjs redux jestjs react-testing-library


    【解决方案1】:

    react hooks 测试库docs 对此进行了更深入的研究。但是,我们本质上缺少的是可以通过创建包装器获得的提供程序。首先我们声明一个组件作为我们的提供者:

    import { Provider } from 'react-redux'
    
    const ReduxProvider = ({ children, reduxStore }) => (
      <Provider store={reduxStore}>{children}</Provider>
    )
    

    那么在我们的测试中我们调用

    test("...", () => {
      const store = configureStore();
      const wrapper = ({ children }) => (
        <ReduxProvider reduxStore={store}>{children}</ReduxProvider>
      );
      const { result } = renderHook(() => {
        useSaveAuthenticationDataToStorages(useDispatch());
      }, { wrapper });
      // ... Rest of the logic
    });
    

    【讨论】:

    • 请注意,如果你把这个 ReduxProvider 放在它自己的文件中(就像我一样),你需要导入 react 才能让它工作 import React from 'react';
    • configureStore() 是什么?
    【解决方案2】:

    这可能是一个较晚的答案,但您也可以在测试中使用它

    jest.mock('react-redux', () => {
        const ActualReactRedux = jest.requireActual('react-redux');
        return {
            ...ActualReactRedux,
            useSelector: jest.fn().mockImplementation(() => {
                return mockState;
            }),
        };
    });
    

    【讨论】:

    • 我不确定我是否理解这一点。我将此添加到测试中,但我仍然看到有关缺少 &lt;Provider&gt; 的错误。你能扩展这个答案吗?
    • 考虑提供完整的答案。
    • 我收到一个错误TypeError: require.requireActual is not a function,你知道为什么吗?
    • @Sachihiro 你需要jest.requireActual 而不是require.requireActual
    • 似乎可行,但您将无法在测试用例中更新 mockState?
    【解决方案3】:

    此问题与您的测试文件有关。您必须在测试文件中声明 providerstore

    通过以下代码更新或替换您的app.test.tsx

    注意:如果您还没有安装redux-mock-store,请不要忘记安装。

    import React from 'react';
    import { render } from '@testing-library/react';
    
    import App from './App';
    
    import { Provider } from 'react-redux';
    import configureStore from 'redux-mock-store';
    
    describe('With React Testing Library', () => {
        const initialState = { output: 10 };
        const mockStore = configureStore();
        let store;
    
        it('Shows "Hello world!"', () => {
            store = mockStore(initialState);
            const { getByText } = render(
                <Provider store={store}>
                    <App />
                </Provider>
            );
    
            expect(getByText('Hello World!')).not.toBeNull();
        });
    });
    

    我在搜索 1 小时后得到了这个解决方案。 非常感谢OSTE

    原解决方案:Github issues/8145 and solution link


    使用此解决方案,如果您遇到 TypeError: window.matchMedia is not a function 之类的错误,请通过此方式解决。将这些行添加到您的 setupTests.ts 文件中。原解决方案链接stackoverflow.com/a/64872224/5404861

    global.matchMedia = global.matchMedia || function () {
      return {
        addListener: jest.fn(),
        removeListener: jest.fn(),
      };
    };
    

    【讨论】:

      【解决方案4】:

      我认为您可以像这样创建test-utils.[j|t]s(?x)whatever you set the name of the file to

      https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/test-utils.tsx

      //root(or wherever your the file)/test-utils.tsx
      
      import React from 'react';
      import { render, RenderOptions } from '@testing-library/react';
      import { Provider } from 'react-redux';
      
      // Import your store
      import { store } from '@/store';
      
      const Wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
      
      const customRender = (ui: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>) => render(ui, { wrapper: Wrapper, ...options });
      
      // re-export everything
      export * from '@testing-library/react';
      // override render method
      export { customRender as render };
      
      
      

      像这样使用它: https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/pages/index.test.tsx

      //__tests__/pages/index.test.tsx
      
      
      import React from 'react';
      import { render, screen } from '../test-utils';
      import Home from '@/pages/index';
      
      describe('Home Pages', () => {
        test('Should be render', () => {
          render(<Home />);
          const getAText = screen.getByTestId('welcome');
          expect(getAText).toBeInTheDocument();
        });
      });
      
      
      

      为我工作。

      screenshot work

      顺便说一句,如果您将test-utils.[j|t]s(?x)whatever you set the name file 放在目录__test__ 上,不要忘记在jest.config.js 上忽略它。

      //jest.config.js
      
      testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/', '<rootDir>/__tests__/test-utils.tsx'],
      
      

      回购:https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart

      【讨论】:

        猜你喜欢
        • 2021-05-15
        • 2021-03-12
        • 2020-09-08
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        • 1970-01-01
        • 2020-05-31
        • 2023-02-24
        相关资源
        最近更新 更多