使用 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 上设置道具。
如果您有 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
。
我有一个测试是设置道具,观察组件的一些变化。唯一的麻烦是我将呈现的元素包装在 <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 上设置道具。
如果您有 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
。