【Cypressコンポーネントテスト】Object.assign を使ってVueのprops.dataを上書きする


Cypressのコンポーネントテストで、テストごとに props.data の値を変えてVueコンポーネントをmountする時、値の変わらない props.data も都度追加するのが手間だったので、良い感じにマージ出来ないか調べた際の備忘録です。

| package | version |
| ------- | ------- |
| cypress | 13.7.1 |
| vue | 3.2.47 |

### コンポーネントテストの下準備

#### まず mount する vue ファイルを importし、

```javascript
import Page1 from "@/views/Page1.vue";
```

#### props に渡す data を定義し、 `cy.mount` でコンポーネントをマウントする。

参考: https://docs.cypress.io/api/commands/mount

```javascript
const optionsDefault = {
  props: {
    userId: 1,
    hogeID: "A",
    fugaID: "B",
    piyoID: "C",
    isBtnEnabled: true

  },
};
cy.mount(Page1, optionsDefault);
```

#### コンポーネントテストを書いていく。

```javascript: TestComponent.vue
import Page1 from "@/views/Page1.vue";

const optionsDefault = {
  props: {
    userId: 1,
    hogeID: "A",
    fugaID: "B",
    piyoID: "C",
    isBtnEnabled: true
  },
};
describe("test A", () => {
  beforeEach(() => {
    cy.mount(Page1, optionsDefault);
  });
  it("isBtnEnabled: true を確認する", () => {
    // テスト実行内容は割愛
  });
});
```

続く「test B」では、props.data の `isBtnEnabled` の値が `false` の場合のテストを行いたいが、props.data を全て引っ張ってくる必要がある。

```javascript
describe("test B", () => {
  beforeEach(() => {
    const optionsDefault = {
      props: {
        userId: 1,
        hogeID: "A",
        fugaID: "B",
        piyoID: "C",
        isBtnEnabled: false, // testBで 変更する値は isBtnEnabled のみ
      },
    };
    cy.mount(Page1, optionsDefault);
  });
  it("isBtnEnabled: false を確認する", () => {
    // テスト実行内容は割愛
  });
});
```

そこで、`Object.assign()` を使い、オブジェクトをマージさせます。

```javascript: Object.assign() 例
const target = { hoge: "aaa", fuga: "bbb" };
const source = { fuga: "ccc", bar: "ddd" };

// オブジェクト target に souceをマージする
const mergeTarget = Object.assign(target, source);

console.log(target);
// Object { hoge: "aaa", fuga: "ccc", bar: "ddd" }
// ※重複したプロパティは後に指定された値に上書きされるので、fuga: bbbは ccc となる)
```
↑ これを使うとこうなる ↓
```javascript: Vue component test
describe("vue component test B", () => {
  beforeEach(() => {
    const addOptions = {
      // 上書きしたいprops.dataを定義
      props: {
        isBtnEnabled: true,
      },
    };
    //最初に定義したprops.data optionsDefault に上書きしたい addOptions をマージ
    const mergeOptions = Object.assign({}, optionsDefault["props"], addOptions["props"]);

    //Vueをmount
    cy.mount(Page1, { props: mergeOptions });
  });
  it("isBtnEnabled: true", () => {
    // テスト実行内容
  });
});
```

### 完成したコード

```javascript: TestComponent.vue
import Page1 from "@/views/Page1.vue";

const optionsDefault = {
  props: {
    userId: 1,
    isBtnEnabled: true,
    testArr: [],
  },
};
describe("test A", () => {
  beforeEach(() => {
    cy.mount(Page1, optionsDefault);
  });
  it("isBtnEnabled: true を確認する", () => {
    // テスト実行内容は割愛
  });
});

describe("vue component test B", () => {
  // 上書きしたい props.data を定義
  const addOptions = {
    props: {
      isBtnEnabled: true
    }
  };
  beforeEach(() => {
    // 最初に定義した props.data `optionsDefault` に
    // 上書きしたい props.data `addOptions` をマージ
    const options = Object.assign({}, optionsDefault["props"], addOptions["props"]);

    // Vueをmount
    cy.mount(Page1, { props: options });
  });

  it("isBtnEnabled: true", () => {
    // テスト実行内容
  });
});
```

参考
Object.assign() - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
リアクティブの探求 | Vue.js
https://v2.ja.vuejs.org/v2/guide/reactivity#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6