I want to test that function passed from mapDispatchToProps was invoked when button clicking is simulated.
How to test that function which passed from mapDispatchToProps is invoked?
I tried to pass a mocked function by props, but it doesn't work. Any help will be appreciated.
Here below my fake class code and test example.
My component
// All required imports
class App extends React.Component<Props> {
render() {
const { onClick } = this.props;
return (
<>
<h1>Form</h1>
<input />
<button onClick={() => onClick()} />
</>
);
}
}
const mapStateToProps = (state) => {
return {
state
};
};
const mapDispatchToProps = (dispatch) => {
return {
onClick: () => dispatch(actions.onClick())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
My test file
import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16/build/index';
import jsdom from 'jsdom';
import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import ConnectedApp, { App } from './App';
function setUpDomEnvironment() {
const { JSDOM } = jsdom;
const dom = new JSDOM('<!doctype html><html><body></body></html>', { url: 'http://localhost/' });
const { window } = dom;
global.window = window;
global.document = window.document;
global.navigator = {
userAgent: 'node.js',
};
copyProps(window, global);
}
function copyProps(src, target) {
const props = Object.getOwnPropertyNames(src)
.filter(prop => typeof target[prop] === 'undefined')
.map(prop => Object.getOwnPropertyDescriptor(src, prop));
Object.defineProperties(target, props);
}
setUpDomEnvironment();
configure({ adapter: new Adapter() });
const mockStore = configureMockStore();
describe('App', () => {
describe('When App connected to store', () => {
describe('When button clicked', () => {
it('should not crush after click on login button', () => {
const onClick = jest.fn()
const store = mockStore(initialStates[1]);
const wrapper = mount(
<Provider store={store}>
<ConnectedApp />
</Provider>);
wrapper.find('button').simulate('click');
??? how to test that function passed from mapDispatchToProps was fired?
});
});
});
});
Steps: extract each mapDispatchToProps property as a separate action creator function in another file. extract each mapStateToProps property as a separate selector function in another file. write tests for the selectors and action creators.
If you do not supply your own mapDispatchToProps function or object full of action creators, the default mapDispatchToProps implementation just injects dispatch into your component's props.
* Test just the React component alone, you test the dumb component. * Test React-Redux part of the component, then test the connected component. Don’t use decorator @connect to test. You should not use decorators to connect your component as shown below:- To test the dumb component, include
* redux-mock-store — Used to mock our Redux store. If you check the script in package.json I have added ”test”: “jest” So to run the test all you have to do is And Jest will pick all the test files which are put under the folder __test__. Place all your test files under the folder __test__ as Jest by default picks all the test from here.
Once you have your test passing you can take advantage of Snapshot testing from Jest. This has the added benefit of letting you reduce your test code. Here’s an example: If you recall from the Testing Smart Components section of Part 2 I recommended testing your actions separately from your components.
You can help us out by using the "report an issue" button at the bottom of the tutorial. This is part 3 of a 4-part series on testing React / Redux apps using both Jest and Enzyme for a robust testing solution. In this part we’ll cover some simple examples on how to test Redux actions.
I recommend following the approach described in the docs and export the connected component as the default
export for use in the application, and export the component itself as a named export for testing.
For the code above export
the App
class and test the click like this:
import * as React from 'react';
import { shallow } from 'enzyme';
import { App } from './code';
describe('App', () => {
it('should call props.onClick() when button is clicked', () => {
const onClick = jest.fn();
const wrapper = shallow(<App onClick={onClick} />);
wrapper.find('button').simulate('click');
expect(onClick).toHaveBeenCalledTimes(1);
});
});
shallow
provides everything that is needed for testing the component itself. (shallow
even calls React lifecycle methods as of Enzyme
v3)
As you have found, to do a full rendering of the component requires a mock redux
store and wrapping the component in a Provider
. Besides adding a lot of complexity, this approach also ends up testing the mock store and all child components during the component unit tests.
I have found it much more effective to directly test the component, and to export and directly test mapStateToProps()
and mapDispatchToProps()
which is very easy since they should be pure functions.
The mapDispatchToProps()
in the code above can be tested like this:
describe('mapDispatchToProps', () => {
it('should dispatch actions.onClick() when onClick() is called', () => {
const dispatch = jest.fn();
const props = mapDispatchToProps(dispatch);
props.onClick();
expect(dispatch).toHaveBeenCalledWith(actions.onClick());
});
});
This approach makes unit testing the component very simple since you can pass the component props directly, and makes it very simple to test that the component will be handed the correct props by the pure functions (or objects) passed to connect()
.
This ensures that the unit tests are simple and targeted. Testing that connect()
and redux
are working properly with the component and all of its child components in a full DOM rendering can be done in the e2e
tests.
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