Search code examples
reactjsreduxjestjsenzymestore

Jest/Enzyme TypeError: (0 , _store.configureStore) is not a function


This is my first time testing a react component with redux store related stuff and really confused on pretty much everything. Tried all google research and still not knowing what to do. The component looks like below and got two errors in testing console

  • TypeError: (0 , _store.configureStore) is not a function
  • TypeError: Cannot read property 'getState' of undefined

the component:

import PropTypes from 'prop-types';
import __includes from 'lodash/includes';
import __isEmpty from 'lodash/isEmpty';
import __lowerCase from 'lodash/lowerCase';
import __toLower from 'lodash/toLower';
import { connect } from 'react-redux';

import { setEmailErrorClass, setPasswordErrorClass, setConfirmPasswordErrorClass } from '../../../redux/actions';
import './TextboxWrapper.scss';

const { notify } = require('../../../services/functions');

class Textbox extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      value: this.props.defaultValue !== undefined ? this.props.defaultValue : '',
      name: this.props.name,
      errorClass: '',
      errorMessage: ''
    };

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

  componentWillReceiveProps(nextProps) {
    if (nextProps.isError) {
      this.setState({ errorClass: 'error' });
    }
  }

 // ...some functions...
  

  render() {
    return (
      <div data-type={this.props.type} className={`textbox-wrapper ${this.state.errorClass}`}>
        {
          this.props.type === 'payment' ? (
            <div id={this.props.id} className={this.props.extraClass}></div>
          ) : (
              <input
                type={this.props.type}
                placeholder={this.props.placeholder}
                onChange={e => this.onChange(e)}
                onBlur={this.checkErrors}
                value={this.state.value}
                name={this.props.name}
                min={this.props.min}
                max={this.props.max}
                onFocus={this.props.onFocus}
              />
            )
        }
      </div>
    );
  }
}

const mapDispatchToProps = { setEmailErrorClass, setPasswordErrorClass, setConfirmPasswordErrorClass };

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

Below is configureStore:

import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import rootReducer from './rootReducer';

const store = configureStore({
  reducer: rootReducer,
  middleware: getDefaultMiddleware({
    serializableCheck: false
  })
});

export default store;

Below is Textbox.test.js:

import React from 'react';
import { Textbox } from './index';
import { Provider } from 'react-redux';
import { mount, shallow } from 'enzyme';
import { configureStore } from '../../../redux/store';
import { browserHistory } from 'react-router';

describe('Textbox', function () {
  const baseProps = {[enter image description here][1]
    errorClass: 'nope',
  };

  let store;

  beforeAll(() => {
    store = configureStore({}, browserHistory);
  });

  it('renders a wrapping div with accurate className received from props', () => {
    const wrapper = mount(
      <Provider store={store}>
        <Textbox {...baseProps} />
      </Provider>
    );

    const selectWrapper = wrapper.find('div');

    expect(
      selectWrapper.hasClass(`textbox-wrapper ${baseProps.errorClass}`)
    ).toEqual(true);
  });

Got two errors in console: 

  [1]: https://i.sstatic.net/D0hWk.jpg

Solution

  • '../../../redux/store' doesn't appear to export a configureStore function:

    import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
    import rootReducer from './rootReducer';
    
    const store = configureStore({
      reducer: rootReducer,
      middleware: getDefaultMiddleware({
        serializableCheck: false
      })
    });
    
    export default store;
    

    It default exports the store object.

    I'm guessing you either want to import and use the configured store object in your test:

    import store from '../../../redux/store';
    import { browserHistory } from 'react-router';
    
    describe('Textbox', function () {
      const baseProps = {
        errorClass: 'nope',
      };
    
      it('renders a wrapping div with accurate className received from props', () => {
        const wrapper = mount(
          <Provider store={store}>
            <Textbox {...baseProps} />
          </Provider>
        );
    
        const selectWrapper = wrapper.find('div');
    
        expect(
          selectWrapper.hasClass(`textbox-wrapper ${baseProps.errorClass}`)
        ).toEqual(true);
      });
      ...
    }
    

    Or you want to import configureStore from '@reduxjs/toolkit' and import your reducers and instantiate the store object in the test. This ends up effectively the same as above.

    import { configureStore } from '@reduxjs/toolkit';
    import { browserHistory } from 'react-router';
    import rootReducer from './rootReducer';
    
    describe('Textbox', function () {
      const baseProps = {[enter image description here][1]
        errorClass: 'nope',
      };
    
      let store;
    
      beforeAll(() => {
        store = configureStore({
          reducer: rootReducer,
        });
      });
    
      it('renders a wrapping div with accurate className received from props', () => {
        const wrapper = mount(
          <Provider store={store}>
            <Textbox {...baseProps} />
          </Provider>
        );
    
        const selectWrapper = wrapper.find('div');
    
        expect(
          selectWrapper.hasClass(`textbox-wrapper ${baseProps.errorClass}`)
        ).toEqual(true);
      });
      ...
    }