My question is how do we cover these lines in jest?
export const mapDispatchToProps = dispatch => {
return {
submitClaimsForm: form => {
dispatch(submitClaimsForm(form));
}
};
};
In my component this is what the redux connected area looks like:
export function mapStateToProps(state) {
return {
formNonMember: state.form,
submissionSuccess: state.claimSubmission.submissionSuccess
};
}
export const mapDispatchToProps = dispatch => {
return {
submitClaimsForm: form => {
dispatch(submitClaimsForm(form));
}
};
};
let AdditionalDetailsFormConnect = reduxForm({
form: 'AdditionalDetails',
destroyOnUnmount: false
})(AdditionalDetailsForm);
export default connect(
mapStateToProps,
mapDispatchToProps
)(AdditionalDetailsFormConnect);
And this is how the dispatched action is used:
onSubmit() {
this.props.submitClaimsForm(this.props.formattedForm);
}
Next this is what the actual action looks like:
import {postClaimsForm} from '../shared/services/api';
export const Actions = {
SET_SUBMISSION_STATUS: 'SET_SUBMISSION_STATUS'
};
export const submitClaimsForm = form => dispatch => {
return postClaimsForm(form)
.then(res => {
// console.log('promise returned:', res);
return dispatch({
type: Actions.SET_SUBMISSION_STATUS,
submissionSuccess: true
});
})
.catch(error => {
// console.log('error returned:', error);
return dispatch({
type: Actions.SET_SUBMISSION_STATUS,
submissionSuccess: false
});
});
};
What I've tried so far:
it('mapDispatchToProps works as expected', () => {
const actionProps = mapDispatchToProps({
submitClaimsForm: jest.fn()
});
actionProps.submitClaimsForm();
expect(submitClaimsForm).toHaveBeenCalled();
});
But this errors and tells me that dispatch is undefined.
I also have this test, which passes, it tells me that submitClaimsForm has been called, but it just covers the lines for onSubmit:
it('onSubmit is called on submit', function() {
const spyOnSubmit = jest.spyOn(wrapper.instance(), 'onSubmit');
const mockHandleSubmit = jest.fn(wrapper.instance().onSubmit);
const submitClaimsForm = jest.fn(wrapper.instance().submitClaimsForm);
wrapper.setProps({
handleSubmit: mockHandleSubmit,
submitClaimsForm
});
wrapper.find('MyForm').simulate('submit');
expect(mockHandleSubmit).toHaveBeenCalled();
expect(spyOnSubmit).toHaveBeenCalled();
expect(submitClaimsForm).toHaveBeenCalled(); // <--
});
The reason your mapDispatchToProps works as expected test fails is because mapDispatchToProps expects a dispatch function to be passed in, not the map itself (that's what mapDispatchToProps returns).
This should work:
jest.mock('./actions');
import * as actions from './actions';
it('mapDispatchToProps calls the appropriate action', async () => {
// mock the 'dispatch' object
const dispatch = jest.fn();
const actionProps = mapDispatchToProps(dispatch);
const formData = { ... };
actionProps.submitClaimsForm(formData);
// verify the appropriate action was called
expect(actions.submitClaimsForm).toHaveBeenCalled(formData);
});
Related
I have a createAsyncThunk function as such
export const startup = createAsyncThunk<
void,
void,
{
dispatch: AppDispatch;
}
>("startup", async (_params, { dispatch }) => {
const appConfigs = await retrieveStoredAppConfiguration();
if (appConfigs?.tenantConfig && appConfigs?.clientRegistration) {
const configs: InitAppConfigs = {
tenantConfig: appConfigs.tenantConfig,
clientRegistration: appConfigs.clientRegistration,
};
await initializeApp(configs, dispatch);
dispatch(appConfigurationSlice.actions.initialize(appConfigs));
}
});
So I have a unit test as such
describe("AppStartupThunk", () => {
it("should dispatch AppStartupThunk successfully", async () => {
const retrieveStoredAppConfigurationSpy = jest
.spyOn(retrieveStoredAppConfiguration, "retrieveStoredAppConfiguration")
.mockImplementation(() => {
return Promise.resolve(appConfigs);
});
const result = await store.dispatch(initApplicationStartup());
expect(true).toBeTruthy();
expect(retrieveStoredAppConfigurationSpy).toHaveBeenCalled();
});
});
My test covers all the lines except for when dispatch is invoked in the createAsyncThunk. Is there any way I can cover that dispatch call. I'm not sure how to do it with createAsyncThunk.
I am trying to pass an object as an argument to a user action but I can't access it in the action. It just returns undefined when I do console.log(dataToSubmit).
Here is the action method:
const loginUser = (dataToSubmit) => {
console.log(dataToSubmit)
return (dispatch) => {
dispatch(loginUserRequest)
axios.post('http://localhost:5000/api/user/login' , dataToSubmit)
.then(response => {
if(response.data.loginSuccess){
const user = response.data.user
dispatch(loginUserSuccess(user))
}
else{
console.log('Login attempt failed')
}
})
.catch(error => dispatch(loginUserFailure(error.message)))
}
}
export default loginUser
I'm passing the argument here:
const handleSubmit = (event) => {
event.preventDefault();
if (isFormValid(email , password)){
const data = {
email,
password
}
loginUser(data)
}
}
I've already mapped dispatch to props:
const mapDispatchToProps = (dispatch) => {
return{
loginUser : () => dispatch(loginUser())
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SignIn)
I'm new to redux. Thanks
You need to pass the argument in mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return{
loginUser : (data) => dispatch(loginUser(data))
}
}
Hello I'm trying to test this function with the return of the dispatch in how many times it have been called, but really don't know how to do it correctly in order to call dispatch
export const mapDispatchToProps = (dispatch) => {
return {
hideSidebar: () => {
dispatch(hideSidebar)
},
updateUnit: (unitObject) => {
dispatch(settingsActions.updateArray(unitObject))
}
}
}
I have these test
describe('mapDispatchToProps', () => {
test('test', () => {
const dispatch = jest.fn(() => Promise.resolve())
mapDispatchToProps(dispatch)
expect(dispatch).toHaveBeenCalledTimes(2)
})
})
Any suggestions?
Create a dispatch mock function and pass it to mapDispatchToProps.
Then call the functions defined on the result.
You can use something like toHaveBeenCalledWith to verify that the correct action was dispatched:
// Stubs for hideSidebar and settingsActions.updateArray
const hideSidebar = { type: 'hide-side-bar' };
const settingsActions = { updateArray: u => ({ type: 'update-unit', payload: u })};
export const mapDispatchToProps = (dispatch) => {
return {
hideSidebar: () => {
dispatch(hideSidebar)
},
updateUnit: (unitObject) => {
dispatch(settingsActions.updateArray(unitObject))
}
}
}
test('mapDispatchToProps', () => {
const dispatch = jest.fn();
const map = mapDispatchToProps(dispatch);
map.hideSidebar();
expect(dispatch).toHaveBeenCalledWith({ type: 'hide-side-bar' }); // Success!
map.updateUnit({ theKey: 'theVal' });
expect(dispatch).toHaveBeenCalledWith({ type: 'update-unit', payload: { theKey: 'theVal' } }); // Success!
})
I'm using react native + redux + redux-thunk
I do not have much experience with redux and react native
I'm calling an action inside my component.
this.props.checkClient(cliente);
if(this.props.clienteIsValid){
...
}
and within that action there is a call to an api that takes a few seconds.
export const checkClient = (cliente) => {
return dispatch => {
axios.get(`${API_HOST}/api/checkclient`, header).then(response => {
dispatch({type: CHECK_CLIENT, payload: response.data }); //valid or invalid
}).catch((error) => { });
}
}
My question is how can I delay the return of the action until the api response is completed? I need the api response to know if the client is valid or invalid. That is, I need the action to be resolved and then verify that the client is valid or invalid.
You can return a promise from the action, so that the call becomes thenable:
// Action
export const checkClient = (cliente) => {
return dispatch => {
// Return the promise
return axios.get(...).then(res => {
...
// Return something
return true;
}).catch((error) => { });
}
}
class MyComponent extends React.Component {
// Example
componentDidMount() {
this.props.checkClient(cliente)
.then(result => {
// The checkClient call is now done!
console.log(`success: ${result}`);
// Do something
})
}
}
// Connect and bind the action creators
export default connect(null, { checkClient })(MyComponent);
This might be out of scope of the question, but if you like you can use async await instead of then to handle your promise:
async componentDidMount() {
try {
const result = await this.props.checkClient(cliente);
// The checkClient call is now done!
console.log(`success: ${result}`)
// Do something
} catch (err) {
...
}
}
This does the same thing.
I don't understand the problem, but maybe this could help
export const checkClient = (cliente) => {
return dispatch => {
dispatch({type: CHECK_CLIENT_PENDING });
axios.get(`${API_HOST}/api/checkclient`, header).then(response => {
dispatch({type: CHECK_CLIENT, payload: response.data }); //valid or invalid
}).catch((error) => { });
}
}
...
this.props.checkClient(cliente);
if(this.props.clienteIsPending){
...
}
if(this.props.clienteIsValid){
...
}
I have written a full code if there is still confusion. The promise should work for a sequence of asynchronous redux action calls
Actions
export const buyBread = (args) => {
return dispatch => {
return new Promise((resolve, reject) => {
dispatch({type: BUY_BREAD_LOADING });
// or any other dispatch event
// your long running function
dispatch({type: BUY_BREAD_SUCCESS, data: 'I bought the bread'});
// or any other dispatch event
// finish the promise event
resolve();
// or reject it
reject();
});
}
export const eatBread = (args) => {
return dispatch => {
return new Promise((resolve, reject) => {
dispatch({type: EAT_BREAD_LOADING });
// or any other dispatch event
// your long running function
dispatch({type: EAT_BREAD_SUCCESS, data: 'I ate the bread'});
// or any other dispatch event
// finish the promise event
resolve();
// or reject it
reject();
});
}
Reducer
const initialState = {}
export const actionReducer = (state = initialState, payload) => {
switch (payload.type) {
case BUY_BREAD_LOADING:
return { loading: true };
case BUY_BREAD_SUCCESS:
return { loading: false, data: payload.data };
case EAT_BREAD_LOADING:
return { loading: true };
case EAT_BREAD_SUCCESS:
return { loading: false, data: payload.data };
}
Component class
import React, {Component} from 'react';
class MyComponent extends Component {
render() {
return (
<div>
<button onClick={()=>{
this.props.buyBread().then(result =>
this.props.eatBread();
// to get some value in result pass argument in resolve() function
);
}}>I am hungry. Feed me</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
actionReducer: state.actionReducer,
});
const actionCreators = {
buyBread: buyBread,
eatBread: eatBread
};
export default connect(mapStateToProps, actionCreators)(MyComponent));
Redux is harrrrd... At least to me, it is!!! Can someone please explain to me how can I pass this fetched json[0] through mapDispatchToProps to my action creator? And am I doing it right? I am using redux-thunk, is this the correct way of using it?
state = {
articles: {
article: []
}
};
qrCodeOnReadHandler = ({ data }) => {
this.props.onQRRead();
console.log(this.props.art);
fetch(data)
.then(response => response.json())
.then(json => {
console.log(json),
// () => this.props.onQRRead(json[0]),
this.setState({
...this.state,
articles: {
...this.state.articles,
article: json[0]
}
});
});
};
connecting redux
const mapStateToProps = state => {
return {
art: state.articles.article
};
};
const mapDispatchToProps = dispatch => {
return {
onQRRead: () => dispatch(article())
};
};
action creators
export const fetchedArticle = res => {
return {
type: ARTICLE,
res: res
};
};
export const article = res => {
return dispatch => {
dispatch(fetchedArticle(res));
};
};
how can I pass this fetched json[0] through mapDispatchToProps to my
action creator
You have to make your onQRRead receive an argument like this:
const mapDispatchToProps = dispatch => {
return {
onQRRead: payload => dispatch(article(payload))
};
};
The name of the function parameter is arbitrary.
For now, you can use it like the way you just did:
this.props.onQRRead(json[0])