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

throwError isn't working as expected in one test, but works in another #312

Open wwdrew opened 4 years ago

wwdrew commented 4 years ago

I'm using:

redux-saga: 1.1.1 redux-saga-test-plan: 4.0.0-rc.3

I have two sagas I'm testing. In this one, throwing an error is working correctly:

Working test saga

export function* authenticationSignIn({ connection }: AuthenticationSignInAction) {
  try {
    const authoriseResponse: Auth0AuthoriseResponse = yield call(authorise, connection)

    yield put(authenticationAuthorisedAction(authoriseResponse))
  } catch (error) {
    yield call(console.log, `authenticationSignIn error: ${error.message}`)
  }
}

Working test file

it('logs an error if authentication refresh fails', () => {

    const testingAction = authenticationSignInAction('twitter')
    const error = new Error('signin error')

    return expectSaga(authenticationSignIn, testingAction)
      .provide([
        [call.fn(authorise), throwError(error)]
      ])
      .call(console.log, 'authenticationSignIn error: signin error')
      .run()
  })

But this one fails:

Failing test saga

export function* refreshContentSaga() {
  const token = yield select(getToken)

  try {
    const { result }: ContentResponse = yield call(refreshContent, token)

    yield put(contentUpdated({ allProducts: {}, homePageItems: [] }))
  } catch (error) {
    console.log(`refreshContent saga error: ${error.message}`)
  }
}

Failing test

it('catches an error', () => {

    const testToken = 'testToken'
    const testError = new Error('refresh content error')

    return expectSaga(refreshContentSaga)
      .provide([
        [select(getToken), testToken],
        [call.fn(api.refreshContent), throwError(testError)]
      ])
      .call(console.error, `refreshContent saga error: ${testError}`)
      .run()
  })

Which gives me this error:

    SagaTestError: 
    call expectation unmet:

    Expected
    --------
    { '@@redux-saga/IO': true,
      combinator: false,
      type: 'CALL',
      payload: 
       { context: null,
         fn: [Function: bound error],
         args: [ 'refreshContent saga error: refresh content error' ] } }

    Actual:
    ------
    1. { '@@redux-saga/IO': true,
      combinator: false,
      type: 'CALL',
      payload: 
       { context: null,
         fn: [Function: refreshContent],
         args: [ 'testToken' ] } }

To me it looks like the throwError call isn't working, but it works perfectly in the first situation. The only difference in the one is the extra select provider, but if I remove that the test fails for a different reason, so I know it's working correctly.

Any ideas?

jp928 commented 4 years ago

@wwdrew Thanks for reporting a bug. Do you mind to swap the order of select and call? make it likes

it('catches an error', () => {

    const testToken = 'testToken'
    const testError = new Error('refresh content error')

    return expectSaga(refreshContentSaga)
      .provide([
        [call.fn(api.refreshContent), throwError(testError)],
        [select(getToken), testToken]
      ])
      .call(console.error, `refreshContent saga error: ${testError}`)
      .run()
  })
wwdrew commented 4 years ago

Hi @jp928, thanks for getting back to me! I've just tried swapping the order and it's still giving me the same result.

justinline commented 4 years ago

I'm also getting failures with tests that use throwError() providers after recently upgrading some project dependencies (redux-saga-test-plan not being one of them). Seems like the catch of the try/catch no longer gets hit... Will try and investigate further

EDIT: Ok, so it seems like my issue was triggered by upgrading axios from 0.19.0 to 0.19.2 and it made some tests using throwError that should've previously failed (but didn't) correctly fail. But it was inconsistent between machines somehow. Not sure what caused it, but the issue is resolved for me now at least.