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

createMockTask + expectSaga not working together very well. #97

Open rmevans9 opened 7 years ago

rmevans9 commented 7 years ago

I am trying to test a pretty straight forward flow that is giving me some issues. Basically I have fork a delay, complete some actions then join the delay back in. This forces the saga to run for a minimum amount of time which for my use case is important. I am trying to use expectSaga to test this flow and am running into some issues which are actually due to redux-saga but I feel an issue on this library could make sense... explanation below after the example use case

Example Saga:

const task = yield fork(delay, 1500);

{...other actions}

yield join(task);

Example Test:

it('is a test', () => {
    const mockDelayTask = createMockTask();

    return expectSaga(exampleSaga)
        .provide([
            [matchers.fork.fn(delay), mockDelayTask]
        ])
        .run();
});

When executing the test redux-saga actually fails complaining that it can't read the property 'push' of undefined. Looking at redux-saga code it is happening because of this line https://github.com/redux-saga/redux-saga/blob/master/src/internal/proc.js#L509 which tries to add a 'joiner' onto the task which if you look at https://github.com/redux-saga/redux-saga/blob/master/src/internal/utils.js#L82 you can see that is simply because their mock task does not implement the joiner array. My first thought is 'no biggy, I want this task to be done running for my test purposes anyway' and just do mockDelayTask.setRunning(false) before I call expectSaga. Well... that causes a different error about isAborted not being a function. That is because of https://github.com/redux-saga/redux-saga/blob/master/src/internal/proc.js#L511 which, again, is not defined on the mock task.

With all of that said - I was going to open a PR on redux-saga's repo to add these additional properties but found this issue https://github.com/redux-saga/redux-saga/issues/182 which basically says that the mock task is suitable for more traditional unit testing (which is true) and that anything above and beyond can be attached manually. Now, I am more then happy to attach them manually but feel like it might be a good fit for this library to have its own createMockTask-esq function that attaches the additional properties because with expectSaga forking and then joining sagas that you want to mock out seems like a very real use case.

Thoughts? Feel free to tell me if you hate this idea... as mentioned above I would be more then happy to attach the properties as one off changes in my tests but wanted to see if anyone else thought this would bring value.

jfairbank commented 7 years ago

Hi @rmevans9!

Thanks for the suggestion. I think adding a helper to Redux Saga Test Plan to create mock tasks could be useful, considering it runs sagas with Redux Saga. Is this something that you'd be interested in adding to Redux Saga Test Plan?

rmevans9 commented 7 years ago

I sure can, just wanted to make sure there was interest in it before sinking some time into it. I will work on getting a PR opened in the next day or two

jfairbank commented 7 years ago

Great, thanks!

iamgollum commented 5 years ago

I am able to get this working when using the pure fork() effect in the provider:

      ... ETC...
      const task = createMockTask();
      ......
      ......
      const { effects } = await expectSaga(datasourceSagas.watchDatasourceSaga)
        .dispatch(action)
        .provide([
          // { fork: forkIntercept },
          [interceptTakeEffect(action)],
          [fork(datasourceSagas.datasourceWorker, action), task],
          [matchers.call.fn(DatasourceService.queryDatasource), datasourceData],
          [cancelled(), true],
        ])
        .put.actionType(DATASOURCE_STORE_TASK)
        // .call.fn(api.cancelRequest)
        .withReducer(reducer)
        .hasFinalState(finalStateData)
        .silentRun();
balazserdeszlogmein commented 2 years ago

Did this get fixed?

In current state, this library is unable to integration test any saga that contains a yield join line. It always throws the error that the owner of this issue talks about. ("Cannot read property 'push' of undefined.")

Also, in an expectSaga(), join() calls cannot be asserted at all, since this is the typescript definition ('join' is not listed in the Pick):

export type ExpectApiEffects
    = Pick<EffectApi<ExpectApi>, 'getContext' | 'setContext' | 'race' | 'take' | 'takeMaybe'>
    & Pick<EffectApiEx<ExpectApi>, 'actionChannel' | 'apply' | 'call' | 'cps' | 'fork' | 'put' | 'putResolve' | 'select' | 'spawn'>;