cro*_*ays 14 testing reactjs redux enzyme react-redux
我有一个简单的Todo组件,该组件利用了我正在使用酶进行测试的react-redux钩子,但是出现如下所示的错误或浅渲染的空对象。
使用react-redux的钩子测试组件的正确方法是什么?
Todos.js
const Todos = () => {
const { todos } = useSelector(state => state);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
Run Code Online (Sandbox Code Playgroud)
Todos.test.js v1
...
it('renders without crashing', () => {
const wrapper = shallow(<Todos />);
expect(wrapper).toMatchSnapshot();
});
it('should render a ul', () => {
const wrapper = shallow(<Todos />);
expect(wrapper.find('ul').length).toBe(1);
});
Run Code Online (Sandbox Code Playgroud)
v1错误:
...
Invariant Violation: could not find react-redux context value;
please ensure the component is wrapped in a <Provider>
...
Run Code Online (Sandbox Code Playgroud)
Todos.test.js v2
...
Invariant Violation: could not find react-redux context value;
please ensure the component is wrapped in a <Provider>
...
Run Code Online (Sandbox Code Playgroud)
V2测试也失败,因为wrapper是<Provider>和调用dive()上wrapper会返回相同的错误为V1。
在此先感谢您的帮助!
Kri*_*iti 46
模拟 useSelector 使用可以做到这一点
import * as redux from 'react-redux'
const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue({ username:'test' })
Run Code Online (Sandbox Code Playgroud)
abi*_*ibo 10
我可以使用酶安装工具测试使用redux钩子的组件,并向Provider提供模拟存储:
零件
import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';
// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
const dispatch = useDispatch()
const startupComplete = useSelector(state => state.startup.complete)
if (!startupComplete) {
setTimeout(() => dispatch(StartupActions.startup()), 1000)
}
return (
<div className="app">
{startupComplete ? <AppRouter /> : <Startup />}
</div>
);
}
export default App;
Run Code Online (Sandbox Code Playgroud)
测试
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';
const mockStore = configureMockStore([thunk]);
describe('App', () => {
it('should render a startup component if startup is not complete', () => {
const store = mockStore({
startup: { complete: false }
});
const wrapper = mount(
<Provider store={store}>
<App />
</Provider>
)
expect(wrapper.find('Startup').length).toEqual(1)
})
})
Run Code Online (Sandbox Code Playgroud)
在阅读了这里的所有回复并挖掘了文档之后,我想汇总使用 react-redux hooks with Enzyme 和浅层渲染来测试 React 组件的方法。
这些测试依赖于模拟useSelector和useDispatch钩子。我还将在 Jest 和 Sinon 中提供示例。
基本笑话示例
import React from 'react';
import { shallow } from 'enzyme';
import * as redux from 'react-redux';
import TodoList from './TodoList';
describe('TodoList', () => {
let spyOnUseSelector;
let spyOnUseDispatch;
let mockDispatch;
beforeEach(() => {
// Mock useSelector hook
spyOnUseSelector = jest.spyOn(redux, 'useSelector');
spyOnUseSelector.mockReturnValue([{ id: 1, text: 'Old Item' }]);
// Mock useDispatch hook
spyOnUseDispatch = jest.spyOn(redux, 'useDispatch');
// Mock dispatch function returned from useDispatch
mockDispatch = jest.fn();
spyOnUseDispatch.mockReturnValue(mockDispatch);
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should render', () => {
const wrapper = shallow(<TodoList />);
expect(wrapper.exists()).toBe(true);
});
it('should add a new todo item', () => {
const wrapper = shallow(<TodoList />);
// Logic to dispatch 'todoAdded' action
expect(mockDispatch.mock.calls[0][0]).toEqual({
type: 'todoAdded',
payload: 'New Item'
});
});
});
Run Code Online (Sandbox Code Playgroud)
基本的诗浓示例
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import * as redux from 'react-redux';
import TodoList from './TodoList';
describe('TodoList', () => {
let useSelectorStub;
let useDispatchStub;
let dispatchSpy;
beforeEach(() => {
// Mock useSelector hook
useSelectorStub = sinon.stub(redux, 'useSelector');
useSelectorStub.returns([{ id: 1, text: 'Old Item' }]);
// Mock useDispatch hook
useDispatchStub = sinon.stub(redux, 'useDispatch');
// Mock dispatch function returned from useDispatch
dispatchSpy = sinon.spy();
useDispatchStub.returns(dispatchSpy);
});
afterEach(() => {
sinon.restore();
});
// More testing logic...
});
Run Code Online (Sandbox Code Playgroud)
测试多个useSelectors需要我们模拟 Redux 应用程序状态。
var mockState = {
todos: [{ id: 1, text: 'Old Item' }]
};
Run Code Online (Sandbox Code Playgroud)
然后我们可以模拟我们自己的useSelector.
// Jest
const spyOnUseSelector = jest.spyOn(redux, 'useSelector').mockImplementation(cb => cb(mockState));
// Sinon
const useSelectorStub = sinon.stub(redux, 'useSelector').callsFake(cb => cb(mockState));
Run Code Online (Sandbox Code Playgroud)
useSelector我认为这是在玩笑中从 Redux store模拟 hook 的最好也是最简单的方法:
import * as redux from 'react-redux'
const user = {
id: 1,
name: 'User',
}
const state = { user }
jest
.spyOn(redux, 'useSelector')
.mockImplementation((callback) => callback(state))
Run Code Online (Sandbox Code Playgroud)
其想法是,您可以state仅使用商店数据的子集来提供商店模拟。
如果您使用另一个文件中定义的函数选择器,则@abidibo之外还有另一种方法。您可以模拟useSelector和选择器功能,然后shallow从酶中使用:
零件
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';
const Example = () => {
const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);
return isSpinnerDisplayed ? <Spinner /> : <Button />;
};
export default Example;
Run Code Online (Sandbox Code Playgroud)
选择器
export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;
Run Code Online (Sandbox Code Playgroud)
测试
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';
jest.mock('react-redux', () => ({
useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');
describe('Example', () => {
it('should render Button if getIsSpinnerDisplayed returns false', () => {
getIsSpinnerDisplayed.mockReturnValue(false);
const wrapper = shallow(<Example />);
expect(wrapper.find(Button).exists()).toBe(true);
});
});
Run Code Online (Sandbox Code Playgroud)
可能有点hacky,但对我来说效果很好:)