我有一个组件SampleComponent
,可以安装另一个“连接组件”(即container
)。当我尝试按SampleComponent
测试mount
时(因为我需要componentDidMount
),我收到错误:
不变违规:无法在上下文中找到“存储”或 道具“Connect(ContainerComponent)”。包装根组件 在a中,或明确地将“store”作为prop来传递给 “连接(的ContainerComponent)”。
测试此功能的最佳方式是什么?
答案 0 :(得分:38)
Enzyme's mount采用可选参数。你需要的两个是必要的
options.context: (Object [optional]): Context to be passed into the component
options.childContextTypes: (Object [optional]): Merged contextTypes for all children of the wrapper
您可以使用如下选项对象挂载SampleComponent
:
const store = {
subscribe: () => {},
dispatch: () => {},
getState: () => ({ ... whatever state you need to pass in ... })
}
const options = {
context: { store },
childContextTypes: { store: React.PropTypes.object.isRequired }
}
const _wrapper = mount(<SampleComponent {...defaultProps} />, options)
现在,您的SampleComponent会将您提供的上下文传递给connected component
。
答案 1 :(得分:10)
我基本上做的是引入我的redux
商店(和Provider
)并将其包装在实用程序组件中,如下所示:
export const CustomProvider = ({ children }) => {
return (
<Provider store={store}>
{children}
</Provider>
);
};
然后,我mount
SampleComponent
并对其进行测试:
it('contains <ChildComponent/> Component', () => {
const wrapper = mount(
<CustomProvider>
<SampleComponent {...defaultProps} />
</CustomProvider>
);
expect(wrapper.find(ChildComponent)).to.have.length(1);
});
答案 2 :(得分:3)
您可以使用名称导出来解决此问题:
你应该:
class SampleComponent extends React.Component{
...
render(){
<div></div>
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SampleComponent)
您可以在课前添加导出:
export class SampleComponent extends React.Component{
并导入此组件而不使用redux store:
import { SampleComponent } from 'your-path/SampleComponent';
使用此解决方案,您无需将商店导入测试文件。
答案 3 :(得分:3)
您可以在测试中使用React-Redux的Provider组件包装容器组件。因此,通过这种方法,您实际引用了商店,将其传递给Provider,并在里面测试您的组件。这种方法的优点是您实际上可以为测试创建自定义商店。如果要测试组件的Redux相关部分,则此方法很有用。
也许你不关心测试与Redux相关的部分。如果您只对测试组件的呈现和本地状态相关行为感兴趣,则只需为组件的未连接纯文本版本添加命名导出即可。只是为了澄清何时将“export”关键字添加到您的类中,基本上您说现在可以使用花括号{}或不以2种方式导入类。例如:
export class MyComponent extends React.Component{ render(){ ... }}
...
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)
稍后在您的测试文件中:
import MyComponent from 'your-path/MyComponent'; // it needs a store because you use "default export" with connect
import {MyComponent} from 'your-path/MyComponent'; // don't need store because you use "export" on top of your class.
我希望能帮助那里的任何人。
答案 4 :(得分:2)
还有使用redux-mock-store的选项。
用于测试Redux异步操作创建者和中间件的模拟存储。模拟存储将创建一个分派的动作数组,用作测试的动作日志。
模拟存储在存储对象上提供了Redux所需的必要方法。 您可以指定可选的中间件和应用程序的特定初始状态。
import configureStore from 'redux-mock-store'
const middlewares = []
const mockStore = configureStore(middlewares)
const initialState = {}
const store = mockStore(initialState)
const wrapper = mount(<SampleComponent store={store}/>)
答案 5 :(得分:0)
为了使装饰器语法的使用更具可测试性,我这样做了: https://www.npmjs.com/package/babel-plugin-undecorate
输入:
@anyOldClassDecorator
export class AnyOldClass {
@anyOldMethodDecorator
method() {
console.log('hello');
}
}
输出:
@anyOldClassDecorator
export class AnyOldClass {
@anyOldMethodDecorator
method() {
console.log('hello');
}
}
export class __undecorated__AnyOldClass {
method() {
console.log('hello');
}
}
希望这可以提供可靠的选项3 !