将酶.mount().setProps 与 react-redux Provider 一起使用
Posted
技术标签:
【中文标题】将酶.mount().setProps 与 react-redux Provider 一起使用【英文标题】:using enzyme.mount().setProps with a react-redux Provider 【发布时间】:2017-07-19 09:37:24 【问题描述】:我有一个设置 props 的测试,以观察组件的一些变化。唯一的复杂之处是我将渲染的元素包装在 <Provider>
中,因为在树的下方还有一些连接的组件。
我正在通过渲染
const el = () => <MyComponent prop1= prop1 />;
const wrapper = mount(<Provider store=store> el() </Provider>);
然后我尝试使用以下方法观察一些变化:
wrapper.setProps( /* new props */ );
// expect()s etc.
问题是setProps()
没有在包装的组件上正确设置道具。我认为这是因为 <Provider>
实际上并没有传递道具,因为它不是 HoC。除了更改本地范围的 prop 变量并重新渲染之外,还有更好的测试方法吗?
【问题讨论】:
现在,我通过mount(el, context, childContextTypes )
传递上下文而不是用<Provider>
包装解决了问题(尽管不是问题)。
我也有同样的问题。我希望看到您的解决方案使用 childContextTypes 为您工作。你介意分享代码吗?
基本上你只需要在上下文中设置商店,例如使用redux-mock-store
。即mount(el, context: store , childContextTypes: store: PropTypes.object.isRequired );
.
非常感谢@GTF 的回复。后来,我能够使用 context 和 childContextTypes 在互联网上关注其他示例。和你现在描述的一样。太棒了!
【参考方案1】:
另一种方法是使用wrappingComponent
。
例如,假设这是您的提供者
const ExampleProvider = ( children ) => (
<Provider store=store>
children
</Provider>
);
然后初始化wrapper
如下
wrapper = mount(<Component />, wrappingComponent: ExampleProvider);
然后在测试用例中,你应该可以直接调用wrapper.setProps
。
【讨论】:
这是将包装组件(例如 Redux Provider 或 React Router)添加到安装有酶的子组件的正确方法。谢谢!【参考方案2】:我想提供与上述类似的解决方案。
使用问题中定义的安装包装器,
const wrapper = mount(<Provider store=store> el() </Provider>);
然后,在测试本身上,您可以简单地克隆子组件,即Provider
中的子组件,然后调用setProps
:
it('should get do x and y', () =>
wrapper.setProps(
children: cloneElement(wrapper.props().children as ReactElement, ...props ),
);
// handle the rest below
);
如果您使用 javascript,则无需包含 as ReactElement
类型断言。
对于那些使用 TypeScript 的人,有必要将其声明为 ReactElement
,因为 ReactChild
可能是 ReactElement<any> | ReactText
类型。由于我们确定在 Provider 中呈现的元素是 ReactElement
,因此最快的解决方案是使用类型断言。
【讨论】:
【参考方案3】:在将组件包装在 Provider 中后,我遇到了同样的问题。我所做的是,我在子组件上使用了 setProps 而不是组件本身。
这是我在测试套件中的组件示例:
let component, connectedComponent;
component = () =>
store = configureMockStore()(myStore);
connectedComponent = mount(
<Provider >
<MyComponent store=store params=xyz: 123 />
</Provider>);;
但在测试本身中,我是这样做的:
connectedComponent.setProps(children: <MyComponent params= />);
【讨论】:
【参考方案4】:这是一种使用setProps
的方法
import Provider from 'react-redux';
const renderComponent = properties => mount(
React.createElement(
props => (
<Provider store=store>
<IntlProvider locale="en" defaultLocale="en" messages=messages>
<Router>
<MyComponent ...props />
</Router>
</Provider>
),
properties))
然后在你的测试中
it('should set some props', () =>
const renderedComponent = renderComponent(props);
renderedComponent.setProps( /* some props */ );
expect(true).toBe(true);
)
【讨论】:
【参考方案5】:您应该只在包装的组件或父组件上调用setProps
。
一个好的经验法则是您的测试应该只测试单个组件(父组件),因此不允许使用酶为子组件设置道具。
https://github.com/airbnb/enzyme/blob/master/docs/api/ShallowWrapper/setProps.md#setpropsnextprops--self
如果您有子组件需要我们满足存储依赖项(通过 Provider 和上下文),那很好,但这些子组件确实应该有自己的独立测试。
我们鼓励您为setProps
上的更改编写测试。
如果您发现自己正在为容器或连接器编写测试,您真的只想验证子组件是否接收到正确的道具和/或状态。例如:
import createMockStore from 'mocks'
import shallwo from 'enzyme'
// this component exports the redux connection
import Container from '../container'
const state = foo: 'bar'
let wrapper
let wrapped
let store
beforeEach(() =>
store = createMockStore(state)
wrapper = shallow(<Container store=store />)
wrapped = wrapper.find('MyChildComponent')
)
it('props.foo', () =>
const expected = 'bar'
const actual = wrapped.prop('foo')
expect(expected).toEqual(actual)
)
另一个提示是,它有助于理解 shallow 和 mount 之间的区别,这样您就不会在测试中不必要地嘲笑孩子的依赖关系,这里的最佳答案是一个很好的阅读:
When should you use render and shallow in Enzyme / React tests?
【讨论】:
这并没有回答问题,有时你想用mount进行测试。如果您使用的是 redux,您应该能够测试您的内部组件并测试它如何管理 prop 更改、未从 store 交付的 props。以上是关于将酶.mount().setProps 与 react-redux Provider 一起使用的主要内容,如果未能解决你的问题,请参考以下文章