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();
});
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With