Jest.js tests don't pass when expected/received values are objects

macbem picture macbem · Feb 19, 2017 · Viewed 19.5k times · Source

I'm testing this reducer:

const todo = (state = {}, action) => {
  switch(action.type) {
    case 'ADD_TODO':
      return {
        id: action.id,
        text: action.text,
        completed: false
      }
    case 'TOGGLE_TODO':
      if(state.id !== action.id) {
        return state;
      }
      return {...state, completed: !state.completed};

    default:
      return state;
  }
}

const todos = (state = [], action) => {
  switch(action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        todo(undefined, action)
      ]
    case 'TOGGLE_TODO':
      return state.map(item => todo(item, action));
    default:
      return state;
  }
}

export default todos;

With this test:

import todos from './todos';

test('creates a new todo', () => {
  const stateBefore = [];
  const action = {
    type: 'ADD_TODO',
    id: 0,
    text: 'test'
  };
  const stateAfter = [{
    id: 0,
    text: 'test',
    completed: false
  }];

  expect( JSON.stringify( todos(stateBefore, action) ) ).toBe( JSON.stringify(stateAfter) );
});

The problem is that my tests fail with a Compared values have no visual difference remark if I remove the JSON.stringify() calls - I get that comparing an object to an object poses some problems because of reference, but do I have to use JSON.stringify() or loop through the object keys to compare them each time?

Answer

macbem picture macbem · Feb 19, 2017

I'm answering my own question.

The .toBe method tests for exact (===) equality. In order to compare objects, you have to use the .toEqual method which does recursive checks of every object key / array index, depending on your data type.

In conclusion, you don't have to use JSON.stringify() and Jest goes through object keys for you, you just have to use the right equality testing method.

Source: https://facebook.github.io/jest/docs/using-matchers.html#content