测试自定义钩子:不变违规:找不到 react-redux 上下文值;请确保组件被包裹在 <Provider> 中

IT技术 reactjs redux jestjs react-testing-library
2021-05-22 21:51:57

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

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

但是,我收到一个错误:

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

发生这种情况是因为useDispatch没有连接商店。但是,我这里没有任何组件可以与提供程序一起包装。我只需要测试只是将数据保存到商店的钩子。

我该如何解决?

4个回答

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

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
});

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

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

此问题与您的测试文件有关。您必须声明提供程序存储在您的测试文件中。

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问题/8145及解决方案链接


使用此解决方案,如果您遇到类似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(),
  };
};

我认为您可以像这样创建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();
  });
});


为我工作。

截图工作

顺便说一句,如果您将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