redux-saga-test-plan icon indicating copy to clipboard operation
redux-saga-test-plan copied to clipboard

Matching selector factories

Open eric-burel opened this issue 8 years ago • 3 comments

Hi,

I can't match selectors built using a factory.

    expectSaga(watchInvalidateWidgets)
      .provide([
        [matchers.call.fn(Foo.bar), data],
        [matchers.select.selector(makeSelectStuffsForThisProject(projectId))],
      ])
      .dispatch(invalidateStuffs(projectId, stuffs))
      .put(success(projectId, 'foo', data))
      .put(success(projectId, 'bar', data))
      .run()
      ;

Since the selector is built using a factory, each time I trigger the factory I get a different object. It seems that the matcher is failing in this case, the actual underlying selector is triggered (and fails).

Is there another way to match my selector ? Is there a way to mock makeSelectStuffsForThisProject so that it returns a dummy selector of my own, and insert it in the saga ?

eric-burel avatar Oct 12 '17 09:10 eric-burel

Got the same problem today. Here my solution: (basically I match against the args instead of the selector function)

.provide({
                // assert that the selector got called with the correct resorucePath
                // then mock the result
                select(effect, next) {
                    if (isEqual(effect.args[0].resourcePath, [ 'placements', '2x3' ])) {
                        return { teaserIds: [ 1, 2 ] };
                    }

                    return next();
                },
            })

ms88privat avatar Nov 09 '17 11:11 ms88privat

Ran into this today and fixed it by mocking the selectorFactory with jest mocks. In my case it was for the redux-form getFormInitialValues selector:

jest.mock('redux-form', () => ({
  getFormInitialValues: jest.fn().mockReturnValue(() => 'mock')
}));

jeffsheets avatar Dec 02 '17 18:12 jeffsheets

I solved this a different way, when I realised that the saga is calling a function to create the selector so it should be a call effect.

const stuffSelector = yield call(makeSelectStuffsForThisProject, projectId);
const stuff = yield select(stuffSelector);

Then in your test you can just provide whatever you want for the selector, such as Jest mock or an empty function (since it never gets called, it's just to make sure it's the same function):

const stuffSelector = () => {};
 expectSaga(watchInvalidateWidgets)
      .provide([
        [matchers.call.fn(Foo.bar), data],
        [matchers.call.fn(makeSelectStuffsForThisProject), stuffSelector],
        [matchers.select.selector(stuffSelector), stuff],
      ])
      …

jameshoward avatar Nov 20 '19 17:11 jameshoward