Search code examples
javascriptunit-testingreduxredux-sagaredux-saga-test-plan

take assertion with redux-saga-test-plan that takes a function as pattern gives 'take effects do not match' error


I want to test a saga that yields a take effect which takes a function as pattern, e.g.

export function* mySaga(myAction: {
  type: string;
}): Generator<TakeEffect, boolean, { type: string }> {
  const { type: actionType } = (yield take(
    (action: any) => action.type === myAction.type,
  )) as { type: string };
  return actionType === myAction.type;
}

with a test that looks like:

it('Should test mySaga', () => {
  testSaga(mySaga, { type: 'myActionType' }).next().take().next().finish();
});

but I get the following error:

SagaTestError: 
Assertion 1 failed: take effects do not match

Expected
--------
{ '@@redux-saga/IO': true,
  combinator: false,
  type: 'TAKE',
  payload: { pattern: '*' } }

Actual
------
{ '@@redux-saga/IO': true,
  combinator: false,
  type: 'TAKE',
  payload: { pattern: [Function] } }

I have not been able to find how to assert the a take effect that takes a function pattern instead of a string. Can someone please help me?


Solution

  • Since you pass an anonymous function to take effect creator. We can't get this anonymous function in the test case using the module requiring.

    You can use inspect general assertions helper.

    If your saga yields a nondeterministic type of value or something not easily covered by the effect assertions or other general assertions, then you can use inspect to retrieve the actual yielded value and perform your own assertions with your favorite assertion library.

    So that we can get the returned effect of yield take((action: any) => action.type === myAction.type). Then, assert this effect.

    E.g. (using jestjs as testing framework)

    saga.ts:

    import { TakeEffect, take } from 'redux-saga/effects';
    
    export function* mySaga(myAction: { type: string }): Generator<TakeEffect, boolean, { type: string }> {
      const { type: actionType } = (yield take((action: any) => action.type === myAction.type)) as { type: string };
      console.log('actionType: ', actionType);
      return actionType === myAction.type;
    }
    

    saga.test.ts:

    import { testSaga } from 'redux-saga-test-plan';
    import { TakeEffect } from 'redux-saga/effects';
    import { mySaga } from './saga';
    
    describe('63523200', () => {
      it('should pass', () => {
        testSaga(mySaga, { type: 'myActionType' })
          .next()
          .inspect<TakeEffect>((yieldedValue) => {
            expect(yieldedValue.payload.pattern).toEqual(expect.any(Function));
            // test this anonymous function
            expect((yieldedValue.payload.pattern as Function)({ type: 'myActionType' })).toBeTruthy();
            expect((yieldedValue.payload.pattern as Function)({ type: 'hisActionType' })).toBeFalsy();
          })
          .next({ type: 'otherActionType' })
          .isDone();
      });
    });
    

    unit test result:

     PASS  src/stackoverflow/63523200/saga.test.ts
      63523200
        ✓ should pass (23 ms)
    
      console.log
        actionType:  otherActionType
    
          at src/stackoverflow/63523200/saga.ts:5:11
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |     100 |     100 |                   
     saga.ts  |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        2.809 s, estimated 3 s