33

我有一个SampleComponent安装另一个“连接组件”(即container)的组件。当我尝试SampleComponent通过mounting 进行测试时(因为我需要componentDidMount),我得到了错误:

不变违规:在“Connect(ContainerComponent)”的上下文或道具中找不到“store”。要么将根组件包装在 a 中,要么将“store”作为道具显式传递给“Connect(ContainerComponent)”。

测试这个的最好方法是什么?

4

6 回答 6

43

Enzyme 的 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.

于 2016-09-28T13:43:12.410 回答
11

我本质上所做的是将我的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);
});
于 2016-06-14T19:20:07.373 回答
4

选项1)

您可以在测试中使用 React-Redux 的 Provider 组件包装容器组件。因此,使用这种方法,您实际上引用了 store,将其传递给 Provider,然后在内部编写您的被测组件。这种方法的优点是您实际上可以为测试创建自定义存储。如果您想测试组件中与 Redux 相关的部分,这种方法很有用。

选项 2)

也许你不关心测试 Redux 相关的部分。如果您只是对测试组件的渲染和本地状态相关的行为感兴趣,您可以简单地为组件的未连接纯版本添加一个命名导出。并且只是为了澄清当您将“export”关键字添加到您的类时,您基本上是在说现在可以通过两种方式导入该类,或者使用大括号 {} 或不使用。例子:

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.

我希望可以帮助那里的任何人。

于 2017-09-21T08:06:06.600 回答
4

还可以选择使用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}/>)
于 2018-10-17T08:45:03.647 回答
3

您可以使用名称导出来解决此问题:

你应该有:

class SampleComponent extends React.Component{
...
   render(){
       <div></div>
   }
}

export default connect(mapStateToProps, mapDispatchToProps)(SampleComponent)

您可以在课前添加导出:

export class SampleComponent extends React.Component{

并在没有 redux 存储的情况下导入此组件:

import { SampleComponent } from 'your-path/SampleComponent';

使用此解决方案,您无需将 store 导入您的测试文件。

于 2017-01-26T15:18:09.097 回答
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

于 2018-06-25T04:24:46.310 回答