为什么这些Jest测试失败了? TypeError:无法读取未定义的属性“apply”

时间:2017-06-13 14:04:38

标签: javascript reactjs react-redux jestjs enzyme

我有2个组件/测试Login.js和Routes.js都有相同的错误:

  

TypeError:无法读取未定义的'apply'属性   enter image description here

不确定在这里尝试应用的内容......

组件

Login.js

import React from 'react'
import { connect } from "react-redux"
import { bindActionCreators } from 'redux'; 
import { setCurrentUser } from '../../actions/authActions'
import * as api from '../../services/api'
import Notification from '../common/Notification'

const mapDispatchToProps = (dispatch) => {
    return {
        setUser: (user) => {
            bindActionCreators(setCurrentUser(user), dispatch)
        }
    }
};

export class LoginContainer extends React.Component {
    constructor(props) {
        super(props)

        this.state = {};

        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleSubmit(e) {
        ...
    }

    render() {
        return (
            <div className="app-bg">
                ...
            </div>
        )
    }
}

export default connect(null, mapDispatchToProps)(LoginContainer); 

Routes.js

import React from 'react'
import { Route, Switch } from 'react-router-dom'
import LoginContainer from './auth/Login'
import Dashboard from './Dashboard'
import NoMatch from './NoMatch'

const Routes = () => {
    return (
        <Switch>
            <Route exact={ true } path="/" component={ LoginContainer }/>
            <Route path="/dashboard" component={ Dashboard }/>
            <Route component={ NoMatch } />
        </Switch>
    );
}

export default Routes

测试

Login.test

import React from 'react'
import { Provider } from "react-redux"
import ReactTestUtils from 'react-dom/test-utils'
import { createCommonStore } from "../../store";
import { mount, shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { missingLogin } from '../../consts/errors'
// import Login from './Login'
import { LoginContainer as Login } from './Login';
import Notification from '../common/Notification'

const store = createCommonStore();

const user = {
    id: 1,
    role: 'Admin',
    username: 'leongaban'
};
const loginComponent = shallow(
    <Provider store={store}>
        <LoginContainer/>
    </Provider>
);
const fakeEvent = { preventDefault: () => '' };

describe('<Login /> component', () => {
    it('should render', () => {
        const tree = toJson(loginComponent);
        expect(tree).toMatchSnapshot();
    });

    it('should contains the words "Forgot Password"', () => {
        expect(loginComponent.contains('Forgot Password')).toBe(true);
    });

    it('should render the Notification component if state.error is true', () => {
        loginComponent.setState({ error: true });
        expect(loginComponent.find(Notification).length).toBe(1);
    });
});

Routes.test

import React from 'react'
import { Provider } from "react-redux"
import { mount, shallow } from 'enzyme'
import { MemoryRouter } from 'react-router'
import { createCommonStore } from "../store";
import toJson from 'enzyme-to-json'

import Routes from './Routes'
import Login from './auth/Login'
import Dashboard from './Dashboard'
import NoMatch from './NoMatch'

const store = createCommonStore();

const routesMount = (path) => {
    return mount(
        <Provider store={store}>
            <MemoryRouter initialEntries={[ path ]} initialIndex={0}>
                <Routes />
            </MemoryRouter>
        </Provider>
    );
};

describe('<Routes /> component', () => {
    it('should save a snapshot', () => {
        const routesComponent = shallow(<Routes />);
        const tree = toJson(routesComponent);
        expect(tree).toMatchSnapshot();
    });

    it('should render Login component when visiting /', () => {
        const routesComponent = routesMount('/');
        expect(routesComponent.find(Login).length).toBe(1);
    });

    it('should render Dashboard component when visiting /dashboard', () => {
        const routesComponent = routesMount('/dashboard');
        expect(routesComponent.find(Dashboard).length).toBe(1);
    });

    it('should render the NoMatch component when visiting invalid path', () => {
        const routesComponent = routesMount('/404');
        expect(routesComponent.find(NoMatch).length).toBe(1);
    });
});

商店

store.js

The Redux Chrome plugin window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

import React from "react"
import { applyMiddleware, combineReducers, compose, createStore} from "redux"
import thunk from "redux-thunk"
import { userReducer } from "./reducers/UserReducer"
import { authReducer } from "./reducers/AuthReducer"

export const createCommonStore = (trackStore=false) => {
    const reducers = combineReducers({
        user: userReducer,
        user: authReducer
    });

    //noinspection JSUnresolvedVariable
    const store = createStore(reducers,
        compose(
            applyMiddleware(thunk),
            window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
        )
    );

    if (trackStore) {
        store.subscribe((() => {
            console.log("  store changed", store.getState());
        }));
    }

    return store;
};

1 个答案:

答案 0 :(得分:6)

store.js中,表达式window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()的计算结果为undefined。这会导致compose中的错误。插件文档具有solution

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers,
    composeEnhancers(
        applyMiddleware(thunk),
    )
);