Vue, Reactに代表されるSPAのjavascriptフレームワークが増えたことで、フロンドエンドのテストが重要になってきました。少し前ではE2Eテストの自動化と言えば、Seleniumを用いたブラウザの自動化、ほぼ一択でしたが近年では、有償のツールなども多くあります。今回は、そのE2Eテストの自動化ツール、Cypressを開発中のプロジェクトに導入してときにちょっと困った話について紹介したいと思います。

Cypressとは

E2Eテストフレームワークの一つです。次のような特徴があります。

  • テストが高速
  • 無料でテストができる(ダッシュボードは有料)
  • typescriptとの相性が良い

対応ブラウザ

以前は、Chrome一択だったのですが、Ver4からは複数のブラウザに対応しています。対応しているブラウザは、公式サイトをご確認ください。

導入方法

cypressは、プロジェクトごとにインストールするほうが良いので、プロジェクトディレクトリにて、下記コマンドでインストールができます。

$ yarn add -D cypress

下記コマンドを実行するとCypressのメインウィンドウが表示されます。

$ ./node_modules/.bin/cypress open

下記windowsが立ち上がります。

OKボタンを押して閉じます。テストスクリプトはインストールディレクトリの中の cypress の中の integration の中にあります。下記は、example_spec.jsがインストールされている様子です。

ここからスクリプトをクリックすれば、ひとまず実行されます。

公式サイトやサンプル

インストールが完了したら、初めてのテストの書き方をみましょう。15分ぐらいでなんとなく書き方がわかると思います。

こちらは、上のサイトでも紹介されている通り、Cypressが利用できるかを見る非常にシンプルなテストです。

describe('My First Test', () => {
  it('Does not do much!', () => {
    expect(true).to.equal(true)
  })
})

RSpecと同じ形式なので、RSpecやそれから派生したテストフレームワークを普段から触っている人は、馴染めるかと思います。サンプルも公式サイトの方で紹介されているので、このあたりを見ながら比較的簡単に実装できるかと思います。Typesceriptに絡めた解説は、こちらにあります。

GitLabCIで発生したエラーの紹介

発生したときに利用していたものとしては、下記のものがあります。

  • NuxtJS
  • typescript
  • Jestによる単体テスト導入
  • GitlabCIによるCI

Nuxtプロジェクトで生成されたテンプレートにjestというunittestフレームワークを導入しし、gitlabCIで単体テストをMRを出したタイミングで実行するような仕組みになっています。

README.md
assets
components
composition
conf
coverage
cypress
cypress.json
domain
jest.config.js
layouts
middleware
node_modules
nuxt.config.js
package.json
pages
plugins
static
store
tailwind.config.js
test
tsconfig.json
types
yarn.lock

cypressの導入によって、cypressというディレクトリが追加された状態にしてからMRを出したところ、下記のようなエラーが 発生しました。

warning " > vue-jest@3.0.7" has unmet peer dependency "vue@^2.x".
warning " > vue-jest@3.0.7" has unmet peer dependency "vue-template-compiler@^2.x".
[4/4] Building fresh packages...
Done in 75.18s.
$ cd $FRONT_SRC_TOP && yarn test:unit
yarn run v1.22.0
$ jest test/
FAIL test/pages/reminder.spec.ts
  ● Test suite failed to run
    test/pages/reminder.spec.ts:63:21 - error TS2339: Property 'toBeTruthy' does not exist on type 'Assertion'.
    63     expect(wrapper).toBeTruthy()

1時間ぐらい悩んだのですが、expectjestとcypressの2つで提供されていて、jestの型定義で認識してほしい場所で、cypressのexprectとして認識されているのが原因でした。

修正方法

単体テストでは、jestの型をcypressを利用するときは、cypressの型を使えばOKなので、

こんな感じでトップのtsconfig.jsonで”cypress”は除外するようにしました。

{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ESNext",
    "moduleResolution": "Node",
    "lib": [
      "ESNext",
      "ESNext.AsyncIterable",
      "DOM"
    ],
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@types/node",
      "@nuxt/types",
      "jest"
    ]
  },
  "exclude": [
    "node_modules",
    ".nuxt",
    "dist",
    "cypress"
  ]
}

cypressを利用する場合のtsconfig.jsonは、専用にcypress/に配置するように変更

{
  "compilerOptions": {
    "noEmit": true,
    "types": [
      "cypress"
    ]
  },
  "include": [
    "./*/*.ts"
  ]
}

こんな感じで直りました。

まとめ

cypressは、昔ちょっと触ってから久しぶりに触りましたが使いやすい印象を持ちました。E2E向けテストで無料で利用できるものが少ないので、選択肢の一つとして今後は注目していこうかなと思います。お疲れ様でした。