Тестирование вложенных компонентов с ферментом внутри React & Redux

у меня есть компонент SampleComponent который монтирует другой " подключенный компонент "(т. е. container). Когда я пытаюсь проверить SampleComponent by mounting (так как мне нужно componentDidMount), Я получаю ошибку:

инвариантное нарушение: не удалось найти "хранилище" ни в контексте, ни реквизит "Connect(ContainerComponent)". Либо оберните корневой компонент в a или явно передать "store" в качестве опоры для "Connect (ContainerComponent)".

каков наилучший способ тестирования это?

5 ответов


держатель энзима принимает опционные параметры. Два, которые необходимы для того, что вам нужно

options.context: (Object [optional]): Context to be passed into the component

options.childContextTypes: (Object [optional]): Merged contextTypes for all children of the wrapper Ты бы сел на лошадь!--3--> С объектом options, как так:

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.


то, что я по существу сделал, было принести в мой 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);
});

1)

вы можете обернуть компонент контейнера компонентом поставщика React-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.

надеюсь, кто-нибудь там поможет.


вы можете использовать экспорт имен для решения этой проблемы:

вы должны:

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';

С помощью этого решения вам не нужно импортировать хранилище в тестовые файлы.


в попытке сделать использование синтаксиса декоратора более проверяемым, я сделал это: 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!