javascriptreactjsunit-testingjavascript-objectsspread-syntax

Why do I have to spread my object twice when copying state from my react object


I have this object below, I want to test that when i perform an action to change the state of the group key in the state that it updates correctly. As you can see there are way more key value pairs in this object than just group so I would like to spread the initialState object and write my test changing only the group value.

Here is the initialState:

export const initialState = {
  testing: false,
  filters: {
    start: moment()
      .startOf("month")
      .format(),
    end: moment()
      .endOf("month")
      .format(),
    city: "",
    group: "daily"
  },
  locations: []
};

My unit test:

test("It performs the setGroup action correctly", () => {
    const active = "month";

    const action = setGroup(active);

    const state = reducer(
      {
        ...initialState,
        filters: {
          ...initialState.filters,
          group: "daily"
        }
      },
      action
    );

    expect(state).toEqual({
      ...initialState,
      filters: {
        ...initialState.filters,
        group: "month"
      }
    });
  });

This test works however I want to know why I have to spread the initialstate once, and then again within the filters object I have to spread the initialState.filters again just to manipulate the month.

In my head this should work fine :

const state = reducer(
      {
        ...initialState,
        filters: {
          group: "daily"
        }
      },
      action
    );

My question is why do I need to put the line initialState.filters to make this test viable. Please can someone help me understand? I have done research but can't find anything.


Solution

  • When you are doing ...initialState.filters you are spreading the filters object on initialState. You have to do this as you have just defined a new filters object in your reducer and so have to place in it the values you want to keep from the old version.

    If this all seems a bit to verbose, then check out Immer, which allows you to have immutable objects with a bit more a traditional API

    https://immerjs.github.io/immer/docs/introduction