Redux Saga Test - mosinn/DOCS-n-Snippets-n-Steps GitHub Wiki

Tip:

Each line of saga is entire method on its own, of which, the each next() of test case, executes ONE line of actual saga at a time.

So putting break point in each line of actual saga and actual test's next(), keeps break point jumping between test and saga, very useful, indeed for checking each line return is as per previous next(arg)

Saga ASSERTION failure LOG is shallow. How to expand it to observe n-level nested differences in EFFECT arguments ?

// Add to the top of TEST file
import util from 'util'
util.inspect.defaultOptions.depth = null

Saga Test Assertion Failure DEBUG when PARAMETERIZED Test and no useful info printed in log ?

 Use the logging as there is NO OTHER WAY if there is no DIFF in Failed Test Case :)
Expected
--------
{
  '@@redux-saga/IO': true,
  combinator: false,
  type: 'CALL',
  payload: {
    context: null,
    fn: [Function: submitPeriodicPayment],
    args: [
      'http://localhost',
      'token',

Eg:

Test Case and Code Logs: image

Saga to be tested:

export const productSelector = (state: Store) => state.xyz.formData.data.product;

export function* fetchAccountsWorker(action: ActionType<typeof xyzActions.fetchAccounts>) {
  try {
    const product: Product = yield select(productSelector);
    const url = getFromNonGeneratorHelperFunc(product);
    const response: AxiosResponse<Account[]> = yield call(fetchAccounts, url, product, action);
    yield put(xyzActions.fetchAccountsSucceeded(response.data));
  } catch (e) {
    console.error('Failed to fetch accounts', e);
  }

Test using redux-saga-test-plan:

Tip: [testSaga] ONLY -

MUST DEBUG Saga Test while running in Intellij to understand flow of TEST and mocks 
next with args does two things
	sets fake but IMPORTANT input for upcoming effect
	advances saga

Take Saga test with a pinch of salt and not too seriously. These pass most of time if under test code is changed. Just debug make sure all lines are covered and dust it away !!!

   it('logs to console if failed to fetch account info', () => {
   let myActionRef: ActionType<CreateViewEditActionType.FETCH_TRACE_ACCOUNTS> = {
       type: CreateViewEditActionType.FETCH_TRACE_ACCOUNTS
     };

     testSaga(fetchAccountInfoWorker, myActionRef)
       .next() // Always needed to reach the line
       .select(productSelector) // Assert select effect is called with a given selector. Note, originally selector in real code was anonymous func, but that gives an issue in select() effect test
       .next(mockSelectedProductAsIfReturnedBySelectJustAbove)//This will be passed to getFromNonGeneratorHelperFunc() as this is what will be fake returned by previous select. Url will be real based on this fake input
       .call(fetchTraceAccounts, 'url1CreatedByHelperFromFakeProductInput', myActionRef)
       .next(mockApiResponseFromCallEffect)
       .put(createViewEditActions.fetchTraceAccountsSucceeded(mockApiResponseFromCallEffect)) // Assert put effect is passed an expected mock input
       .throw({message: "msg", name: "error"})
       .isDone();
     // tips - testSaga ONLY - MUST DEBUG Saga Test while running in Intellij to understand flow of TEST and mocks - next with args does two things. Sets fake but IMPORTANT input for upcoming effect and advances saga

     expect(mockConsoleError).toHaveBeenCalled();
   });
⚠️ **GitHub.com Fallback** ⚠️