Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing custom redux middleware

How do I unit test custom redux middleware? I have this simple function that is supposed to dispatch action after a given timeout but ... I have no idea how to approach it. I dint find enough resources regarding this issue.

const callAPiTimeoutMiddleware = store => next => (action) => {
  if (action[CALL_API]) {
    if (action[CALL_API].onTimeout) {
      setTimeout(() => {
        store.dispatch({ type: action[CALL_API].onTimeout });
      }, DEFAULT_TIMEOUT_LENGTH);
    }
  }

  return next(action);
}

These are my tests based on blog post that is mentioned in the accepted answer:

describe('callAPiTimeoutMiddleware', () => {
  describe('With [CALL_API] symbol', () => {
    it('should dispatch custom action', () => {
      const clock = sinon.useFakeTimers();
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = {
        [CALL_API]: {
          endpoint: 'endPoint',
          method: 'METHOD',
          types: ['REQUEST_TYPE', 'SUCCESS_TYPE', 'FAILURE_TYPE'],
          onTimeout: 'TIMEOUT_TYPE',
        },
      };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);
      clock.tick(99000);

      expect(fakeStore.dispatch.calledOnce).toEqual(true);
    });


    it('should call next action', () => {
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = {
        [CALL_API]: {
          endpoint: 'endPoint',
          method: 'METHOD',
          types: ['REQUEST_TYPE', 'SUCCESS_TYPE', 'FAILURE_TYPE'],
          onTimeout: 'TIMEOUT_TYPE',
        },
      };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);

      expect(fakeNext.calledOnce).toEqual(true);
    });
  });

  describe('Without [CALL_API] symbol', () => {
    it('should NOT dispatch anything', () => {
      const clock = sinon.useFakeTimers();
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = { type: 'SOME_TYPE' };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);
      clock.tick(99000);

      expect(fakeStore.dispatch.calledOnce).toEqual(false);
    });


    it('should call next action', () => {
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = { type: 'SOME_TYPE' };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);

      expect(fakeNext.calledOnce).toEqual(true);
    });
  });
});
like image 450
Michal Avatar asked Dec 20 '16 12:12

Michal


People also ask

How do I test useDispatch jest?

Show activity on this post. import * as redux from "react-redux"; describe('dispatch mock', function(){ it('should mock dispatch', function(){ //arrange const useDispatchSpy = jest. spyOn(redux, 'useDispatch'); const mockDispatchFn = jest. fn() useDispatchSpy.

What is custom middleware in redux?

A redux middleware is nothing more than a function which is invoked on every action and we can do almost anything e.g Data manipulations, popups, confirmations, API response validation and more, before pushing the updates to the reducers followed by the state change.

How do I test mapStateToProps using jest?

Steps: extract each mapDispatchToProps property as a separate action creator function in another file. extract each mapStateToProps property as a separate selector function in another file. write tests for the selectors and action creators.


2 Answers

The redux-thunk middleware has unit tests written. You can refer that here

He is using only mocha and chai.

And here he is talking about how you can write unit tests for your redux app.

Nice blog on redux middlewares and how to write unit tests for them.

like image 200
Thaadikkaaran Avatar answered Oct 26 '22 13:10

Thaadikkaaran


I needed some more details to actually create tests for the middleware, so here is my answer specific to the middleware test:

Middlewares can be tested very easily without doing a lot of mocking. The chained arrow functions appear intimidating, but it is just a matter of how they are called. I used jest to help me testing but you can replace all jest functions with something else. I'll get right into the code and explain in comments:

import logger from './logger'; //this is your middleware
const next = jest.fn(); // middleware needs those as parameters, usually calling next(action) at the end to proceed
const store = jest.fn(); 

const action = { type: 'YOUR_ACTION_TYPE', payload: { your: 'data' }}
logger(store)(next)(action);

This is how you call your middleware in a test. In your case if you want to check if dispatch has been called you could do something like this:

// Add this in the beginning
store.dispatch = jest.fn();

// Add this after calling logger()
expect(store.dispatch.mock.calls).toEqual('whatever calls you expected');
like image 31
Gegenwind Avatar answered Oct 26 '22 13:10

Gegenwind