LoginSignup
2
0

More than 3 years have passed since last update.

Cypress で Code Coverage を測定する。

Last updated at Posted at 2021-01-04

あらすじ

Cypress で Code Coverage 測定してみました。

インデックス

Cypress Code Coverage やってみた

参考

環境設定

Vue + Vuetify + TypeScript のプロジェクトを前提にしてます。

Vue プロジェクトの作成

Babel, TypeScript, Lint を追加しておきます。

vue create {YOUR_PROJECT_NAME}
Vuetify の追加
vue add vuetify

tsconfig.json の types に vuetify と cypress を入れるのを忘れずに。

Cypress のインストール
yarn add --dev cypress
Cypress Test Runner を launch
yarn run cypress open
TypeScript のサポートをインストール
yarn add --dev @bahmutov/add-typescript-to-cypress
@cypress/code-coverage plugin をインストール
yarn add --dev @cypress/code-coverage
babel-plugin-intanbul をインストール

@cypress/code-coverage 自体にはカウンターを設置する機能はないので、 babel を頼ります。

yarn add --dev babel-plugin-istanbul
babel core をインストール
yarn add --dev @babel/core
babel.config.js を編集

.js, .ts, .vue のファイルに対し、 instrument してくれるように設定します。

babel.config.js
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
  plugins: [
    [
      "babel-plugin-istanbul",
      {
        extension: [".js", ".ts", ".vue"]
      }
    ]
  ]
};
cypress/support/index.ts を編集

code-coverage のプラグインをインポートします。

cypress/support/index.ts
// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')

import "@cypress/code-coverage/support";
cypress/plugins/index.js を編集

インポートした code-coverage のプラグインを config に反映します。

cypress/plugins/index.js
// promisified fs module
const fs = require("fs-extra");
const path = require("path");

// コンフィグファイルを読み込む。
const getConfigurationByFile = (on, config) => {
  // accept a configFile value or use development by default

  const file = config.env.configFile || "dev";
  const pathToConfigFile = path.resolve(
    ".",
    "cypress/config",
    `${file}.json`
  );
  return fs.readJson(pathToConfigFile);
};

const cypressTypeScriptPreprocessor = require("./cy-ts-preprocessor");

/**
 * @type {Cypress.PluginConfig}
 */
module.exports = async (on, config) => {
  require("@cypress/code-coverage/task")(on, config);
  on("file:preprocessor", cypressTypeScriptPreprocessor);

  config = await getConfigurationByFile(on, config);

  return Object.assign({}, config, {
    fixturesFolder: "cypress/fixtures",
    integrationFolder: "cypress/e2e",
    screenshotsFolder: "cypress/screenshots",
    videosFolder: "cypress/videos",
    supportFile: "cypress/support/index.ts",
  });
};
cypress.json を編集

codeCoverageTasksRegistered を true にすることでプラグインが有効になります。

cypress.json
{
    "baseUrl": "http://localhost:8080/",
    "env": {
        "codeCoverageTasksRegistered": true
    }
}
package.json を編集

Cypress 関連のコマンドを追加します。
Vue CLI にて Cypress をインストールした際は、サーバの立ち上げから Cypress の起動を一気に行ってくれるコマンドがすでに用意されています。
今回は Vue CLI を使っていないので、 start-server-and-test を利用します。
https://docs.cypress.io/guides/guides/continuous-integration.html#Boot-your-server

yarn add --dev start-server-and-test 
package.json
"scripts": {
    "cy:open": "cypress open --env configFile=qa",
    "cy:run": "cypress run",
    "test:e2e": "start-server-and-test serve http://localhost:8080 cy:open"
  },

※ 一部抜粋。

カバレッジを測定する

今回のテスト対象のコードはこちら。

HelloWorld.vue
<template>
  <v-app>
    <v-container>
      <div class="Home">
        <h1 data-cy="greeting">{{ greeting }}</h1>
        <v-row>
          <v-col cols="12" sm="6">
            <v-btn
              block
              color="error"
              @click="greeteEnglish"
              data-cy="greeteEnglishButton"
              >英語で挨拶</v-btn
            >
          </v-col>
          <v-col cols="12" sm="6">
            <v-btn
              block
              color="success"
              @click="greeteJapanese"
              data-cy="greeteJapaneseButton"
              >日本語で挨拶</v-btn
            >
          </v-col>
        </v-row>
      </div>
    </v-container>
  </v-app>
</template>

<script lang="ts">
/*eslint @typescript-eslint/no-explicit-any: "off"*/
import { Component, Emit, Vue } from "vue-property-decorator";

@Component
export default class TCHelloWorldVue extends Vue {
  name = "HelloWorld"

  greeting = "挨拶"

  @Emit('greeteEnglish')
  greeteEnglish() {
    this.greeting = "Hello.";
  }

  @Emit('greeteJapanese')
  greeteJapanese() {
    this.greeting = "こんにちは。";
  }
};
</script>

テストはこんな感じ。
「英語で挨拶」ボタンを押して、「 Hello. 」と表示されるかテストします。

HelloWorld.spec.ts
describe("My First Test", () => {
  it("Visits the app root url", () => {
    cy.visit("http://localhost:8080");
  });
  it("Click English greeting Button", () => {
    cy.get("[data-cy=greeteEnglishButton]").click();
    cy.get("[data-cy=greeting]").contains("Hello.");
  });
});

Cypress を起動しましょう。

yarn test:e2e

GUI の結果に注目してみます。
BEFORE ALL, AFTER EACH, AFTER ALL にて @cypress/code-coverage の処理が行われています。
image.png

最後にレポートを確認します。
image.png

今回のテストでは「日本語で挨拶」する関数を読んでいないので、レッドになっています。
日本語のテストも追加しましょう。

Home.spec.ts
describe("My First Test", () => {
  it("Visits the app root url", () => {
    cy.visit("http://localhost:8080");
  });
  it("Click English greeting Button", () => {
    cy.get("[data-cy=greeteEnglishButton]").click();
    cy.get("[data-cy=greeting]").contains("Hello.");
  });
  it("Click Japanese greeting Button", () => {
    cy.get("[data-cy=greeteJapaneseButton]").click();
    cy.get("[data-cy=greeting]").contains("こんにちは。");
  });
});

image.png

すべて ⛳️ になりました。めでたしめでたし。

E2E テストで確認出来ないコードについて

例えば E2E テストでは case 文の default を確認出来ない場合があります。
この場合は Cypress にて unit test を書くことになります。

まとめ

E2E テストでも Code Coverage を取ることで品質上げていきたい。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0