将酶.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() 没有在包装的组件上正确设置道具。我认为这是因为 &lt;Provider&gt; 实际上并没有传递道具,因为它不是 HoC。除了更改本地范围的 prop 变量并重新渲染之外,还有更好的测试方法吗?

【问题讨论】:

现在,我通过mount(el, context, childContextTypes ) 传递上下文而不是用&lt;Provider&gt; 包装解决了问题(尽管不是问题)。 我也有同样的问题。我希望看到您的解决方案使用 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&lt;any&gt; | 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 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

[android命令篇]getprop setprop

Jest和酶有啥区别?

linux命令:挂载mount与卸载umount

你应该知道的那些Android小经验

[Vue]实例化Vue时的两种挂载方式el与$mount

Docker Bind Mount 与 Volume