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:
- Mock entire
selectors1.js
module withjest.mock
, however, it won't work if I'll need to changeselectors1.baseSelector
output for some specific cases - Wrap every dependency selectors like this:
export 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?
selectors2
is creating a new instance ofselectors1
therefore it's not the instance you mocked with the spy method but you would like it to be? One option may be to to use dependency injection so you can initialize it with the mocked instance. Another may be to mock selector2's target selector to return a mocked instance1, but it sounds like you're trying to avoid that for scalability reasons. I feel like I may not be grasping the whole domain of the problem or maybe exactly whatcreateSelector
is doing. You've already touched on using a module mock. – Runck