Rory
Rory

Reputation: 1492

Testing mutations with DeepFreeze for Redux objects

I have a simple Reducer

const uid = () => Math.random().toString(34).slice(2);
const bots = (state = [] , action) => {

    switch(action.type) {    
      case 'ADD_BOT':

          return [
              ...state, {
                    id: uid(),
                    isDone: false,
                    text: action.bots.text
              }
          ]

          //this will fail
     case 'ADD_BOT_THAT_MUTATES':
          console.log("mutating");
          action.bots.id = uid();
          state.push(action.bots);
          return state;

      default:
        return state;
  }
}
export default bots

And my spec file is

import deepFreeze from 'deep-freeze';
import bots from '../bots';

describe('Simple test', () =>  {

 function addBot(text) {
  return {
    type: 'ADD_BOT',
    bots: {
      id: 1,
      isDone: false,
      text: text
    }
  };
 }

 function addBotThatMutates(text) {
  return {
    type: 'ADD_BOT_THAT_MUTATES',
    bots: {
      id: 1,
      isDone: false,
      text: text
    }
  };
 }

  let state = []; 
  deepFreeze(state); 

  beforeEach(() => {

        state = bots(state, addBot("initial"));

  });

    it('should fail due to deepFreeze', () => {

        //create a payload
        let payload = addBot("test 1234");
        let payloadThatMutates = addBotThatMutates("test 5678");

        state = bots(state, payload);

        state = bots(state, payloadThatMutates);

        expect(3).toEqual(state.length);
    });
});

When I call the Reducer with state = bots(state, payload); I expect it to return a non mutated array as I'm using an ES6 spread statement in the Reducer.

When I call state = bots(state, payloadThatMutates); I was expecting an error flagged by deepFreeze. This is because in the Reducers I'm using state.push(action.bots); which I understand will mutate.

But I don't get any errors and my resultant state is an array of 3 objects.

Do I have an incorrect Reducers or have I not understood deepFreeze ?

This Unit test is not working as I expect. But my App/Web code works if i call the 'ADD_BOT_THAT_MUTATES action and Reducer I get no updated state i.e. Redux mutates the state.

Or have I just done something plain stupid ?

Upvotes: 1

Views: 1805

Answers (1)

Rory
Rory

Reputation: 1492

Since posting, I've managed to get my head around deepFreeze and mutations Below are my two tests that give the expected results

import deepFreeze from 'deep-freeze';
import bots from '../bots';

describe('Simple test', () =>  {

 function addBot(text) {
  return {
    type: 'ADD_BOT',
    bots: {
      id: 1,
      isDone: false,
      text: text
    }
  };
 }

 function addBotThatMutates(text) {
  return {
    type: 'ADD_BOT_THAT_MUTATES',
    bots: {
      id: 1,
      isDone: false,
      text: text
    }
  };
 }

  let state; 

  beforeEach(() => {        
    state = []
        state = bots(state, addBot("initial"));  
  });

    it('should pass due to non-muting reducer ', () => {
        //create a payload
        let payload = addBot("test 1234");
        let state2 = bots(state, payload);
        //state  has non mutated and state2 is a new array
         expect(state.length).toEqual(1);
         expect(state2.length).toEqual(2);
    });

  it('should fail due to deepFreeze', () => {
          deepFreeze(state); 
          //create a payload
          let payloadThatMutates = addBotThatMutates("test 5678");
          //deepFreeze will throw 'object is not extensible' because state is now mutating because of the push in the the reducer
          let state2 = bots(state, payloadThatMutates);          
          expect(state).toEqual(state2);
    });

});

Hope this helps anyone

Upvotes: 1

Related Questions