Testing a Redux action that dispatches 2 other functions with Jest? - redux

I have a function (a Redux action) which calls 2 functions. I can't figure how how to test this with Jest:
This is my function:
import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';
export default () => async dispatch => {
await dispatch(doSomething());
dispatch(doSomethingElse());
};
This is my test:
import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';
import functionToTest from 'redux/function-to-test'
describe("functionToTest", ()=>{
jest.mock('redux/do-something');
jest.mock('redux/do-something-else');
const dispatch = jest.fn();
test('my test', ()=>{
functionToTest()(dispatch);
console.log(dispatch.mock.calls); // This returns an anonymous function
console.log(doSomething) // This returns undefined
})
})

It looks like you are wanting to mock the default export for do-something and do-something-else and test that they get dispatched by the code under test.
If that is the case then you can do it like this:
import functionToTest from 'redux/function-to-test'
jest.mock('redux/do-something', () =>
() => 'do something mock'
);
jest.mock('redux/do-something-else', () =>
() => 'do something else mock'
);
describe("functionToTest", () => {
test('my test', async () => { // <= async test function
const dispatch = jest.fn();
await functionToTest()(dispatch); // <= await the Promise
expect(dispatch.mock.calls[0][0]).toBe('do something mock'); // Success!
expect(dispatch.mock.calls[1][0]).toBe('do something else mock'); // Success!
});
});
Details
You can pass a module factory function as the second paramter to jest.mock and Jest will use the result of calling the function as what it gives back when the module is imported during the test.
jest.mock calls get hoisted by babel-jest and run before everything else in the code file. The hoisting doesn't work right when jest.mock is defined in a test function so the jest.mock calls should be moved to the top level scope of the test file.
The function under test is async so use an async test function and await the Promise to make sure it has completed before asserting.

Related

Jest testing mocking default constructor and static constant

I want to test the following code:
import messaging from '#react-native-firebase/messaging';
export const canRequestPushNotificationPermission = async () => {
return (
(await messaging().hasPermission()) ===
messaging.AuthorizationStatus.NOT_DETERMINED
);
};
I noticed that in order to test messaging() I needed to mock the default constructor like so:
jest.mock('#react-native-firebase/messaging', () => {
return () => ({
hasPermission: jest.fn(() => Promise.resolve(true)),
});
});
However this mocks the default constructor, how can I mock this constructor as well as the messaging.AuthorizationStatus.NOT_DETERMINED?
use spyOn to mock the getter of the property of object
see https://jestjs.io/docs/jest-object#jestspyonobject-methodname
for example,
jest.spyOn(messaging, 'AuthorizationStatus', 'get').mockReturnValue({NOT_DETERMINED: 1})

Calling a helper function requiring dispatch from thunk

I'm using Redux Toolkit, though I don't think that makes a difference.
I've set up a snackbar that reads from store.data.message, and I write the message by setting a value and then clearing the message after a timeout. This happens in a helper function, showMessage.
I call showMessage from my thunks:
export const showMessage = (dispatch: any, message: string) => {
dispatch(setMessage(message))
setTimeout(() => dispatch(clearMessage()), 3000)
}
export const fetchDataState = (): AppThunk => async dispatch => {
const state = await getSystemState()
showMessage(dispatch, 'Fetched system state.')
dispatch(getStateSucceeded(state))
}
I simply want to know if there is a way to write these without having to pass dispatch in every time I call showMessage.
Correct me if I'm wrong, but I imagine I can't write it like a thunk because redux-thunk is middleware that calls the thunks in its own way, and I'm not calling them that way.
Yes, you can write it as a thunk like this:
export const showMessage = (message: string) => (dispatch: AppDispatch) => {
dispatch(setMessage(message))
setTimeout(() => dispatch(clearMessage()), 3000)
}
// call it:
dispatch(showMessage("Hi!"))

Testing async mapDispatchToProps actions with Jest/Enzyme gives error

