redux-mock-store
redux-mock-store copied to clipboard
does not work with nested async thunks?
adapted from the async example in the README:
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
const middlewares = [thunk]; // add your middlewares like `redux-thunk`
const mockStore = configureStore(middlewares);
// You would import the action from your codebase in a real scenario
function success() {
return {
type: "FETCH_DATA_SUCCESS"
};
}
function success_innerAsync() {
return {
type: "FETCH_DATA_SUCCESS--INNER_DISPATCH"
};
}
function fetchData() {
return async dispatch => {
await fetch("/users.json"); // Some async action with promise
dispatch(success());
dispatch(fetchMoreData_innerAsync());
};
}
function fetchMoreData_innerAsync() {
return async dispatch => {
await fetch("/more-data.json"); // Some async action with promise
dispatch(success_innerAsync());
};
}
it("should execute fetch data", () => {
const store = mockStore({});
// Return the promise
return store.dispatch(fetchData()).then(() => {
const actions = store.getActions();
expect(actions).toEqual([success(), success_innerAsync()]);
});
});
What I'm expecting here is that the thunk fetchData dispatches success() to the store and also dispatches the thunk fetchMoreData_innerAsync; this second thunk should dispatch success_innerAsync() to the store. So i would expect e.g.:
expect(store.getActions()).toEqual([success(), success_innerAsync()]);
But instead, the result is:
Expected value to equal:
[{"type": "FETCH_DATA_SUCCESS"}, {"type": "FETCH_DATA_SUCCESS--INNER_DISPATCH"}]
Received:
[{"type": "FETCH_DATA_SUCCESS"}]
Difference:
- Expected
+ Received
Array [
Object {
"type": "FETCH_DATA_SUCCESS",
},
- Object {
- "type": "FETCH_DATA_SUCCESS--INNER_DISPATCH",
- },
]
Here's a code sandbox demonstrating:
https://codesandbox.io/s/fragrant-smoke-e0egv?file=/src/index.test.js
This is just a minimal example for to demonstrate, this kind of usage of async thunks in real code seems to work fine in my application. Hence, I don't think I'm abusing Redux/thunks somehow (though please let me know if i am!), but rather that I'm either not understanding how to properly use the mock store, or that there's a bug that only captures the top level of async thunks.
(Or perhaps this will turn out to be a feature request for some kind of new API that expands on .getActions to await all nested async actions/thunks somehow...)
Thanks for any advice!
Update: this definitely seems to be a tricky race condition kind of thing, because inserting a brief delay allows the tests to pass.
Here's an updated sandbox https://codesandbox.io/s/nifty-hofstadter-wnouo
And I'll put the updated passing code here as well for posterity:
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
const middlewares = [thunk]; // add your middlewares like `redux-thunk`
const mockStore = configureStore(middlewares);
// You would import the action from your codebase in a real scenario
function success() {
return {
type: "FETCH_DATA_SUCCESS"
};
}
function success_innerAsync() {
return {
type: "FETCH_DATA_SUCCESS--INNER_DISPATCH"
};
}
function fetchData() {
return async dispatch => {
await fetch("/users.json"); // Some async action with promise
dispatch(success());
dispatch(fetchMoreData_innerAsync());
};
}
function fetchMoreData_innerAsync() {
return async dispatch => {
await fetch("/more-data.json"); // Some async action with promise
dispatch(success_innerAsync());
};
}
async function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
it("should execute fetch data", async () => {
const store = mockStore({});
// Return the promise
await store.dispatch(fetchData());
await wait(1000);
const actions = store.getActions();
expect(actions).toEqual([success(), success_innerAsync()]);
});
I'm having this same issue, but the wait makes no difference for me. Redux mock store version is 1.5.4 and react-redux version is 7.1.3. Any additional async actions that are dispatched inside an action creator are never called
Edit: I actually figured out the reason that my async thunk that was dispatched inside the async action I was testing wasn't getting called because there was an exception inside it. Sadly, there's no indication of this except for when you call store.getActions(), I saw an error action that was dispatched with the error message.
@landonalder thanks!! I had the same error and after reading your comment about the error not showing. I search for and discovered the error. It is working now!
@garyee glad to hear this helped :)