Redux-api-call's makeFetchAction comes with its own dataSelector, but in real world, we can't just grab and use it.
We may need to write our selector which bases on dataSelector.
Then when we write our unit test of that selector, we have to setup state which has api_calls property and the response.
For example:
const state = {
// some other properties
api_calls: {
fooApi: {
// meta data of this api call
data: {
foo: 'bar'
}
}
}
}
Number 1: Setting up this state is very tedious task for us because what we really want to test is just selector of our response (
which is { foo: 'bar' } in this case, but we end up making (almost) the whole state object.
Number 2: We want to write test for our selector, not makeFetchAction's selector.
How can we do better? Imagine that we have something like this API to construct our state base on actionCreator from makeFetchAction
import setAPIResponse from './testUtils/setAPIResponse';
const state = setAPIResponse(actionCreator, {
foo: "bar"
}).withState({});
The state will be exactly the same with the state above. Want to test selector which selects from more than 1 selector, here
is your recipe.
import setAPIResponse from './testUtils/setAPIResponse';
const state = setAPIResponse(actionCreator, {
foo: "bar"
})
.setAPIResponse(anotherActionCreator, {
duck: {
age: 27,
name: 'Melon'
}
})
.withState({});
You know what I mean, right? And you can also pass the inititalState or seedState along with it by calling withState.
Here is the implemetation of the setAPIResponse.
import { get } from 'lodash';
/* eslint-disable */
class MockAPIResponse {
constructor(state = {}) {
this.state = state;
}
setAPIResponse = (actionCreator, json) => {
const action = actionCreator();
const symbol = Object.getOwnPropertySymbols(action)[0];
// eslint-disable-next-line immutable/no-let
let apiName;
if (symbol) {
apiName = action[symbol].name;
} else {
apiName = action[0].payload.name;
}
this.val = {
[apiName]: {
data: json,
},
};
return new MockAPIResponse(this.withState(this.state));
}
withState = (state) => {
return {
...this.state,
...state,
api_calls: {
...state.api_calls,
...this.state.api_calls,
...get(state, 'api_calls', {}),
...this.val,
},
};
}
}
export default new MockAPIResponse().setAPIResponse;
Good luck and happy testing.