I'm having a pretty complex selectors structure in my project (some selectors may have up to 5 levels of nesting) so some of them are very hard to test with passing input state and I would like to mock input selectors instead. However I found that this is not really possible.
Here is the most simple example:
// selectors1.js
export const baseSelector = createSelector(...);
-
// selectors2.js
export const targetSelector = createSelector([selectors1.baseSelector], () => {...});
What I would like to have in my test suite:
beforeEach(() => {
jest.spyOn(selectors1, 'baseSelector').mockReturnValue('some value');
});
test('My test', () => {
expect(selectors2.targetSelector()).toEqual('some value');
});
But, this approach won't work as targetSelector
is getting reference to selectors1.baseSelector
during initialization of selectors2.js
and mock is assigned to selectors1.baseSelector
after it.
There are 2 working solutions I see now:
selectors1.js
module with jest.mock
, however, it won't work if I'll need to change selectors1.baseSelector
output for some specific casesexport const targetSelector = createSelector([(state) => selectors1.baseSelector(state)], () => {...});
But I don't like this approach a lot for obvious reasons.
So, the question is next: is there any chance to mock Reselect selectors properly for unit testing?
The thing is that Reselect is based on the composition concept. So you create one selector from many others. What really you need to test is not the whole selector, but the last function which do the job. If not, the tests will duplicate each other, as if you have tests for selector1, and selector1 is used in selector2, then automatically you test both of them in selector2 tests.
In order to achieve:
test only the result function of the selector. It is accessible by selector.resultFunc
.
So for example:
const selector2 = createSelector(selector1, (data) => ...);
// tests
const actual = selector2.resultFunc([returnOfSelector1Mock]);
const expected = [what we expect];
expect(actual).toEqual(expected)
Instead of testing the whole composition, and duplicating the same assertion, or mocking specific selectors outputs, we test the function which defines our selector, so the last argument in createSelector, accessible by resultFunc
key.