测试自定义挂钩:不变违规:找不到 react-redux 上下文值;请确保组件包裹在 <Provider>
Testing custom hook: Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
我有一个要测试的自定义挂钩。它接收一个 redux store dispatch 函数和 returns 一个函数。为了得到我正在尝试做的结果:
const { result } = renderHook(() => { useSaveAuthenticationDataToStorages(useDispatch())});
但是,我得到一个错误:
Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a
这是因为 useDispatch
并且没有连接商店。但是,我这里没有任何组件可以用提供程序包装。我只需要测试将数据简单地保存到商店的挂钩。
我该如何解决?
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
});
这可能是一个迟到的答案,但您也可以在测试中使用它
jest.mock('react-redux', () => {
const ActualReactRedux = jest.requireActual('react-redux');
return {
...ActualReactRedux,
useSelector: jest.fn().mockImplementation(() => {
return mockState;
}),
};
});
此问题与您的测试文件有关。您必须在测试文件中声明 provider 和 store。
用下面的代码
更新或替换你的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
文件中。原解link
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();
});
});
适合我。
screenshot work
顺便说一句,如果您将 test-utils.[j|t]s(?x)
或 whatever you set the name file
位置放在目录 __test__
上,请不要忘记在 jest.config.js
.[=23= 上忽略它]
//jest.config.js
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/', '<rootDir>/__tests__/test-utils.tsx'],
回购:https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart
我有一个要测试的自定义挂钩。它接收一个 redux store dispatch 函数和 returns 一个函数。为了得到我正在尝试做的结果:
const { result } = renderHook(() => { useSaveAuthenticationDataToStorages(useDispatch())});
但是,我得到一个错误:
Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a
这是因为 useDispatch
并且没有连接商店。但是,我这里没有任何组件可以用提供程序包装。我只需要测试将数据简单地保存到商店的挂钩。
我该如何解决?
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
});
这可能是一个迟到的答案,但您也可以在测试中使用它
jest.mock('react-redux', () => {
const ActualReactRedux = jest.requireActual('react-redux');
return {
...ActualReactRedux,
useSelector: jest.fn().mockImplementation(() => {
return mockState;
}),
};
});
此问题与您的测试文件有关。您必须在测试文件中声明 provider 和 store。
用下面的代码
更新或替换你的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
文件中。原解link
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();
});
});
适合我。
screenshot work
顺便说一句,如果您将 test-utils.[j|t]s(?x)
或 whatever you set the name file
位置放在目录 __test__
上,请不要忘记在 jest.config.js
.[=23= 上忽略它]
//jest.config.js
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/', '<rootDir>/__tests__/test-utils.tsx'],
回购:https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart