为什么我的不可变Redux商店在UI和测试中不一样?

时间:2017-02-06 03:52:42

标签: unit-testing reactjs redux immutable.js

我正在构建一个连接到Redux商店以获取其道具的AppHeader组件。理想情况下,我可能会做不同的事情,但决定用它来测试连接组件(我是React的新手)。

我试图通过使用redux-mock-store来测试这个组件,但是当我在测试中使用它时,UI就失败了。当我在UI中工作时,测试失败。

以下PROBLEM_LINE中的AppHeader.component.js是症状源自的地方。

设置为appHeader: state.get('AppHeader')时,测试成功通过,但控制台显示:

Uncaught TypeError: state.get is not a function at
    Function.mapStateToProps [as mapToProps]`

设置为appHeader: state.AppHeader时,UI会正确显示" Real App Title"在一个内部,但测试现在抛出:

TypeError: Cannot read property 'toJS' of undefined

这似乎是使用Immutable.js结构的问题。如果我使用普通JS对象更改了两个initialState变量,则测试通过并显示正确的值。我觉得我必须使用不可变的错误,或者没有正确设置存储。

我几乎阅读了Google重新发布的所有帖子:测试连接的组件/容器,但大部分都在mapStateToProps中使用state.AppHeaderstate.get('AppHeader'),除了少数几个以外如何连接redux并做出反应,但没有那么多测试它。

我试图放弃使用redux-mock-store,并创建我自己的商店(即具有调度,订阅等功能),但这并没有解决任何问题,只创建了新问题。也许我需要重新调查一下,如果这是最好的方式。

的src / index.js

import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux'
import {Router, browserHistory} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';

import configureStore from './store/configureStore';
import routes from './routes';

const store = configureStore;
const history = syncHistoryWithStore(browserHistory, store);

render(
  <Provider store={store}>
    <Router history={history} routes={routes} />
  </Provider>,
  document.getElementById('root')
);

SRC /存储/ configureStore.js

import {createStore, combineReducers} from 'redux';
import {routerReducer} from 'react-router-redux';

import * as reducers from '../ducks';

const rootReducer = combineReducers({
  routing: routerReducer,
  ...reducers
});

export default createStore(
  rootReducer
);

的src /鸭/ index.js

import AppHeader from './AppHeader.duck';

export {
  AppHeader
};

的src /鸭/ AppHeader.duck.js

import {fromJS} from 'immutable';

////////////
/// Actions

const SET_APP_TITLE = 'new-react/AppHeader/SET_APP_TITLE';

////////////
/// Reducer

const initialState = fromJS({  <-- USING IMMUTABLE HERE
  title: 'Real App Title'
});

export default function reducer(state = initialState, action){
  switch(action.type){
    case SET_APP_TITLE:
      return state.set('title', action.payload.title);
    default:
      return state;
  }
}

////////////
/// Action Creators

export function setAppTitle(title){
  return {
    type: SET_APP_TITLE,
    payload: {title}
  };
}

module.exports = reducer;

的src /组件/ AppHeader.component.js

import React from 'react';
import {connect} from 'react-redux';

export class AppHeader extends React.PureComponent {
  render() {
    const appHeader = this.props.appHeader;
    return (
      <div className="appHeader">
        <h1 className="appHeader_title">
          {appHeader.title}
        </h1>
      </div>
    );
  }
}

AppHeader.propTypes = {
  appHeader: React.PropTypes.object
};

const mapStateToProps = state => {
  return {
    appHeader: state.AppHeader.toJS() <-- PROBLEM LINE
  };
}

export default connect(
  mapStateToProps
)(AppHeader);

的src /组件/ AppHeader.component.spec.js

import React from 'react';
import ReactDOM from 'react-dom';
import {mount} from 'enzyme';
import {Provider} from 'react-redux';
import configureMockStore from 'redux-mock-store'
import {fromJS} from 'immutable';

import AppHeader from './AppHeader';

let initialState = fromJS({    <-- USING IMMUTABLE AGAIN
  AppHeader: {
    title: 'Mock App Title'
  }
});

const mockStore = configureMockStore([])(initialState);

describe('AppHeader', () => {
  let component;

  beforeEach(() => {
    const wrapper = mount(
      <Provider store={mockStore}>
        <AppHeader />
      </Provider>
    );
    component = wrapper.find('AppHeader');
  });

  it('renders without crashing', () => {
     expect(component).toBeDefined();
  });
  it('shows the app title', () => {
    expect(component.find('.appHeader_title').text())
      .toBe('App Header Title');
  });
});

所有依赖项都安装在最后一天左右,npm install的最新版本也是如此。应用程序本身是使用create-react-app创建的。

0 个答案:

没有答案