Test asynchronous nested component - reactjs

Say I have the following wrapper component:
'use strict'
import React, {PropTypes, PureComponent} from 'react'
import {update} from '../../actions/actions'
import LoadFromServerButton from '../LoadFromServerButton'
import {connect} from 'react-redux'
export class FooDisplay extends PureComponent {
render () {
return (
<p>
<span className='foo'>
{this.props.foo}
</span>
<LoadFromServerButton updateFunc={this.props.update} />
</p>
)
}
}
export const mapStateToProps = (state) => {
return {foo: state.foo.foo}
}
FooDisplay.propTypes = {
foo: PropTypes.string
}
export const mapDispatchToProps = (dispatch) => {
return {
update: (foo) => dispatch(update(foo))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(FooDisplay)
and the following inner component:
'use strict'
import React, {PropTypes, PureComponent} from 'react'
import {get} from '../../actions/actions'
import ActiveButton from '../ActiveButton'
import {connect} from 'react-redux'
export class LoadFromServerButton extends PureComponent {
doUpdate () {
return this.props.get().then(this.props.updateFunc)
}
render () {
return (
<ActiveButton action={this.doUpdate.bind(this)} actionArguments={[this.props.foo]} text='fetch serverside address' />
)
}
}
export const mapStateToProps = (state) => {
return {foo: state.foo.foo}
}
export const mapDispatchToProps = (dispatch) => {
return {
get: () => dispatch(get())
}
}
LoadAddressFromServerButton.propTypes = {
updateFunc: PropTypes.func.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(LoadFromServerButton)
ActiveButton is a very thin wrapper around a button with an onclick and arguments destructuring.
Now lets say that I my get action is written as follows:
export const get = () => dispatch => http('/dummy_route')
.spread((response, body) => dispatch(actOnThing(update, body)))
Now if I write a test like so:
/* global window, test, expect, beforeAll, afterAll, describe */
'use strict'
import React from 'react'
import FooDisplay from './index'
import {mount} from 'enzyme'
import {Provider} from 'react-redux'
import configureStore from '../../store/configureStore'
import nock, {uriString} from '../../config/nock'
import _ from 'lodash'
const env = _.cloneDeep(process.env)
describe('the component behaves correctly when integrating with store and reducers/http', () => {
beforeAll(() => {
nock.disableNetConnect()
process.env.API_URL = uriString
})
afterAll(() => {
process.env = _.cloneDeep(env)
nock.enableNetConnect()
nock.cleanAll()
})
test('when deep rendering, the load event populates the input correctly', () => {
const store = configureStore({
address: {
address: 'foo'
}
})
const display = mount(<Provider store={store}><FooDisplay /></Provider>,
{attachTo: document.getElementById('root')})
expect(display.find('p').find('.address').text()).toEqual('foo')
const button = display.find('LoadFromServerButton')
expect(button.text()).toEqual('fetch serverside address')
nock.get('/dummy_address').reply(200, {address: 'new address'})
button.simulate('click')
})
})
This results in:
Unhandled rejection Error: Error: connect ECONNREFUSED 127.0.0.1:8080
After a little bit of thinking, this is due to the fact that the test does not return a promise, as the button click causes the promise to fire under the hood, therefore, afterAll runs immediatly, cleans nock, and a real http connection goes over the wire.
How do I test this case? I don't seem to have an easy way to return the correct promise... How do I test updates to the DOM resulting from these updates?

In order to mock only one method of the imported module, use .requireActual(...)
jest.mock('../your_module', () => ({
...(jest.requireActual('../your_module')),
YourMethodName: () => { return { type: 'MOCKED_ACTION'}; }
}));

As you mentioned the problem is that you dont have the promise to return from test. So to make get return a know promise you can just mock get directly without using nock:
import {get} from '../../actions/actions'
jest.mock('../../actions/actions', () => ({get: jest.fn}))
this will replace the action module with an object {get: jestSpy}
in your test you can then create a promise and let get return this and also return this promise from your test:
it('', ()=>{
const p = new Promise.resolve('success')
get.mockImplementation(() => p)//let get return the resolved promise
//test you suff
return p
})

Related

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();
});
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 are using react it already comes with #testing-library and you don't need enzyme to do snapshot testing. This is how I do my snapshot testing.
import React, { Suspense } from "react";
import { screen } from "#testing-library/react";
import "#testing-library/jest-dom/extend-expect";
import AccountComponent from "../";
import store from "./store";// you can mock the store if your prefer too
describe("<AccountComponent />", () => {
test("it should match snapshot", async () => {
expect.assertions(1);
const { asFragment } = await render(
<Suspense fallback="Test Loading ...">
<Provider store={store}>
<AccountComponent />
</Provider>
</Suspense>
);
expect(asFragment()).toMatchSnapshot();
});
});
When it is a functional component and you are using hooks, unit tests may not work with shallow rendering. You have to use 'renderHooks' instead to create a wrapper. Please refer https://react-hooks-testing-library.com/ for more details.

Jest mock factory not working for class mock

I'm trying to mock an service class to test an React component. But the module factory from jest.mock is not working.
Search component:
import React, { useState } from "react";
import SearchService from "../../services/SearchService";
export default function Search() {
const [searchResults, setSearchResults] = useState([]);
function doSearch() {
const service = new SearchService();
service.search().then(setSearchResults);
}
return (
<div className="component-container">
<div>
<button onClick={doSearch}>search</button>
</div>
{searchResults.map((result) => (
<div key={result}>{result}</div>
))}
</div>
);
}
SearchService:
export default class SearchService {
search = function () {
return new Promise((resolve) => {
setTimeout(
() => resolve(["result 1", "result 2", "result 3", "result 4"]),
1000
);
});
};
}
Test file:
import React from "react";
import { screen, render } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
import { act } from "react-dom/test-utils";
import Search from "../features/search/Search";
jest.mock("../services/SearchService", () => {
return jest.fn().mockImplementation(() => {
return { search: jest.fn().mockResolvedValue(["mock result"]) };
});
});
test("Search", async () => {
render(<Search />);
const button = screen.getByRole("button");
expect(button).toBeDefined();
act(() => {
userEvent.click(button);
});
await screen.findByText("mock result");
});
This is the same structure as the Jest documentation example. In the code above I'm passing the mock implementation through the module factory parameter of the jest.mock.
But it does not work. When I log the new SerchService() I get "mockConstructor {}" and when I run the test it throws the error "service.search is not a function".
When I change my test file to...
import React from "react";
import { screen, render } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
import { act } from "react-dom/test-utils";
import Search from "../features/search/Search";
import SearchService from "../services/SearchService";
jest.mock("../services/SearchService");
test("Search", async () => {
SearchService.mockImplementation(() => {
return { search: jest.fn().mockResolvedValue(["mock result"]) };
});
render(<Search />);
const button = screen.getByRole("button");
expect(button).toBeDefined();
act(() => {
userEvent.click(button);
});
await screen.findByText("mock result");
});
It works...
I kinda can understand why it works in the second way, it is like using jest.spyOn I guess. What I cant understand is why it doesnt work with the first approach.
What I'm doing wrong? How can I mock a module implementation with jest.mock without calling .mockImplementation inside each test?
I found that there is a problem with the documentation and that the factory needs to return an function() (not an arrow function), so I changed the mock to the following and it works:
jest.mock("../services/SearchService.js", () => {
return function () {
return { search: jest.fn().mockResolvedValue(["mock result"]) };
};
});
Found on this post.

How to test a component using react-redux hooks with Enzyme?

I have a simple Todo component that utilizes react-redux hooks that I'm testing using enzyme but I'm getting either an error or an empty object with a shallow render as noted below.
What is the correct way to test components using hooks from react-redux?
Todos.js
const Todos = () => {
const { todos } = useSelector(state => state);
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
Todos.test.js v1
...
it('renders without crashing', () => {
const wrapper = shallow(<Todos />);
expect(wrapper).toMatchSnapshot();
});
it('should render a ul', () => {
const wrapper = shallow(<Todos />);
expect(wrapper.find('ul').length).toBe(1);
});
v1 Error:
...
Invariant Violation: could not find react-redux context value;
please ensure the component is wrapped in a <Provider>
...
Todos.test.js v2
...
// imported Provider from react-redux
it('renders without crashing', () => {
const wrapper = shallow(
<Provider store={store}>
<Todos />
</Provider>,
);
expect(wrapper).toMatchSnapshot();
});
it('should render a ul', () => {
const wrapper = shallow(<Provider store={store}><Todos /></Provider>);
expect(wrapper.find('ul').length).toBe(1);
});
v2 tests also fail since wrapper is the <Provider> and calling dive() on wrapper will return the same error as v1.
To mock useSelector use can do this
import * as redux from 'react-redux'
const spy = jest.spyOn(redux, 'useSelector')
spy.mockReturnValue({ username:'test' })
I could test a component which uses redux hooks using enzyme mount facility and providing a mocked store to the Provider:
Component
import React from 'react';
import AppRouter from './Router'
import { useDispatch, useSelector } from 'react-redux'
import StartupActions from './Redux/Startup'
import Startup from './Components/Startup'
import './App.css';
// This is the main component, it includes the router which manages
// routing to different views.
// This is also the right place to declare components which should be
// displayed everywhere, i.e. sockets, services,...
function App () {
const dispatch = useDispatch()
const startupComplete = useSelector(state => state.startup.complete)
if (!startupComplete) {
setTimeout(() => dispatch(StartupActions.startup()), 1000)
}
return (
<div className="app">
{startupComplete ? <AppRouter /> : <Startup />}
</div>
);
}
export default App;
Test
import React from 'react';
import {Provider} from 'react-redux'
import { mount, shallow } from 'enzyme'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk';
import App from '../App';
const mockStore = configureMockStore([thunk]);
describe('App', () => {
it('should render a startup component if startup is not complete', () => {
const store = mockStore({
startup: { complete: false }
});
const wrapper = mount(
<Provider store={store}>
<App />
</Provider>
)
expect(wrapper.find('Startup').length).toEqual(1)
})
})
There is another way than #abidibo if you use a function selector defined in another file. You can mock useSelector and your selector function, and then use shallow from enzyme:
Component
import * as React from 'react';
import { useSelector } from 'react-redux';
import Spinner from './Spinner';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';
const Example = () => {
const isSpinnerDisplayed = useSelector(getIsSpinnerDisplayed);
return isSpinnerDisplayed ? <Spinner /> : <Button />;
};
export default Example;
Selectors
export const getIsSpinnerDisplayed = state => state.isSpinnerDisplayed;
Test
import * as React from 'react';
import { shallow } from 'enzyme';
import Example from './Example';
import Button from './Button ';
import { getIsSpinnerDisplayed } from './selectors';
jest.mock('react-redux', () => ({
useSelector: jest.fn(fn => fn()),
}));
jest.mock('./selectors');
describe('Example', () => {
it('should render Button if getIsSpinnerDisplayed returns false', () => {
getIsSpinnerDisplayed.mockReturnValue(false);
const wrapper = shallow(<Example />);
expect(wrapper.find(Button).exists()).toBe(true);
});
});
It may be a little bit hacky, but it works well for me :)
Testing React Redux Hooks With Enzyme's Shallow Rendering
After reading through all the responses here and digging through the documentation, I wanted to aggregate the ways to test React components using react-redux hooks with Enzyme and shallow rendering.
These tests rely on mocking the useSelector and useDispatch hooks. I'll also provide examples in both Jest and Sinon.
Basic Jest Example
import React from 'react';
import { shallow } from 'enzyme';
import * as redux from 'react-redux';
import TodoList from './TodoList';
describe('TodoList', () => {
let spyOnUseSelector;
let spyOnUseDispatch;
let mockDispatch;
beforeEach(() => {
// Mock useSelector hook
spyOnUseSelector = jest.spyOn(redux, 'useSelector');
spyOnUseSelector.mockReturnValue([{ id: 1, text: 'Old Item' }]);
// Mock useDispatch hook
spyOnUseDispatch = jest.spyOn(redux, 'useDispatch');
// Mock dispatch function returned from useDispatch
mockDispatch = jest.fn();
spyOnUseDispatch.mockReturnValue(mockDispatch);
});
afterEach(() => {
jest.restoreAllMocks();
});
it('should render', () => {
const wrapper = shallow(<TodoList />);
expect(wrapper.exists()).toBe(true);
});
it('should add a new todo item', () => {
const wrapper = shallow(<TodoList />);
// Logic to dispatch 'todoAdded' action
expect(mockDispatch.mock.calls[0][0]).toEqual({
type: 'todoAdded',
payload: 'New Item'
});
});
});
Basic Sinon Example
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import * as redux from 'react-redux';
import TodoList from './TodoList';
describe('TodoList', () => {
let useSelectorStub;
let useDispatchStub;
let dispatchSpy;
beforeEach(() => {
// Mock useSelector hook
useSelectorStub = sinon.stub(redux, 'useSelector');
useSelectorStub.returns([{ id: 1, text: 'Old Item' }]);
// Mock useDispatch hook
useDispatchStub = sinon.stub(redux, 'useDispatch');
// Mock dispatch function returned from useDispatch
dispatchSpy = sinon.spy();
useDispatchStub.returns(dispatchSpy);
});
afterEach(() => {
sinon.restore();
});
// More testing logic...
});
Testing Multiple useSelector Hooks
Testing multiple useSelectors requires us to mock the Redux app state.
var mockState = {
todos: [{ id: 1, text: 'Old Item' }]
};
Then we can mock our own implementation of useSelector.
// Jest
const spyOnUseSelector = jest.spyOn(redux, 'useSelector').mockImplementation(cb => cb(mockState));
// Sinon
const useSelectorStub = sinon.stub(redux, 'useSelector').callsFake(cb => cb(mockState));
I think this is both the best and the simplest way to mock useSelector hook from Redux store in jest:
import * as redux from 'react-redux'
const user = {
id: 1,
name: 'User',
}
const state = { user }
jest
.spyOn(redux, 'useSelector')
.mockImplementation((callback) => callback(state))
With the idea being that you are able to provide the state store mock with just a subset of store data.
After searching for help I combined some of the methods I found to mock useSelector.
First create a function that does some bootstrapping before your test.
Setting up the store with some values that you want to overwrite and mock the useSelector function of react-redux.
I think it is really useful for creating multiple testcases where u see how the store state influences the behaviour of your component.
import configureMockStore from 'redux-mock-store';
import * as Redux from 'react-redux';
import MyComponent from './MyComponent';
const mockSelectors = (storeValues) => {
const mockStore = configureMockStore()({
mobile: {
isUserConnected: false
...storeValues
},
});
jest
.spyOn(Redux, 'useSelector')
.mockImplementation(state => state.dependencies[0](mockStore.getState()));
};
describe('isUserConnected: true', () => {
beforeEach(() => {
mockSelectors({ isUserConnected: true });
component = shallow(<MyComponent />);
test('should render a disconnect button', () => {
expect(component).toBeDefined();
expect(component.find('button')).toBeTruthy();
});
});
});
And the component:
import React from 'react';
import { shallowEqual, useSelector } from 'react-redux';
const MyComponent = () => {
const isConnected = useSelector(selectIsConnected, shallowEqual);
return (
<>
{
showDisconnect ? (
<button type="button" onClick={() => ()}>disconnect</button>
) : null
}
</>
);
};
export default MyComponent;
Below code works for me.
import { configure, shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import ServiceListingScreen from './ServiceListingScreen';
import renderer from 'react-test-renderer';
import { createStore } from 'redux';
import serviceReducer from './../store/reducers/services';
import { Provider } from 'react-redux'
const store = createStore(serviceReducer ) ;
configure({adapter: new Adapter()});
const ReduxProvider = ({ children, reduxStore }) => (
<Provider store={reduxStore}>{children}</Provider>
)
describe('Screen/ServiceListingScreen', () => {
it('renders correctly ', () => {
const wrapper = shallow(<Provider store={store}><ServiceListingScreen /></Provider>);
const tree = renderer.create(wrapper).toJSON();
expect(tree).toMatchSnapshot();
});
});
You can try redux-saga-test-plan cool redux assertion and running library and lightweight it doest all your heavy lifting of running saga and assertion automatically
const mockState = { rick:"Genius", morty:"dumbAsss"}
expectSaga(yourCoolSaga)
.provide({
select({ selector }, next) {
if (selector) {
return mockState;
}
return next();
}
})
// some assertion here
.put(actions.updateRickMortyPowers(mockState))
.silentRun();
Some of the answers above mocked the useSelector or useDispatch but the redux docs actually advice against that...check out this answer here: https://stackoverflow.com/a/74024854/14432913 which worked for me and followed the example in redux docs
this is worked for me as well :
import { shallow, mount } from "enzyme";
const store = mockStore({
startup: { complete: false }
});
describe("==== Testing App ======", () => {
const setUpFn = props => {
return mount(
<Provider store={store}>
<App />
</Provider>
);
};
let wrapper;
beforeEach(() => {
wrapper = setUpFn();
});

jest.fn() value must be a mock function or spy received function: [Function getTemplates]

I have a function in module called handlelistOfTemplates which calls actions defined in another file. I want to test when handlelistOfTemplates is called the function in actions file is called with correct parameters.
My container component :
import React from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import * as getData from '../../services/DataService';
class Container extends React.Component {
constructor(props){
super(props)
this.props.actions.getTemplates(1);
this.state = {
value: 1
}
}
handlelistOfTemplates = (template, index, value) => {
this.props.selectedTemplate(template);
this.setState({ value });
this.props.actions.getTemplates(template);
};
componentDidMount() {
}
render() {
return(
<ListOfTemplates listOfTemplates={this.props.listOfTemplates} value={this.state.value} onChange={this.handlelistOfTemplates}/>
);
}
}
function mapStateToProps({state}) {
return {
listOfTemplates: state.listOfTemplates
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(getData, dispatch)
};
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(Container);
And my test :
import React from 'react';
import sinon from 'sinon';
import expect from 'expect';
import { shallow } from 'enzyme';
import PropTypes from 'prop-types';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { createMockStore, createMockDispatch } from 'redux-test-utils';
import Container from './Container';
const shallowWithStore = (component, store) => {
const context = {
store,
muiTheme: getMuiTheme(),
};
const childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
store: PropTypes.object.isRequired
}
return shallow(component, { context, childContextTypes });
};
let store;
const loadComponent = (testState) => {
const props = {
actions: {
getTemplates: () => {return Promise.resolve()}
}
}
store = createMockStore(testState)
return shallowWithStore(<Container {...props}/>, store);
}
const getFakeState = () => {
return {
listOfTemplates: [],
};
}
describe('Container', () => {
let testState, component;
describe("when Appeal template is selected from select template dropdown", () => {
beforeAll(() => {
testState = getFakeState();
component = loadComponent(testState);
});
fit('should update the content in editor', (done) => {
component.dive().find('ListOfTemplates').props().onChange('Appeal', 1, 2);
component.update();
done();
expect(component.dive().state().value).toEqual(2) // error value still is at 1
expect(component.instance().props.actions.getTemplates).toHaveBeenCalled();
});
});
});
When I run the above test I get the following error.
expect(jest.fn())[.not].toHaveBeenCalled()
jest.fn() value must be a mock function or spy.
Received:
function: [Function getTemplates]
Is there something else I should be running to get this to work ?may be my mock is not correct.
even i tried doing this :
jest.spyon(component.instance().props.actions, 'getTemplates'); before expect the error remains same.
Also, when i checking the component's local state has been modified or not. I'm not getting the updated state.
when i call component.dive().find('ListOfTemplates').props().onChange('Appeal', 1, 2);
the component.dive().state().value should become 2 but it is 1 instead.
Could you please help me where i'm doing wrong?
You should pass a Mock function getTemplate to your component, otherwise jest won't be able to check whether it was called or not.
You can do that like this: (notice jest.fn() )
const props = {
actions: {
getTemplates: jest.fn(() => Promise.resolve())
}
}

mapDispatchToProps props null in jest test

I have just started my first react job (yay!) and am attempting to write unit tests using jest. i am having an issue with mapDispatchToProps in my test.
please note, the test passes, but it is throwing the following error message:
Warning: Failed prop type: The prop testDispatch is marked as required in TestJest, but its value is undefined in TestJest
error seems to be test related to the test as it is not thrown when running the page in the web browser. also, mapStateToProps works fine, included to show it works.
using enzyme/shallow in order not to interact with the <Child/> component.
testJest.js
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import Child from './Child'
export class TestJest extends React.Component {
render() {
return (<div>ABC - <Child /></div>);
}
}
TestJest.propTypes = {
testDispatch: PropTypes.func.isRequired,
testState: PropTypes.arrayOf(PropTypes.string)
};
const mapStateToProps = (state) => {
return {
testState: state.utilization.pets // ['dog','cat']
};
};
const mapDispatchToProps = (dispatch) => {
return {
testDispatch: () => dispatch({'a' : 'abc'})
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TestJest);
testJest-test.js
import React from 'react';
import { TestJest } from '../Components/testJest';
import TestJestSub2 from '../Components/TestJestSub2';
import { shallow } from 'enzyme';
describe('TESTJEST', () => {
it('matches snapshot', () => {
const wrapper = shallow(<TestJest />);
expect(wrapper).toMatchSnapshot();
});
});
You can pass empty function to TestJest as testDispatch prop:
it('matches snapshot', () => {
const wrapper = shallow(<TestJest testDispatch={() => {}} />);
expect(wrapper).toMatchSnapshot();
});
or pass jest mock function:
it('matches snapshot', () => {
const wrapper = shallow(<TestJest testDispatch={jest.fn()} />);
expect(wrapper).toMatchSnapshot();
});
if you want to check if testDispatch was called (expect(wrapper.instance().props.testDispatch).toBeCalled();)

Resources