Unit testing redux-saga task cancellation

1.7k views Asked by At

I was wondering if anyone had any tips on how to unit-test the following redux-saga login/logout flow:

let pollingTask = null

function * handleLogin () {
  try {
    const token = yield call(loginHandler)
    pollingTask = yield fork(handlePolls, token)
    yield put('LOGIN_SUCCSES')
  } catch (e) {
    yield put('LOGIN_FAILURE')
  }
}

function * handlePolls (token) {
  while (true) {
    try {
      yield call(pollHandler, token)
      yield put('POLL_SUCCESS')
    } catch (e) {
      yield put('POLL_FAILURE')
    } finally {
      if (yield cancelled()) {
        yield call(pollCancelled)
      }
    }
  }
}

function * handleLogout () {
  try {
    yield call(logoutHandler)
    yield cancel(pollingTask) 
    yield put('LOGOUT_SUCCESS')
  } catch (e) {
    yield put('LOGOUT_FAILURE')
  }
}

Since I need to cancel the pollingTask on logout, I tried using createMockTask() in my tests but I always get its value as undefined when I invoke the handleLogout() saga, although I know that my handleLogin() would always be started first and it would initialize the pollingTask.

Any help would be much appreciated!

1

There are 1 answers

0
DaveLV On

To make the function go to yield cancelled() you call .return() on the iterator.

An example -

//assuming this saga 
function* saga() {
  try {
    const resp = yield call(someApi)
    yield put(action(resp))
  } finally {
    if(yield cancelled()) {
       // handle logic specific to cancellation. For example
       yield <some effect>
    }
  }
}

// test
const gen = saga()
expect(gen.next().value).toEqual(call(someApi))
// simulates cancellation
// gen asking for cancel status
expect(gen.return().value).toEqual( cancelled() ) 
// answer yes, we've been cancelled
expect(gen.next(true).value).toEqual(<some effect>)

Example taken from https://github.com/redux-saga/redux-saga/issues/266#issuecomment-216087030