I am trying to test my mapDispatchToProps actions when an async function is dispatched. I almost tried every possible solution I found and nothing worked so far. I'm always getting the same error:
I'm getting this error:
TypeError: store.dispatch(...).then is not a function
I tried the solution included in redux-mock-store https://github.com/dmitry-zaets/redux-mock-store. I included my middlewares to my mockStore, but it didn't fix the issue.
I tried the solution proposed by Michael Peyper here Testing dispatched actions in Redux thunk with Jest.
We created a function to build the mockStore so I tried to create my mockStore directly within my test file instead, but they both returned the same error.
I can't put all the solutions I tried here because it would take me weeks, but it gives you an idea.
Here's the code for my test:
describe('Component async actions', () => {
const middlewares = [thunk, queryMiddleware];
const createMockStore = configureStore(middlewares);
const store = createMockStore();
afterEach(() => {
jest.clearAllMocks();
});
const someData = {};
const expectedActions = {
type: ADD_DATA,
payload: someData
};
it('should handle addData', () => {
return store.dispatch(actions.addData(someData)).then(() => {
expect(store.getActions()[0]).toEqual(expectedAction);
});
});
});
Here's my mapDispatchToProps:
function mapDispatchToProps(dispatch) {
return {
addData: data => dispatch(addData(data))
.then(({ status }) => {
dispatch(showNotification({ status }));
}),
};
};
I would like to at least be able to get to the expect part and fix this if there's any error in my test, but I can't get passed the dispatch().then
Again, here's the error I get each time: TypeError: store.dispatch(...).then is not a function
Thanks in advance!
I don't know if anyone will get this problem, but I found a solution.
First of all, I had to add my thunk middleware to my createStore from redux-mock-store.
import thunk from 'redux-thunk';
...
const createMockStore = createStore([thunk]);
Then I did a mock of my addData function like this:
import { addData } from 'path/to/addData';
...
jest.mock('path/to/addData');
and I added this code within my test:
addData.mockReturnValue(() =>
new Promise((resolve) => resolve({ status: 200 }));
));
It works!

UnitTest Jest for dispatch Action in Redux

I'm new to unittesting Redux with Jest.
I have the following Action:
export const stepDone = (step) => (dispatch) => {
dispatch({type: STEP_DONE, payload: step});
}
How can I test this function?
Something like this should work:
//Mock the dispatch function with jest's built in mocking functions
const mockDispatch = jest.fn();
//Call the action
stepDone(999)(mockDispatch)
//Check it was called with the correct argument
expect(mockDispatch).toHaveBeenCalledWith({type: STEP_DONE, payload: 999})
The magic of Redux is that when you're testing actions and reducers you're generally just testing pure Javascript so it's not particularly complicated.

How can i test arrow function in mapDispatchToProps of redux by jest

How can I test two simple actions in mapDispatchToProps of my component.
Command for tests that i'm using is jest --coverage, and it tells me to test next lines of my code:
export const mapDispatchToProps = (dispatch) => {
return {
----> rightText: () => dispatch(rightText()),
----> leftText: () => dispatch(leftText()),
};
};
How can I write tests to cover these two arrow functions inside mapDispatchToProps?
I think the easiest way is to pass a spy to mapDispatchToProps and then you can test the functions of returned object:
const actionProps = mapDispatchToProps(spy)
// now you can test them
actionProps.rightText()
actionProps.leftText()
rightText() and leftText() should return an object (if it's synchronous). You can also verify the action object in your spy (or it's a mock here) function.
const mockDispatch = jest.fn()
const actionProps = mapDispatchToProps(mockDispatch)
actionProps.rightText()
actionProps.leftText()
// now you can verify the actions here
mockDispatch.mock.calls[0][0]
mockDispatch.mock.calls[1][0]
And just let you know, you can pass a plain object to connect. In your case you can simply:
connect(mapStateToProps, {
rightText,
leftText
})(Component)

Resources