使用Enzyme测试Redux连接组件时遇store找不到的问题
解决Enzyme测试Redux连接组件时的
Could not find "store" in either the context or props错误 你遇到的这个错误我之前也碰到过,本质是Redux的connect高阶组件找不到它需要的store实例——毕竟测试环境里不像正式项目那样有Provider把store注入到组件树的context里。先回顾下你的测试代码和引入的脚本:
你的测试代码:
import React from 'react' import { shallow, mount, render } from 'enzyme' import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; import Login from '../../src/routes/login/components/Login' configure({ adapter: new Adapter() }) describe('<Login />', () => { test('component has form-group nodes', () => { const component = shallow(<Login />).dive() expect(component.find('.form-group')).to.have.length(2) }); });
引入的外部脚本:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
下面给你几种实用的解决办法,你可以根据测试场景选择:
方法1:直接测试未连接的原始组件(最推荐)
一般来说,我们测试组件的UI逻辑时,不需要重复测试Redux的连接逻辑(这部分Redux官方已经验证过了),所以直接测试未被connect包裹的纯React组件是最省心的。
在你的Login组件文件里,除了默认导出连接后的组件,额外导出原始的未连接组件:
// Login.jsx import { connect } from 'react-redux'; // 导出原始纯组件 export const Login = (props) => { // 组件的UI和业务逻辑 }; // 连接后的组件作为默认导出 export default connect(mapStateToProps, mapDispatchToProps)(Login);
然后在测试文件里导入这个命名导出的原始组件:
// 修改导入语句 import { Login } from '../../src/routes/login/components/Login' // 测试代码简化,不需要dive describe('<Login />', () => { test('component has form-group nodes', () => { const component = shallow(<Login />) expect(component.find('.form-group')).to.have.length(2) }); });
这样就完全不需要处理store的问题,专注测试组件本身的UI表现即可。
方法2:给连接后的组件传递store props
如果你一定要测试连接后的组件,可以创建一个mock store,然后把它作为props直接传给组件:
首先安装redux-mock-store(开发依赖):
npm install redux-mock-store --save-dev
然后修改测试代码:
import React from 'react' import { shallow } from 'enzyme' import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; import configureMockStore from 'redux-mock-store'; import Login from '../../src/routes/login/components/Login' configure({ adapter: new Adapter() }) const mockStore = configureMockStore(); // 可以传入mock的state数据,模拟不同状态下的组件表现 const store = mockStore({ auth: { isLoading: false } }); describe('<Login />', () => { test('component has form-group nodes', () => { const component = shallow(<Login store={store} />).dive() expect(component.find('.form-group')).to.have.length(2) }); });
方法3:通过Enzyme的context传递store
另一种方式是利用Enzyme shallow渲染的context选项来传递store:
import React from 'react' import { shallow } from 'enzyme' import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; import configureMockStore from 'redux-mock-store'; import Login from '../../src/routes/login/components/Login' configure({ adapter: new Adapter() }) const mockStore = configureMockStore(); const store = mockStore({}); describe('<Login />', () => { test('component has form-group nodes', () => { const component = shallow(<Login />, { context: { store } }).dive() expect(component.find('.form-group')).to.have.length(2) }); });
方法4:用Provider包裹组件(适合mount完整渲染)
如果你需要用mount进行完整渲染(比如测试组件生命周期、子组件交互),可以用Redux的Provider组件把Login包裹起来,注入store:
import React from 'react' import { mount } from 'enzyme' import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-15'; import { Provider } from 'react-redux'; import configureMockStore from 'redux-mock-store'; import Login from '../../src/routes/login/components/Login' configure({ adapter: new Adapter() }) const mockStore = configureMockStore(); const store = mockStore({}); describe('<Login />', () => { test('component has form-group nodes', () => { const component = mount( <Provider store={store}> <Login /> </Provider> ); expect(component.find('.form-group')).to.have.length(2) }); });
内容的提问来源于stack exchange,提问作者Dmytro P
相关产品推荐
相关产品推荐

