Rafael Marques
Rafael Marques

Reputation: 1445

basic reducer possibly mutating app state

I am using Redux spread operator to hopefully mantain the state as immutable objects.

However, i am managing to make the most simple unit test fail.

I assume the error probably has to do with immutables, but am i not using the spread operator correctly?

Here is my unit test:

describe('app logic', () => {
  it('initialises app', () => {
    const newState = reducer(INITIAL_STATE, {type: "NEXT"})
    const expectState = {
      start: true,
      render_component: null,
      requests: {},
      results: {},
    }
    console.log('newState', newState)
    console.log('expected state', expectState)
    expect(newState).to.equal(expectState)
  })
})

and here is my reducer

export const INITIAL_STATE = {
  start: false,
  render_component: null,
  requests: {},
  results: {}
}

export const next = (state) => {
  if (state === INITIAL_STATE) {
    return {
      ...state,
      start: true,
    }
  }
  return state
}

export function reducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case 'NEXT':
      return next(state)
    default:
      return state
  }
}

I print the two objects, and they look the same. i get the error :

1) app logic initialises app:

  AssertionError: expected { Object (start, render_component, ...) } to equal { Object (start, render_component, ...) }

Upvotes: 0

Views: 32

Answers (1)

jonahe
jonahe

Reputation: 5000

Not sure exactly which testing library you are using, but usually a name like .equal is used to test strict equality ( === ), which means (at least in the case of objects) that the two things being compared must actually reference the exact same object. So, for example,

const original = { a: 1 }; // creates a new object, assign it
const testMe = { a: 1 }; // creates another new object, assign it
console.log( original === testMe )   // false

evaluates to false, because while the objects have the same content, they do not reference the exact same object. They are separate, independently created, objects that happen to have the same content. Compare that to

const original = {a: 1}; // create a new object
const testMe = original;  // create another reference to the same object
console.log( original === testMe );  // true

So when you return

return {
  ...state,
  start: true,
}

you are creating and returning a new object, so it naturally can not reference the same object that you created and assigned to the variable name expectedState.

If what you are interested in is not strict equality, but rather just that the content in the two objects are the same, there exists other methods than .equal, usually named something with deep (since they go deep into the objects/arrays/whatever to check if the values are the same).

Chai.js has examples of both expect(x).to.equal(y) and expect(x).to.deep.equal(y) in their docs: http://chaijs.com/api/bdd/#method_equal

Your testing library probably has very similar, if not identical, syntax.

Upvotes: 1

Related Questions