Cypress Component Test Runner を Vue Vite で使ってみる

これは「[弁護士ドットコムアドベントカレンダー](https://qiita.com/advent-calendar/2021/bengo4com)」 の24日目の記事です。
昨日の記事は @shirauix さんでした。 （[オンラインユーザーリサーチのすすめ](https://note.com/shirauix/n/n21d438c4936c)）

----

# Cypress Component Test Runner とは？
https://docs.cypress.io/guides/component-testing/introduction

https://www.cypress.io/blog/2021/04/06/introducing-the-cypress-component-test-runner/

テスト時必要なコンポーネントのみを直接マウントすることで不要な部分の読み込みやルーティング等発生させずに高速なテストを行うことができるのがこちらのコンポーネントテスト。
まだα版のようですが、百聞は一見にしかず ということで実際に動かしてみます。

# Vue（Vite） に導入してみる（チュートリアル）

https://www.cypress.io/blog/2021/04/06/getting-start-with-cypress-component-testing-vue-2-3/

チュートリアルの内容を基に進めてみます。
こちらのチュートリアルだと Vue CLI で進めていますが、 Vite もサポートしているとのことなので 今回は Vite で立ち上げます。


[Vue のドキュメント](https://v3.vuejs.org/guide/installation.html#vite)通りにここは進めます。今回は yarn で進めていきます。

``` .bash
$ yarn create vite <project-name> --template vue
$ cd <project-name>
$ yarn
$ yarn dev
```

こんな感じの画面が出ればOK。
![スクリーンショット 2021-12-19 23.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/ebff7d5c-0e43-d393-9808-8e7a4d9475c2.png)

必要なライブラリをインストールします。

``` .bash
$ yarn add cypress @cypress/vue@next @cypress/webpack-dev-server @cypress/vite-dev-server --dev
```
チュートリアルには書いていないが Vite の場合は、`@cypress/vite-dev-server` がないと怒られるので注意。


必要なファイルを用意します。（[ドキュメント](https://docs.cypress.io/guides/component-testing/framework-configuration#Vite-Based-Projects-Vue-React)）

``` cypress/plugins/index.js
const path = require('path')
const { startDevServer } = require('@cypress/vite-dev-server')

module.exports = (on, config) => {
  on('dev-server:start', (options) => {
    return startDevServer({
      options,
      viteConfig: {
        configFile: path.resolve(__dirname, '..', '..', 'vite.config.js'),
      },
    })
  })
}
```

テストは `.spec.ts`　に書いていきます。

``` cypress.json
{
  "testFiles": "**/*.spec.ts",
  "componentFolder": "src"
}
```

ここまで準備できたら `src/components/HelloWorld.vue` をテストするコードを用意してみます。
props されたデータが正しく反映されるかテストします。


``` src/components/HelloWorld.spec.ts
import { mount } from '@cypress/vue'
import HelloWorld from './HelloWorld.vue'

describe('HelloWorld', () => {
  it('renders a message', () => {
    const msg = 'Hello Cypress Component Testing!'
    mount(HelloWorld, {
      propsData: {
        msg
      }
    })

    cy.get('h1').should('have.text', msg)
  })
})
```


テストを実行してみます。

``` bash
$　yarn cypress open-ct
```

![スクリーンショット 2021-12-20 0.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/828af8f9-00d9-8f80-6abe-09fbe8c9504d.png)

テストの結果とテストコード内で指定したコンポーネントが表示されているはずです。
今回テストが成功しているため緑のチェックマークがついています。
次にわざと失敗してみます。テストの内容を変更します。

``` src/components/HelloWorld.spec.ts
import { mount } from '@cypress/vue'
import HelloWorld from './HelloWorld.vue'

describe('HelloWorld', () => {
  it('renders a message', () => {
    const msg = 'Hello Cypress Component Testing!'
    mount(HelloWorld, {
      propsData: {
        msg
      }
    })

    cy.get('h1').should('have.text', 'hogehoge')
  })
})
```

`hoge`とは表示されないので失敗するはずです。
変更を保存をするとリアルタイムでこの結果を反映してくれます。先ほどのテストの結果が表示されていた画面に戻ると...

![スクリーンショット 2021-12-20 1.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/198258f8-1b20-4356-b9a0-71687c0e762a.png)

ちゃんと失敗してくれてます。すばらC。
勿論、コンポーネント側の実装を変更してもその内容がリアルタイムに反映されます。

# 簡単なテストを書いてみる

チュートリアルだけだと面白くないので追加で簡単な実装とそのテストコードを書いてみます。
新たにボタンを用意して、そのボタンをクリックでカウントが2倍になるかテストしてみます。

テスト駆動開発的に、まずはテストを書きます。
`add_button`（既存のボタン）を2回クリックして`twice_button`（新規で実装するボタン）をクリックしたら4になるよねっていうテスト。

``` src/components/HelloWorld.spec.ts
import { mount } from '@cypress/vue'
import HelloWorld from './HelloWorld.vue'


describe('HelloWorld', () => {

// 省略

  it('2倍ボタンクリックでカウントが2倍になる', () => {
    mount(HelloWorld)
    cy.get('#add_button').click()
    cy.get('#add_button').click()
    cy.get('#twice_button').click()
    cy.get('#add_button').should('have.text', 'count is: 4')
  })
})
```
この状態で一度テストを実行。

``` bash
$　yarn cypress open-ct
```

![スクリーンショット 2021-12-21 0.46.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/2ed24d25-e24e-9199-19bb-79476da57705.png)


勿論テストは通らないです。

実装していきましょう。

```　src/components/HelloWorld.vue
<template>

// 省略

　　　　// 既存のボタンに id="add_button" を追加
  <button id="add_button" type="button" @click="count++">count is: {{ count }}</button>
  // 2倍ボタンを追加
  <button id="twice_button" type="button" @click="count = count*2">2倍</button>

// 省略

</template>
```


保存すると、
![a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/0d194649-610d-51f0-8591-18557705e78d.gif)


テストが通ったことが確認できます。見た目を確認しながらテスト駆動開発できるの非常に良いですね。

---

## ヘッドレスモードでテストを実行する

ヘッドレスモードでも実行できます。

``` .bash
$ yarn cypress run-ct
```

テストの結果がターミナル上で表示される。
![スクリーンショット 2021-12-21 0.50.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/3d136ae8-ad51-1787-c228-ea060d84f36a.png)
だけと思いきや`cypress/videos/components/HelloWorld.spec.ts.mp4`が作成されている。
見てみると...
![HelloWorld.spec.ts.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491279/96997b67-cee1-32e8-c5d5-7377687a0a70.gif)
実行したテストの動画ファイルを作成してくれます。Cypress ｽｺﾞｽｷﾞ！ 

# 感想

- コンポーネントの見た目を含むテスト結果をリアルタイムで表示してくれるのでテスト駆動開発しやすそう
- コンポーネントを横断しないE2Eテストはこれで書き換えれば大きく軽量化できそう
- テストの動画ファイル作成してくれる件は感動したが使い道があまり思いつかない...
- まずは個人開発で使ってみようと思う