使用 enzyme.mount().setProps 和 react-redux Provider

using enzyme.mount().setProps with a react-redux Provider

我有一个测试是设置道具,观察组件的一些变化。唯一的麻烦是我将呈现的元素包装在 <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 变量和重新渲染更好的测试方法?

您应该只在包装组件或 parent 上调用 setProps

一个好的经验法则是您的测试应该只测试单个组件(parent),因此不允许使用酶在 children 上设置道具。

https://github.com/airbnb/enzyme/blob/master/docs/api/ShallowWrapper/setProps.md#setpropsnextprops--self

如果您有 child 组件进一步向下我们需要满足存储依赖性(通过提供程序和上下文),那很好,但那些 child 组件应该有自己的隔离测试。

我们鼓励您为 setProps 上的更改编写测试。

如果您发现自己正在为容器或连接器编写测试,您实际上只想验证 child 组件是否正在接收正确的 props 和/或状态。例如:

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 之间的区别,这样你就不会在测试中不必要地模拟 children 的依赖关系,这里的最佳答案是一个很好的阅读:

这是使用 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);
})

将我的组件包装在 Provider 中后,我遇到了同样的问题。我所做的是,我在子组件上使用了 setProps 而不是组件本身。

这是我在测试套件中的组件示例:

 let component, connectedComponent; 
 component = () => {
 store = configureMockStore()(myStore);  
 connectedComponent = mount(
     <Provider >
       <MyComponent store={store} params={{xyz: 123}} />
     </Provider>);};

但是在测试本身中,我这样做了:

connectedComponent.setProps({children: <MyComponent params={{}} />});

我想提供一个与上述类似的解决方案。

使用问题中定义的安装包装器,

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,最快的解决方案是使用类型断言。

另一种方法是使用 wrappingComponent

例如,假设这是您的提供商

const ExampleProvider = ({ children }) => (
      <Provider store={store}>
        {children}
      </Provider>
    );

然后初始化wrapper如下

wrapper = mount(<Component />, { wrappingComponent: ExampleProvider});

然后在测试用例中,你应该可以直接调用wrapper.setProps