嵌套组件用React& amp;终极版

时间:2016-06-13 20:38:39

标签: reactjs mocha redux enzyme

我有一个组件SampleComponent,可以安装另一个“连接组件”(即container)。当我尝试按SampleComponent测试mount时(因为我需要componentDidMount),我收到错误:

  

不变违规:无法在上下文中找到“存储”或   道具“Connect(ContainerComponent)”。包装根组件   在a中,或明确地将“store”作为prop来传递给   “连接(的ContainerComponent)”。

测试此功能的最佳方式是什么?

6 个答案:

答案 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)

选项1)

您可以在测试中使用React-Redux的Provider组件包装容器组件。因此,通过这种方法,您实际引用了商店,将其传递给Provider,并在里面测试您的组件。这种方法的优点是您实际上可以为测试创建自定义商店。如果要测试组件的Redux相关部分,则此方法很有用。

选项2)

也许你不关心测试与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