我正在构建一个连接到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.AppHeader
或state.get('AppHeader')
,除了少数几个以外如何连接redux并做出反应,但没有那么多测试它。
我试图放弃使用redux-mock-store,并创建我自己的商店(即具有调度,订阅等功能),但这并没有解决任何问题,只创建了新问题。也许我需要重新调查一下,如果这是最好的方式。
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')
);
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
);
import AppHeader from './AppHeader.duck';
export {
AppHeader
};
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;
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);
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
创建的。