I'm facing an issue while I'm trying to write unit testing for the below code.
The code below is for component which connects with redux in order to either show data or making a logical operation to show or hide components.
import React, { FC, useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { getRates } from '../store/action-creators/getRates';
import { Table, Button, Loading, Model } from 'components';
import { RootState } from 'store';
import { HomeProps } from './types/Home';
const Home: FC<HomeProps> = ({ rates, loading, error, getRates }) => {
const [ showErrorModal, setShowErrorModal ] = useState<boolean>(false);
useEffect(
() => {
if (error) {
setShowErrorModal(true);
}
},
[ error ]
);
const handleCloseErrorModal = () => {
setShowErrorModal(false);
};
return (
<div className="home">
<Button onClick={getRates} />
{loading ? <Loading /> : <Table rates={rates} />}
{showErrorModal && <Model message={error} onClose={handleCloseErrorModal} />}
</div>
);
};
const mapStateToProps = (state: RootState) => ({
rates: state.rates.rates,
loading: state.rates.loading,
error: state.rates.error
}
);
const mapDispatchToProps = {
getRates
};
const connector = connect(mapStateToProps, mapDispatchToProps) as any;
export default connector(Home);
The test file.
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import Home from '../Home';
import { getRates } from '../../store/action-creators/getRates';
const mockStore = configureStore();
describe('Home component', () => {
it('renders correctly when loading is true', () => {
const initialState = {
rates: {
loading: true,
},
};
const store = mockStore(initialState);
const { getByTestId } = render(
<Provider store={store}>
<Home />
</Provider>
);
const loadingElement = getByTestId('loading');
expect(loadingElement).toBeInTheDocument();
});
it('renders correctly when loading is false', () => {
const initialState = {
rates: {
loading: false,
rates: {
USD: 1.0808,
JPY: 158.35,
},
},
};
const store = mockStore(initialState);
const { getByTestId } = render(
<Provider store={store}>
<Home />
</Provider>
);
const tableElement = getByTestId('rates-table');
expect(tableElement).toBeInTheDocument();
});
it('displays error modal when error is not null', async () => {
const initialState = {
rates: {
loading: false,
error: 'Network error',
},
};
const store = mockStore(initialState);
const { getByTestId, getByText } = render(
<Provider store={store}>
<Home />
</Provider>
);
const errorButtonElement = getByTestId('error-button');
fireEvent.click(errorButtonElement);
const errorModalElement = await waitFor(() => getByTestId('error-modal'));
expect(errorModalElement).toBeInTheDocument();
const errorMessageElement = getByText('Network error');
expect(errorMessageElement).toBeInTheDocument();
});
it('dispatches getRates action when button is clicked', () => {
const initialState = {
rates: {
loading: false,
},
};
const store = mockStore(initialState);
store.dispatch = jest.fn();
const { getByTestId } = render(
<Provider store={store}>
<Home />
</Provider>
);
const buttonElement = getByTestId('get-rates-button');
fireEvent.click(buttonElement);
expect(store.dispatch).toHaveBeenCalledWith(getRates());
});
});
When ever I try to test this file it keep showing the below error.
Any suggestions for that?
Axios is built as ES Module instead of CommonJs when not run in Node. Problem with Jest is that it runs code in Node. This is why telling Jest to transform Axios works.
Axios SDK is shipped with a built CommonJs file for Node env. So, we can fix it by adding this to your package.json:
"jest": {
"moduleNameMapper": {
"^axios$": "axios/dist/node/axios.cjs"
}
}
or in your jest.config.(ts|js|json):
"moduleNameMapper": {
"^axios$": "axios/dist/node/axios.cjs"
}
You can read more here.
moduleNameMapper [object<string, string | array<string>>]A map from regular expressions to module names or to arrays of module names that allow to stub out resources, like images or styles with a single module.