Reactjs 如何使用react redux钩子测试组件?
我有一个简单的Todo组件,它利用react-redux钩子,我正在使用Ezyme测试它,但是我得到一个错误或者一个带有浅渲染的空对象,如下所述 使用react redux的钩子测试组件的正确方法是什么 Todos.jsReactjs 如何使用react redux钩子测试组件?,reactjs,testing,redux,react-redux,enzyme,Reactjs,Testing,Redux,React Redux,Enzyme,我有一个简单的Todo组件,它利用react-redux钩子,我正在使用Ezyme测试它,但是我得到一个错误或者一个带有浅渲染的空对象,如下所述 使用react redux的钩子测试组件的正确方法是什么 Todos.js export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed; const Todos=()=>{ const{todos}=useSelector(state=>state); 返回(
export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;
const Todos=()=>{
const{todos}=useSelector(state=>state);
返回(
{todo.map(todo=>(
- {todo.title}
))}
);
};
Todos.test.jsv1
。。。
它('渲染而不崩溃',()=>{
常量包装器=浅();
expect(wrapper.toMatchSnapshot();
});
它('应呈现ul',()=>{
常量包装器=浅();
expect(wrapper.find('ul').length).toBe(1);
});
v1错误:
...
Invariant Violation: could not find react-redux context value;
please ensure the component is wrapped in a <Provider>
...
。。。
不变冲突:找不到react redux上下文值;
请确保组件包装在
...
Todos.test.jsv2
。。。
//从react redux导入的提供程序
它('渲染而不崩溃',()=>{
常数包装=浅(
,
);
expect(wrapper.toMatchSnapshot();
});
它('应呈现ul',()=>{
常量包装器=浅();
expect(wrapper.find('ul').length).toBe(1);
});
v2测试也会失败,因为wrapper
是
,在wrapper
上调用dive()
将返回与v1相同的错误
提前感谢您的帮助 我可以使用酶安装工具测试使用redux钩子的组件,并向提供商提供模拟存储: 组件
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;
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)
})
})
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;
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);
});
});
从“React”导入React;
从“./路由器”导入AppRouter
从“react redux”导入{useDispatch,useSelector}
从“./Redux/Startup”导入StartupActions
从“./Components/Startup”导入启动
导入“/App.css”;
//这是主要组件,它包括管理的路由器
//路由到不同的视图。
//这也是声明组件的正确位置,应该
//到处显示,即插座、服务等,。。。
函数应用程序(){
const dispatch=usedpatch()
const startupComplete=useSelector(state=>state.startup.complete)
如果(!startupComplete){
setTimeout(()=>dispatch(StartupActions.startup()),1000)
}
返回(
{startupComplete?:}
);
}
导出默认应用程序;
测试
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;
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)
})
})
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;
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);
});
});
从“React”导入React;
从“react redux”导入{Provider}
从“酶”导入{mount,shallow}
从“redux模拟存储”导入configureMockStore
从“redux thunk”导入thunk;
从“../App”导入应用程序;
const mockStore=configureMockStore([thunk]);
描述('App',()=>{
它('如果启动未完成,则应呈现启动组件',()=>{
常量存储=模拟存储({
启动:{完成:错误}
});
常量包装器=装入(
)
expect(wrapper.find('Startup').length).toEqual(1)
})
})
如果您使用在另一个文件中定义的函数选择器,那么除了@abidibo之外还有另一种方法。您可以模拟useSelector
和选择器函数,然后从以下位置使用shallow
:
组件
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;
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)
})
})
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;
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);
});
});
测试
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;
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)
})
})
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;
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);
});
});
import*as React from'React';
从“酶”导入{shall};
从“./Example”导入示例;
从“./按钮”导入按钮;
从“/选择器”导入{getIsSpinnerDisplayed};
mock('react-redux',()=>({
useSelector:jest.fn(fn=>fn()),
}));
开玩笑的模仿(“/选择器”);
描述('示例',()=>{
它('如果getIsSpinnerDisplayed返回false,则应呈现按钮',()=>{
getIsSpinnerDisplayed.mockReturnValue(false);
常量包装器=浅();
expect(wrapper.find(Button.exists()).toBe(true);
});
});
它可能有点粗糙,但对我来说效果很好:)这对我来说也很好:
import { shallow, mount } from "enzyme";
const store = mockStore({
startup: { complete: false }
});
describe("==== Testing App ======", () => {
const setUpFn = props => {
return mount(
<Provider store={store}>
<App />
</Provider>
);
};
let wrapper;
beforeEach(() => {
wrapper = setUpFn();
});
从“酶”导入{shall,mount};
常量存储=模拟存储({
启动:{完成:错误}
});
描述(“===测试应用程序===”,()=>{
常量设置fn=props=>{
回座(
);
};
让包装纸;
在每个之前(()=>{
包装器=setUpFn();
});
模拟使用选择器可以做到这一点
import * as redux from 'react-redux'
const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue({ username:'test' })
在寻找帮助后,我结合了我找到的一些方法来模拟useSelector 首先创建一个函数,在测试之前进行一些引导。 使用一些要覆盖的值设置存储,并模拟react redux的useSelector函数 我认为它对于创建多个测试用例非常有用,在这些测试用例中,您可以看到存储状态如何影响组件的行为
import configureMockStore from 'redux-mock-store';
import * as Redux from 'react-redux';
import MyComponent from './MyComponent';
const mockSelectors = (storeValues) => {
const mockStore = configureMockStore()({
mobile: {
isUserConnected: false
...storeValues
},
});
jest
.spyOn(Redux, 'useSelector')
.mockImplementation(state => state.dependencies[0](mockStore.getState()));
};
describe('isUserConnected: true', () => {
beforeEach(() => {
mockSelectors({ isUserConnected: true });
component = shallow(<MyComponent />);
test('should render a disconnect button', () => {
expect(component).toBeDefined();
expect(component.find('button')).toBeTruthy();
});
});
});
从“redux mock store”导入configureMockStore;
从“react Redux”导入*作为Redux;
从“/MyComponent”导入MyComponent;
常量mockSelectors=(storeValues)=>{
const mockStore=configureMockStore()({
流动电话:{
isUserConnected:false
…存储值
},
});
开玩笑
.spyOn(Redux,“使用选择器”)
.mockImplementation(state=>state.dependencies[0](mockStore.getState());
};
描述('isUserConnected:true',()=>{
在每个之前(()=>{
mockselector({isUserConnected:true});
组件=浅();
测试('应呈现断开连接按钮',()=>{
expect(component.toBeDefined();
expect(component.find('button')).toBeTruthy();
});
});
});
和组件:
import React from 'react';
import { shallowEqual, useSelector } from 'react-redux';
const MyComponent = () => {
const isConnected = useSelector(selectIsConnected, shallowEqual);
return (
<>
{
showDisconnect ? (
<button type="button" onClick={() => ()}>disconnect</button>
) : null
}
</>
);
};
export default MyComponent;
从“React”导入React;
从'react redux'导入{shallowEqual,useSelector};
常量MyComponent=()=>{
const isConnected=使用选择器(选择isConnected,shallewequal);
返回(
{
显示断开连接(
()}>断开连接
):null
}
);
};
导出默认MyComponent;
下面的代码适合我
import { configure, shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ServiceListingScreen from './ServiceListingScreen';
import renderer from 'react-test-renderer';
import { createStore } from 'redux';
import serviceReducer from './../store/reducers/services';
import { Provider } from 'react-redux'
const store = createStore(serviceReducer ) ;
configure({adapter: new Adapter()});
const ReduxProvider = ({ children, reduxStore }) => (
<Provider store={reduxStore}>{children}</Provider>
)
describe('Screen/ServiceListingScreen', () => {
it('renders correctly ', () => {
const wrapper = shallow(<Provider store={store}><ServiceListingScreen /></Provider>);
const tree = renderer.create(wrapper).toJSON();
expect(tree).toMatchSnapshot();
});
});
从“酶”导入{configure,shallow};
从'enzyme-Adapter-react-16'导入适配器;
导入服务列表