redux-saga-test-plan put effects do not match, but payload of actual and expected are equal
Asked Answered
A

1

9

I'm testing this saga

export function* foo() {
  yield put(actions.start());
  yield put(actions.bar({
    onSuccess: () => {
      // do something
    },
    onFailed: () => {
      // do something else
    }
  }));
  yield put(userActions.done());
}

and here is my test

it('should test foo saga, and put start, bar and done actions', () => {
  // assertions / expect
  testSaga(sagas.foo)
    .next()
    .put(actions.start())
    .next()
    .put(
      actions.bar({
        onSuccess: () => {},
        onFailed: () => {},
      }),
    )
    .next()
    .put(actions.done())
    .next()
    .isDone();
});

when I remove payload from saga and test it passes with no problem, but when I add payload (anything not only onSuccess and onFailed callbacks) it shows me this error

Assertion failed: put effects do not match

Expected
--------
{
  channel: null,
  action: 
   { type: 'BAR',
     payload: 
      {
        onSuccess: [Function: onSuccess],
        onFailed: [Function: onFailed]
      }
  }
}

Actual
------
{
  channel: null,
  action: 
   { type: 'BAR',
     payload: 
      {
        onSuccess: [Function: onSuccess],
        onFailed: [Function: onFailed]
      }
  }
}

it's interesting that actual and expected payload are equal, but test does not pass!

Adjournment answered 26/2, 2019 at 12:28 Comment(0)
D
3

The onSuccess and onFailed methods have different references in saga and test cases. The assertions will definitely fail.

Since you declared these two methods inside saga, we were unable to import them into our test cases through module requiring. So, we are unable to use the same references of these two methods in our test case.

We can use inspect general assertion provided by redux-saga-test-plan.

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.

We use it to get the returned effect of yield put(actions.bar({...})). Then, we can get the redux action created by actions.bar({...}) in test case include onSuccess, onFailed methods, and everything you passed in actions.bar() action creator in the foo saga.

We can assert these two methods using expect.any(Function) provided by jestjs. You can even execute and test them.

E.g.

saga.ts:

import { put } from 'redux-saga/effects';
import * as actions from './actions';

export function* foo() {
  yield put(actions.start());
  yield put(
    actions.bar({
      onSuccess: () => {
        // do something
      },
      onFailed: () => {
        // do something else
      },
    }),
  );
  yield put(actions.done());
}

saga.test.ts:

import { testSaga } from 'redux-saga-test-plan';
import { foo } from './saga';
import * as actions from './actions';
import { PutEffect } from 'redux-saga/effects';
import { AnyAction } from 'redux';

describe('54885611', () => {
  it('should pass', () => {
    const logSpy = jest.spyOn(console, 'log');
    testSaga(foo)
      .next()
      .put(actions.start())
      .next()
      .inspect<PutEffect<AnyAction>>((yieldedValue) => {
        expect(yieldedValue.payload.action).toEqual({
          type: 'START',
          payload: expect.objectContaining({ onSuccess: expect.any(Function), onFailed: expect.any(Function) }),
        });
        // test onSuccess
        yieldedValue.payload.action.payload.onSuccess();
        expect(logSpy).toBeCalledWith('do something');

        // test onFailed
        yieldedValue.payload.action.payload.onFailed();
        expect(logSpy).toBeCalledWith('do something else');

        logSpy.mockRestore();
      })
      .next()
      .put(actions.done())
      .next()
      .isDone();
  });
});

unit test result:

 PASS  src/stackoverflow/54885611/saga.test.ts
  54885611
    ✓ should pass (25 ms)

  console.log
    do something

      at console.<anonymous> (node_modules/jest-mock/build/index.js:848:25)

  console.log
    do something else

      at console.<anonymous> (node_modules/jest-mock/build/index.js:848:25)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 actions.ts |     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:        3.351 s
Dickson answered 23/6, 2021 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.