序章

スナップショットテストは、コードのリグレッションを監視し、統合テストとしても機能するJestのテストの一種です。 1つ目は、プロジェクトにコードを追加し、何か小さな問題が発生した場合、スナップショットテストでそれを検出できることを意味します。 2つ目は、スナップショットテストが、コンポーネント全体が意図したとおりに実行されることを確認する方法であることを意味します。

スナップショットテストの仕組みは、初めて実行するときです。 jest、スナップショットはDOMから生成されます。 その後のテストスイートの実行時に、構築されたDOMがこれらのスナップショットと比較されます。 コードを変更した可能性があるため、最初に生成されたものと一致するスナップショットは、物事がまだ機能していることを示しています。

いくつかの質問が自然に出てきます。プログラムに大幅な変更を加えて、DOMの内容が異なる場合はどうなりますか? Jestを使用すると、新しいスナップショットを生成できます。そのようなシナリオでは、それが保証されます。 私のページに非決定的なコンテンツがある場合はどうなりますか? これを処理する方法は複数ありますが、これについてはすぐに説明します。

アプリのセットアップ

次に、アプリケーションをセットアップします。 テスト用の簡単なアプリをセットアップするために、Jestを使用したVueのテストに関するチュートリアルのセットアップセクションに進んでください。 これがあなたの App.vue ファイルは次のようになります。

App.vue
<template>
  <div id="app">
    <div>
      <h3>Let us test your arithmetic.</h3>
      <p>What is the sum of the two numbers?</p>
      <div class="inline">
        <p>{{ x1 }} + {{ x2 }} =</p> <input v-model="guess"> <button v-on:click="check">Check Answer</button>
      </div>
      <button v-on:click="refresh">Refresh</button>
      <p>{{message}}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      x1: Math.ceil(Math.random() * 100), 
      x2: Math.ceil(Math.random() * 100),
      guess: "",
      message: ""
    }
  },
  methods: {
    check() {
      if (this.x1 + this.x2 === parseInt(this.guess)) {
        this.message = "SUCCESS!"
      } else {
        this.message = "TRY AGAIN"
      }
    },
    refresh() {
      this.x1 = Math.ceil(Math.random() * 100);
      this.x2 = Math.ceil(Math.random() * 100);
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.inline * {
  display: inline-block;
}
img {
  height: 350px;
}
</style>

そして、これが私たちが始めたものです app.spec.js 次のようになります:

import { mount } from "@vue/test-utils";
import App from "./../src/App.vue";

describe("App", () => {
  // Inspect the raw component options
  it("has data", () => {
    expect(typeof App.data).toBe("function");
  });
});

describe("Mounted App", () => {
  const wrapper = mount(App);

  test("is a Vue instance", () => {
    expect(wrapper.isVueInstance()).toBeTruthy();
  });

  it("renders the correct markup", () => {
    expect(wrapper.html()).toContain(
      "<p>What is the sum of the two numbers?</p>"
    );
  });

  // it's also easy to check for the existence of elements
  it("has a buttons", () => {
    expect(wrapper.contains("button")).toBe(true);
  });

  it("renders correctly with different data", async () => {
    wrapper.setData({ x1: 5, x2: 10 });
    await wrapper.vm.$nextTick();
    expect(wrapper.text()).toContain("10");
  });

  it("button click without correct sum", () => {
    expect(wrapper.vm.message).toBe("");
    const button = wrapper.find("button");
    button.trigger("click");
    expect(wrapper.vm.message).toBe("TRY AGAIN");
  });

  it("button click with correct sum", () => {
    wrapper.setData({ guess: "15" });
    const button = wrapper.find("button");
    button.trigger("click");
    expect(wrapper.vm.message).toBe("SUCCESS!");
  });
});

それを念頭に置いて it の単なるエイリアスです test ジェストで。 走る npm run test そして、すべてのテストに合格する必要があります。

スナップショットテストを始めましょう!

走る npm install --save-dev jest-serializer-vue 次に、以下に追加します package.json

package.json
{
  ...
  "jest": {
    "snapshotSerializers": ["jest-serializer-vue"]
  },
  ...
}

2番目のdescribeブロックにコードを追加します。

it('renders correctly', () => {
  const wrapper = mount(App)
  expect(wrapper.element).toMatchSnapshot()
})

テストを実行すると、最初にテストを実行したときに「1つのスナップショットが書き込まれました」と表示されることに注意してください。 と呼ばれるディレクトリに注意してください __snapshots__ の隣に作成されました app.spec.js.

で終わるファイルがあるスナップショットファイルを自由に見てください。 .snap 拡大; 接頭辞が付いている属性を除いて、コンポーネントのテンプレートセクション全体が再現されていることに気付くでしょう。 v-.

テストを再実行してください。

エラー!

なぜ?!

ターミナルでスナップショットテストの出力を調べると、理由は明らかです。ページにランダムに数値が生成されています。 また、スナップショットの番号が何であるかを確認できるはずです。 先に進み、合格してそれらをテストに置き換えます data コンポーネントをマウントするとき。 渡した関数は、コンポーネント自体にマージされます data.

もう一度通過すると、次のようになります。

it('renders correctly', () => {
  const wrapper = mount(App, {
    data() {
      return {
        x1: 37,
        x2: 99
      }
    }
  })    
  expect(wrapper.element).toMatchSnapshot()
})

もう1つのアプローチは、コード内の非決定論的関数のモック関数を作成することです。 私たちの場合、それは Math.random().

あなたは次のようなものになってしまうでしょう:

it('renders correctly with mock', () => {
  Math.random = jest.fn(() => .37);
  const wrapper = mount(App)    
  expect(wrapper.element).toMatchSnapshot()
})

ヘッダーをページの写真の上に移動したいとします。 これはVueコンポーネントへの簡単な変更なので、先に進んでそれを行ってください。 テストスイートをもう一度実行してみてください。

エラー!

スナップショットのページの配置が異なるため、失敗しました。 スナップショットのその部分を更新する必要があります。これを実行するには、 npm test -- -u.

これで、テストは再び合格しました。

成功!

スナップショットをインタラクティブに更新したい場合は、実行できます npm test -- -i.

結論

スナップショットは、アプリケーションのインターフェースへの偶発的な変更に遅れないようにするのに非常に役立ちます。 スナップショットは、他のコードと同様にGitにチェックインする必要があります。 テストが失敗した場合は、スナップショットを再帰的に更新する前に、何が起こったかを確認してください。

スナップショットテストは、Vueアプリケーションをテストする際に、特に複雑になるため、非常に役立つはずです。 頑張ってください!