概要

Vue.js でコンポーネントメソッドのテストがうまくいかずハマってしまったので備忘録として残しておきます。 テストフレームワークには Jest を使っていました。

何がうまくいかなかったのか

呼び出すとプロパティの値を書き換えるメソッドをもつコンポーネントがあるとします。

<script>
  export default {
    data() {
      return {
        isActive: true,
      };
    },
    methods: {
      change() {
        this.isActive = false;
      },
    },
  };
</script>

このコンポーネントに対するテストコードは以下のようなものです。

test("change メソッドを呼び出すと、isActive プロパティの値を変更する", () => {
  const wrapper = shallowMount(TestComponent);
  wrapper.vm.change();

  expect(wrapper.vm.isActive).toBe(false);
});

この場合、テストを走らせるとうまくいきます。
では、isActive プロパティをクラスのバインディングに使った場合はどうでしょうか。

<template>
  <div :class="{ active: active }"></div>
</template>

change メソッドを呼び出した後にクラスに active が含まれているかテストします。

test("change メソッドを呼び出すと、active クラスが消える", () => {
  const wrapper = shallowMount(TestComponent);
  expect(wrapper.classes()).toContain("active");

  wrapper.vm.change();
  expect(wrapper.classes()).not.toContain("active");
});

テストを実行してみるとこんどはうまくいかず active クラスが存在したままになってしまいました。

どうしたらうまくいったのか

どうやらプロパティの書き換えによるコンポーネントの再描写は非同期で行われているようでした。
なのでメソッドの呼び出しに async/await を使って同期的に実行されるようテストコードを修正しました。

test("change メソッドを呼び出すと、active クラスが消える", async () => {
  const wrapper = shallowMount(TestComponent);
  expect(wrapper.classes()).toContain("active");

  await wrapper.vm.change();
  expect(wrapper.classes()).not.toContain("active");
});

こうすると無事テストが通るようになりました。