So I would like to test mapStateToProps and mapDispatchToProps with Enzyme/Jest.
I have a component DrawerAvatar like this:
DrawerAvatar.js
const mapStateToProps = state => ({
isAuthenticated: state.authReducer.isAuthenticated
});
export default compose(
connect(mapStateToProps, null)
)(DrawerAvatar);
DrawerAvatar.test.js
import configureMockStore from 'redux-mock-store';
import connectedDrawerAvatar, { DrawerAvatar } from './DrawerAvatar';
const mockStore = configureMockStore();
it('mapStateToProps should return the right value', () => {
const initialState = {
someState: 123
};
const store = mockStore(initialState);
const wrapper = shallow(<connectedDrawerAvatar store={store} />);
expect(wrapper.props().someState).toBe(123);
});
However, this doesn't work because wrapper.props().someState returns undefined... So I have no clue how to test mapStatesToProps along with redux-mock-store using the connected component.
I don't know neither how to test mapDispatchToProps ..!
I've tried the methods providing in this blog but it doesn't work.
Thank you very much !
EDIT:
This works, but I'm not sure if it really tests the mapStateToProps... Can someone confirm that this is the right way to test mapStateToProps ?
DrawerAvatar.test.js
it('mapStateToProps should return the right value', () => {
const initialState = {
isAuthenticated: false
};
const mockStore = configureMockStore();
const store = mockStore(initialState);
const wrapper = shallow(<connectedDrawerAvatar store={store} />);
expect(wrapper.props().store.getState().isAuthenticated).toBe(false);
});
One way I found from : redux discussion on github is
import React from 'react';
import { shallow } from 'enzyme';
import configureMockStore from 'redux-mock-store';
import ConnectedDrawerAvatar from './DrawerAvatar';
describe('DrawerAvatar', ()=> {
const mockStore = configureMockStore();
it.each([true, false], 'receives correct value from store as props', (value)=> {
const initialState = { authReducer: { isAuthenticated: value } }
const store = mockStore(initialState)
const wrapper = shallow(<ConnectedDrawerAvatar store={store} />)
expect(wrapper.props().isAuthenticated).toBe(value)
})
})
You can also try this instead :
In my opinion Testing mapStateToProps(), you need to identify the props for the particular state. Also used provider which makes the components available that are wrapped in Connect() function.
import React from 'react';
import { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import ConnectedDrawerAvatar from './DrawerAvatar';
describe('DrawerAvatar', ()=> {
let component;
let store;
let value;
beforeEach(() => {
const initialState = {
authReducer: { isAuthenticated: value }
};
store = mockStore(initialState);
component = shallow(<Provider store={store}><ConnectedDrawerAvatar/></Provider>);
});
it('should return exact value from the store(props)', () => {
expect(component.props().isAuthenticated).toBe(value);
});
});
Hope this helps!
Easiest way to test that is to that mapStateToProps directly, like this:
export const mapStateToProps = state => ({
isAuthenticated: state.authReducer.isAuthenticated
});
and have a test like this:
it('mapStateToProps should return the right value', () => {
const mockedState = {
authReducer: {
isAuthenticated: false
}
};
const state = mapStateToProps(mockedState);
expect(state).toBeFalsy();
});
But I dont really see why you should do that.
IMO you should not test connected components. Just export the container class and test it directly.
The reason why one should not test component connection is that it is tested well in the library itself so by testing that you don't really add any value.
Related
This is a simplified example I've made.
I have the following react component
Test.tsx
import * as React from 'react';
import { useEffect } from 'react';
import { useAppDispatch, useAppSelector } from '../app/hooks';
import { selectTest, setTest } from './testslice';
const Test: React.FunctionComponent = (props) => {
const vals = useAppSelector(selectTest)
const dispatch = useAppDispatch()
useEffect(() => {
dispatch(setTest(["2","3","4","5"]))
},[])
return <>
{vals.map((v,i) => <button key={i}>{v}</button>)}
</>;
};
export default Test;
And the following redux reducer slice
testSlice.ts
import { createSlice, PayloadAction } from "#reduxjs/toolkit";
import { RootState } from "../app/store";
export interface AppState {
test:string[]
}
const initialState: AppState = {
test:[]
};
export const appSlice = createSlice({
name: 'test',
initialState,
reducers: {
setTest(state,action: PayloadAction<string[]>) {
state.test = action.payload
}
},
});
export const {
setTest,
} = appSlice.actions;
export const selectTest = (state: RootState) => state.test.test;
export default appSlice.reducer;
I would like to test the Test component and see, that the buttons are rendered with the values I've dispatched to the redux store (The length of values will be a fixed length)
Test.test.tsx
import React from 'react';
import { render } from '#testing-library/react';
import { Provider } from 'react-redux';
import { store } from '../app/store';
import Test from './TestComponent';
test('renders learn react link', () => {
const { getByText } = render(
<Provider store={store}>
<Test/>
</Provider>
);
//Somehow test that the buttons rendered in <Test/> component have the values dispatched in the useEffect hook
});
How can I achieve this?
Please have a look at the official documentation of testing redux with react and testing library. The idea is to create a preloadedState which gets injected in your application from inside the test. You can then test for the objects of this preloadedState and see if the objects are rendered correctly. After setting up the helper render function in the docs above with e.g.
...
import appReducer from 'PATH/testSlice';
...
store = configureStore({ reducer: { test: appReducer }, preloadedState })
you can then do:
...
import { render } from '../../test-utils'
...
const givenState = { test: ["1", "2", "3"] }
const { getByText } = render( <Test/>, { preloadedState: givenState });
for(const val of givenState.test) {
expect(getByText(val).toBeVisible();
}
For more "integration"-testing, you could also mock return values from functions that finally populate the state, e.g. fetch calls. That way, you would not need to create a preloadedState but mock the fetch calls, whose objects you would use for assertions.
I'm trying to mock out the import { Auth0Provider } from "#auth0/auth0-react"; in a react app and keep running into issues with this error [Error: For security reasons, window.crypto is required to run auth0-spa-js.] From what I can tell this error is coming from the Auth0Client which gets imported from import { Auth0Client } from '#auth0/auth0-spa-js'; My thought is to mock out the scoped module #auth0/auth0-spa-js and do something like this
const handleRedirectCallback = jest.fn(() => ({ appState: {} }));
const buildLogoutUrl = jest.fn();
const buildAuthorizeUrl = jest.fn();
const checkSession = jest.fn();
const getTokenSilently = jest.fn();
const getTokenWithPopup = jest.fn();
const getUser = jest.fn();
const getIdTokenClaims = jest.fn();
const isAuthenticated = jest.fn(() => false);
const loginWithPopup = jest.fn();
const loginWithRedirect = jest.fn();
const logout = jest.fn();
export const Auth0Client = jest.fn(() => {
return {
buildAuthorizeUrl,
buildLogoutUrl,
checkSession,
handleRedirectCallback,
getTokenSilently,
getTokenWithPopup,
getUser,
getIdTokenClaims,
isAuthenticated,
loginWithPopup,
loginWithRedirect,
logout,
};
});
This seems to be working if I import the Auth0Client into any of my tests, but the problem is that the Auth0Provider is still importing the non mocked out client. Is there anyway to get the Auth0Provider to import the mocked out Auth0Client instead of the actual implementation? The file that uses the Auth0Provider looks like this
// test-utils.js
import React from 'react'
import { render as rtlRender } from '#testing-library/react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { MockedProvider } from '#apollo/client/testing';
import { Auth0Provider } from "#auth0/auth0-react";
import { Auth0Client } from '#auth0/auth0-spa-js';
// Import your own reducer
import applicationsReducer from "../app/slices/applications.slice";
import { UserProvider } from "../user-context";
import {getUserMock} from "../__tests__/apollo_mocks/get_user.mock"
// const MockedAuth0Provider = jest.requireActual("#auth0/auth0-react").Auth0Provider
function render(
ui,
{
initialState,
mocks,
store = createStore(applicationsReducer, initialState),
...renderOptions
} = {}
) {
function Wrapper({ children }) {
return <Auth0Provider clientId="__test_client_id__" domain="__test_domain__">
<Provider store={store}>
<MockedProvider mocks={[getUserMock, ...mocks]} addTypename={false}>
<UserProvider>{children}</UserProvider>
</MockedProvider>
</Provider>
</Auth0Provider>
}
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions })
}
// re-export everything
export * from '#testing-library/react'
// override render method
export { render }
Hopefully this helps someone else but I ended up mocking the provider as well as some of the other auth0 modules that I was using this way
jest.mock('#auth0/auth0-react', () => ({
Auth0Provider: ({ children }) => children,
withAuthenticationRequired: ((component, _) => component),
useAuth0: () => {
return {
isLoading: false,
user: { sub: "foobar" },
isAuthenticated: true,
loginWithRedirect: jest.fn()
}
}
}));
This is all in my setupTests.js file
Here is my test
const initialRootState = {
accounts: [mockAccounts],
isLoading: false
}
describe('Account Dashboard', () => {
let rootState = {
...initialRootState
}
const mockStore = configureStore()
const store = mockStore({ ...rootState })
const mockFunction = jest.fn()
jest.spyOn(Redux, 'useDispatch').mockImplementation(() => mockFunction)
jest
.spyOn(Redux, 'useSelector')
.mockImplementation((state) => state(store.getState()))
afterEach(() => {
mockFunction.mockClear()
// Reseting state
rootState = {
...initialRootState
}
})
it('renders correctly', () => {
const wrapper = mount(
<TestWrapper>
<AccountDashboard />
</TestWrapper>
)
console.log(wrapper)
})
})
In my component I am mapping accounts from the state. In my test I am getting the following error TypeError: Cannot read property 'map' of undefined
I would like to test an if statement I am using in my component to ensure it's returning the proper view based on the number of accounts I am receiving.
However, when I console.log(store.getState()) it is printing correctly. What am I doing wrong?
If you're going to test a Redux connected component, I'd recommend steering away from mocking its internals and instead to test it as if it were a React component connected to a real Redux store.
For example, here's a factory function for mounting connected components with enzyme:
utils/withRedux.jsx
import * as React from "react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { mount } from "enzyme";
import rootReducer from "../path/to/reducers";
/*
You can skip recreating this "store" by importing/exporting
the real "store" from wherever you defined it in your app
*/
export const store = createStore(rootReducer);
/**
* Factory function to create a mounted Redux connected wrapper for a React component
*
* #param {ReactNode} Component - the Component to be mounted via Enzyme
* #function createElement - Creates a wrapper around the passed in component with incoming props so that we can still use "wrapper.setProps" on the root
* #returns {ReactWrapper} - a mounted React component with a Redux store.
*/
export const withRedux = Component =>
mount(
React.createElement(props => (
<Provider store={store}>
{React.cloneElement(Component, props)}
</Provider>
)),
options
);
export default withRedux;
Now, using the above factory function, we can test the connected component by simply using store.dispatch:
tests/ConnectedComponent.jsx
import * as React from "react";
import withRedux, { store } from "../path/to/utils/withRedux";
import ConnectedComponent from "../index";
const fakeAccountData = [{...}, {...}, {...}];
describe("Connected Component", () => {
let wrapper;
beforeEach(() => {
wrapper = withRedux(<ConnectedComponent />);
});
it("initially shows a loading indicator", () => {
expect(wrapper.find(".loading-indicator")).exists().toBeTruthy();
});
it("displays the accounts when data is present", () => {
/*
Ideally, you'll be dispatching an action function for simplicity
For example: store.dispatch(setAccounts(fakeAccountData));
But for ease of readability, I've written it out below.
*/
store.dispatch({ type: "ACCOUNTS/LOADED", accounts: fakeAccountData }));
// update the component to reflect the prop changes
wrapper.update();
expect(wrapper.find(".loading-indicator")).exists().toBeFalsy();
expect(wrapper.find(".accounts").exists()).toBeTruthy();
});
});
This vastly simplifies not having to mock the store/useSelector/useDispatch over and over when you start to test other Redux connected components.
On a side note, you can skip this entirely if you use react-redux's connect function while exporting the unconnected component. Instead of importing the default export, you can import the unconnected component within your test...
Example component:
import * as React from "react";
import { connect } from "react-redux";
export const Example = ({ accounts, isLoading }) => { ... };
const mapStateToProps = state => ({ ... });
const mapDispatchToProps = { ... };
export default connect(mapStateToProps, mapDispatchToProps)(Example);
Example test:
import * as React from "react";
import { mount } from "enzyme";
import { Example } from "../index";
const initProps = {
accounts: [],
isLoading: true
};
const fakeAccountData = [{...}, {...}, {...}];
describe("Unconnected Example Component", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<Example {...initProps } />);
});
it("initially shows a loading indicator", () => {
expect(wrapper.find(".loading-indicator")).exists().toBeTruthy();
});
it("displays the accounts when data is present", () => {
wrapper.setProps({ accounts: fakeAccountData, isLoading: false });
wrapper.update();
expect(wrapper.find(".loading-indicator")).exists().toBeFalsy();
expect(wrapper.find(".accounts").exists()).toBeTruthy();
});
});
I figured out that my test was working incorrectly due to my selector function in my component being implement incorrectly. So the test was actually working properly!
Note: My team is currently using mocked data(waiting for the API team to finish up endpoints).
Originally the useSelector function in my component(that I was testing) looked like:
const { accounts, isLoading } = useSelector(
(state: RootState) => state.accounts,
shallowEqual
)
When I updated this to:
const { accounts, isAccountsLoading } = useSelector(
(state: RootState) => ({
accounts: state.accounts.accounts,
isAccountsLoading: state.accounts.isLoading
}),
shallowEqual
)
My tests worked - here are my final tests:
describe('App', () => {
let rootState = {
...initialState
}
const mockStore = configureStore()
const store = mockStore({ ...rootState })
jest.spyOn(Redux, 'useDispatch').mockImplementation(() => jest.fn())
jest
.spyOn(Redux, 'useSelector')
.mockImplementation((state) => state(store.getState()))
afterEach(() => {
jest.clearAllMocks()
// Resetting State
rootState = {
...initialState
}
})
it('renders correctly', () => {
const wrapper = mount(
<TestWrapper>
<Dashboard />
</TestWrapper>
)
expect(wrapper.find('[data-test="app"]').exists()).toBe(true)
expect(wrapper.find(verticalCard).exists()).toBe(false)
expect(wrapper.find(horizontalCard).exists()).toBe(true)
})
it('renders multiple properly', () => {
rootState.info = mockData.info
const wrapper = mount(
<TestWrapper>
<Dashboard />
</TestWrapper>
)
expect(wrapper.find(verticalCard).exists()).toBe(true)
expect(wrapper.find(horizontalCard).exists()).toBe(false)
})
})
I'm modernising a react application that I'm working on and I started to use hooks.
Before the component I had was the classic class component, with the constructor, state and everything. I was hooking it to redux the following way:
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import Logs from "NS/src/Screen/Logs"
import store from 'NS/src/Reducers/store'
const LogsStore = connect(state => ({ store: state.store }))(Logs);
Now I'm following a tutorial on Hooks, so I change my component accordingly:
export default function Logs() {
const {status, filteredStatus} = this.props.store
const [filter, setFilter] = React.useState('')
clearLogs = () => {
...
}
...
}
the problem is that now this is undefined. How can I access the store from this kind of component?
this is undefined because functional components do not have an instance, the redux props are available at props which is a regular object
const mapState = state => ({ foo : state.foo })
const Component = connect(mapState)(props =>{
console.log(props.foo)
})
Props are passed as an argument to your functional component:
export default function Logs(props) {
const {status, filteredStatus} = props.store
const [filter, setFilter] = React.useState('')
clearLogs = () => {
...
}
...
}
...and if you're into saving lines:
export default function Logs({ store: { status, filteredStatus } }) {
const [filter, setFilter] = React.useState('')
clearLogs = () => {
...
}
...
}
Hi I am writing test for functional component using the jest and enzyme. and When I simulate a click then params(state of component using useState) of component change. and when state is changed then useEffect call and in useEffect I am dispatching some asynchronous actions with params after changed. So I want to test params with I am dispatching the action. for this I want to mock dispatch. How can I achieve this ?
Anyone can help me, thanks in advance. Below I am sharing the code.
component.js
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { clientOperations, clientSelectors } from '../../store/clients';
import Breadcrumb from '../../components/UI/Breadcrumb/Breadcrumb.component';
import DataTable from '../../components/UI/DataTable/DataTable.component';
import Toolbar from './Toolbar/Toolbar.component';
const initialState = {
search: '',
type: '',
pageNo: 0,
rowsPerPage: 10,
order: 'desc',
orderBy: '',
paginated: true,
};
const Clients = ({ history }) => {
const { t } = useTranslation();
const dispatch = useDispatch();
const totalElements = useSelector(state => state.clients.list.totalElements);
const records = useSelector(clientSelectors.getCompaniesData);
const [params, setParams] = useState(initialState);
useEffect(() => {
dispatch(clientOperations.fetchList(params));
}, [dispatch, params]);
function updateParams(newParams) {
setParams(state => ({
...state,
...newParams,
}));
}
function searchHandler(value) {
updateParams({
search: value,
pageNo: 0,
});
}
function typeHandler(event) {
updateParams({
type: event.target.value,
pageNo: 0,
});
}
function reloadData() {
setParams(initialState);
}
const columns = {
id: t('CLIENTS_HEADING_ID'),
name: t('CLIENTS_HEADING_NAME'),
abbrev: t('CLIENTS_HEADING_ABBREV'),
};
return (
<>
<Breadcrumb items={[{ title: 'BREADCRUMB_CLIENTS' }]}>
<Toolbar
search={params.search}
setSearch={searchHandler}
type={params.type}
setType={typeHandler}
reloadData={reloadData}
/>
</Breadcrumb>
<DataTable
rows={records}
columns={columns}
showActionBtns={true}
deletable={false}
editHandler={id => history.push(`/clients/${id}`)}
totalElements={totalElements}
params={params}
setParams={setParams}
/>
</>
);
};
Component.test.js
const initialState = {
clients: {
list: {
records: companies,
totalElements: 5,
},
},
fields: {
companyTypes: ['All Companies', 'Active Companies', 'Disabled Companies'],
},
};
const middlewares = [thunk];
const mockStoreConfigure = configureMockStore(middlewares);
const store = mockStoreConfigure({ ...initialState });
const originalDispatch = store.dispatch;
store.dispatch = jest.fn(originalDispatch)
// configuring the enzyme we can also configure using Enjym.configure
configure({ adapter: new Adapter() });
describe('Clients ', () => {
let wrapper;
const columns = {
id: i18n.t('CLIENTS_HEADING_ID'),
name: i18n.t('CLIENTS_HEADING_NAME'),
abbrev: i18n.t('CLIENTS_HEADING_ABBREV'),
};
beforeEach(() => {
const historyMock = { push: jest.fn() };
wrapper = mount(
<Provider store={store}>
<Router>
<Clients history={historyMock} />
</Router>
</Provider>
);
});
it('on changing the setSearch of toolbar should call the searchHandler', () => {
const toolbarNode = wrapper.find('Toolbar');
expect(toolbarNode.prop('search')).toEqual('')
act(() => {
toolbarNode.props().setSearch('Hello test');
});
toolbarNode.simulate('change');
****here I want to test dispatch function in useEffect calls with correct params"**
wrapper.update();
const toolbarNodeUpdated = wrapper.find('Toolbar');
expect(toolbarNodeUpdated.prop('search')).toEqual('Hello test')
})
});
[upd] I've changed my mind dramatically since then. Now I think mocking store(with redux-mock-store or even real store that changes its state) - and wrapping component with <Provider store={mockedStore}> - is way more reliable and convenient. Check another answer below.
if you mock react-redux you will be able to verify arguments for useDispatch call. Also in such a case you will need to re-create useSelector's logic(that's really straightforward and actually you don't have to make mock be a hook). Also with that approach you don't need mocked store or <Provider> at all.
import { useSelector, useDispatch } from 'react-redux';
const mockDispatch = jest.fn();
jest.mock('react-redux', () => ({
useSelector: jest.fn(),
useDispatch: () => mockDispatch
}));
it('loads data on init', () => {
const mockedDispatch = jest.fn();
useSelector.mockImplementation((selectorFn) => selectorFn(yourMockedStoreData));
useDispatch.mockReturnValue(mockedDispatch);
mount(<Router><Clients history={historyMock} /></Router>);
expect(mockDispatch).toHaveBeenCalledWith(/*arguments your expect*/);
});
import * as redux from "react-redux";
describe('dispatch mock', function(){
it('should mock dispatch', function(){
//arrange
const useDispatchSpy = jest.spyOn(redux, 'useDispatch');
const mockDispatchFn = jest.fn()
useDispatchSpy.mockReturnValue(mockDispatchFn);
//action
triggerYourFlow();
//assert
expect(mockDispatchFn).toHaveBeenCalledWith(expectedAction);
//teardown
useDispatchSpy.mockClear();
})
}});
From functional component we mock dispatch like above to stop it to execute the real implementation. Hope it helps!
This is how I solved using react testing library:
I have this wrapper to render the components with Provider
export function configureTestStore(initialState = {}) {
const store = createStore(
rootReducer,
initialState,
);
const origDispatch = store.dispatch;
store.dispatch = jest.fn(origDispatch)
return store;
}
/**
* Create provider wrapper
*/
export const renderWithProviders = (
ui,
initialState = {},
initialStore,
renderFn = render,
) => {
const store = initialStore || configureTestStore(initialState);
const testingNode = {
...renderFn(
<Provider store={store}>
<Router history={history}>
{ui}
</Router>
</Provider>
),
store,
};
testingNode.rerenderWithProviders = (el, newState) => {
return renderWithProviders(el, newState, store, testingNode.rerender);
}
return testingNode;
}
Using this I can call store.dispatch from inside the test and check if it was called with the action I want.
const mockState = {
foo: {},
bar: {}
}
const setup = (props = {}) => {
return { ...renderWithProviders(<MyComponent {...props} />, mockState) }
};
it('should check if action was called after clicking button', () => {
const { getByLabelText, store } = setup();
const acceptBtn = getByLabelText('Accept all');
expect(store.dispatch).toHaveBeenCalledWith(doActionStuff("DONE"));
});
I see advantages in using actual <Provider store={store}>:
much easier to write tests
much more readable since just store's data is actually mocked(one mock instead of multiple - and sometimes inconsistent - mocks for useDispatch and useSelector)
But introducing real store with real reducer(s) and real dispatching looks like overkill to me as for unit testing(but would be ok to integration testing):
mocking all the server requests might be a huge task
typically we already have that logic covered with test on per-slice basis
With this in mind have picked configureStore from redux-mock-store instead redux and got next helper(uses Enzyme):
import { act } from 'react-dom/test-utils';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
function renderInRedux(
children,
initialData = {}
) {
let state = initialData;
const store = (configureMockStore([thunk]))(() => state);
const wrapper = mount(
<Provider store={store}>
{children}
</Provider>
);
return {
/*
since Enzyme wrappers are readonly, we need retrieve target element in unit test each time after any interaction
*/
getComponent() {
return wrapper.childAt(0);
},
/*
set store to any desired config; previous value is replaced;
*/
replaceStore(newState) {
act(() => {
state = newState;
store.dispatch({ type: dummyActionTypeName }); // just to trigger listeners
});
wrapper.update();
},
/*
bridge to redux-mock-store's getActions
*/
getActions() {
return store.getActions().filter(({ type }) => type !== dummyActionTypeName);
},
/*
bridge to redux-mock-store's clearActions()
*/
clearActions() {
return store.clearActions();
},
};
}
And example of usage:
const {
getComponent,
replaceStore,
} = renderInRedux(<Loader />, { isRequesting: false });
expect(getComponent().isEmptyRender()).toBeTruthy();
replaceStore({ isRequesting: true });
expect(getComponent().isEmptyRender()).toBeFalsy();
But how would it help to avoid mocking server side interaction if we want to test dispatching? Well, by itself it does not. But we can mock and test action dispatching in easy way:
import { saveThing as saveThingAction } from '../myActions.js';
jest.mock('../myActions.js', () => ({
saveThing: jest.fn().mockReturnValue({ type: 'saveThing' })
}));
beforeEach(() => {
});
....
const { getComponent, getActions } = renderInRedux(
<SomeForm />,
someMockedReduxStore
);
getComponent().find(Button).simulate('click');
expect(getActions()).toContainEqual(saveThingAction());
expect(saveThingAction).toHaveBeenCalledWith(someExpectedArguments);
import * as ReactRedux from 'react-redux'
describe('test', () => {
it('should work', () => {
const mockXXXFn = jest.fn()
const spyOnUseDispatch = jest
.spyOn(ReactRedux, 'useDispatch')
.mockReturnValue({ xxxFn: mockXXXFn })
// Do something ...
expect(mockXXXFn).toHaveBeenCalledWith(...)
spyOnUseDispatch.mockRestore()
})
})
UPDATE: DO NOT use React Redux hooks API which is strongly coupling with Redux store implementation logic, make it very difficult to test.