jfairbank / redux-saga-test-plan

Test Redux Saga with an easy plan.
http://redux-saga-test-plan.jeremyfairbank.com
MIT License
1.25k stars 127 forks source link

Matching selector factories #151

Open eric-burel opened 6 years ago

eric-burel commented 6 years ago

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 ?

ms88privat commented 6 years ago

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();
                },
            })
jeffsheets commented 6 years ago

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')
}));
jameshoward commented 4 years ago

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],
      ])
      …