Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Unit test using jest failed

I am doing Unit tests with jest and enzyme. I have following connected component with hooks. I called redux actions to load data.

import React, {useEffect, useState, useCallBack} from "react";
import {connect} from "react-redux";
import CustomComponent  from "../Folder";
import { loadData, createData, updateData } from "../../redux/actions";

const AccountComponent = (props) => {
  const total = 50;
  const [aIndex, setAIndex] = useState(1);
  const [arr, setArr] = useState(['ds,dsf']);
 //... some state variables here

const getData = () => {
   props.loadData(aIndex, total, arr);
}

useEffect(() => {

  getData();

},[aIndex, total])

//some other useEffect and useCallback

return(
 <React.Fragment>
   <CustomComponent {...someParam}/>
    <div>
     ...
    </div>
 </React.Fragment>
)

}

const mapStateToProps = (state) => {
 const { param1, param2, parma3 } = state.AccountData;
 return {
  param1,
  param2,
  parma3
 }
}

export default connect(mapStateToProps, { loadData, createData, updateData })(AccountComponent)

Here, like following I created some test case for above component.

import AccountComponent from "../";
import React from "react";
import renderer from "react-test-renderer"

describe("AccountComponent component", () => {

 const loadData = jest.fn();
 let wrapper;

 it("snapshot testing", () => {
  const tree = renderer.create(<AccountComponent loadData={loadData} />).toJSON();
  expect(tree).toMatchSnapshot();
 })

  beforeEach(() => {
    wrapper = shallow(<AccountComponent loadData={loadData} />).instance();
  });

  it('should call loadData', () => {
    expect(wrapper.loadData).toHaveBeenCalled();
  });
})

But, It doesn't pass and shows error.

Error for snapshot testing:

invariant violation element type is invalid: expected string or a class/function

Error for method call testing:

Cannot read property 'loadData' of undefined.

Enzyme Internal error: Enzyme expects and adapter to be configured, but found none. ...

Not sure what the issue as I am not good in unit testing.

I am using react-redux 7.

Any help would be greatly appreciated.

Edit:

I also tried with provider like following. But, didn't help.

import { Provider } from "react-redux";
import {createStore} from "redux";
import reducer from "../../reducers";

const store = createStore(reducer);

it("snapshot testing", () => {
      const tree = renderer.create(<Provider store={store}><AccountComponent loadData={loadData} /></Provider>).toJSON();
      expect(tree).toMatchSnapshot();
     })


beforeEach(() => {
        wrapper = shallow(<Provider store={store}><AccountComponent loadData={loadData} /></Provider>).instance();
      });
like image 291
ketan Avatar asked May 04 '26 08:05

ketan


1 Answers

In your case when you are using connected components in the same file you need to pass the state through Provider. Also, you need to configure your enzyme. And finally, when you are using react hooks, you will need to do asynchronous unit tests, because effects are async. When you are trying to check if any function has been called you need to "spy" on it.

import configureStore from 'redux-mock-store';
import React from 'react';
import renderer from 'react-test-renderer';
import Enzyme, { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import Adapter from 'enzyme-adapter-react-16';
import { act } from 'react-dom/test-utils';
import createSagaMiddleware from 'redux-saga';
import AccountComponent from '../AccountComponent';
import * as actions from '../../../redux/actions';

jest.mock('../../../redux/actions', () => ({
  loadData: jest.fn(),
  createData: jest.fn(),
  updateData: jest.fn(),
}));

const loadData = jest.spyOn(actions, 'loadData');

// configure Enzyme
Enzyme.configure({ adapter: new Adapter() });

const configureMockStore = configureStore([createSagaMiddleware]);

const initialState = {
  AccountData: {
    param1: 'param1',
    param2: 'param2',
    parma3: 'parma3 ',
  },
};

const store = configureMockStore(initialState);

describe('AccountComponent component', () => {
  let wrapper;

  it('snapshot testing', () => {
    const tree = renderer
      .create(
        <Provider store={store}>
          <AccountComponent />
        </Provider>,
      )
      .toJSON();
    expect(tree).toMatchSnapshot();
  });

  beforeEach(async () => {
    await act(async () => {
      wrapper = shallow(
        <Provider store={store}>
          <AccountComponent />
        </Provider>,
      );
    });

    await act(async () => {
      wrapper.update();
    });
  });

  it('should call loadData', () => {
    expect(loadData).toHaveBeenCalled();
  });
});

Please mock your AccountData state with properties which will be used in that component. Also, I am not sure where is your test file is located, so you might need to change import path from '../../../redux/actions' to you actions file path. Finally, I am not sure what middleware you are using, so fill free to replace import createSagaMiddleware from 'redux-saga'; with your middleware for redux.

like image 87
Observer Avatar answered May 06 '26 23:05

Observer