PeekyでVite + PetiteVueのテストを書く

目的

Vite を使って Web フロントエンドの素早い開発を行いたいが、Vite はブラウザ上の動作と production build に主眼が置かれていてテストコードどうすんの問題を抱えている。

今回はこれを解決していく。

まずは材料の紹介

Viteベースのテスティングフレームワーク

Vite を使ったテスティングフレームワークの二大巨頭は Vitest と Peeky だと思う。

二つともめちゃくちゃよく似たものになっていて、見つけた時点ではファンシーな Web UI は Peeky にしかなかった気がするんだけど、今は Vitest にもあるっぽい。正直どっち使ってもできることにはほとんど差がないんじゃないかという気がする。

Peekyの特徴

Peeky は 0.13.6 時点で以下のような特徴を持つ。

  • いきなり TypeScript が動く(まぁ Vite ベースなので)
  • Jest 互換の BDD
  • stub/mock は Sinon を採用
  • DOM ベースのテストに Haapy DOM を採用

動かし方

  1. @peeky/test を追加
  2. npm scripts に peeky run を追加
  3. テストコードは .spec.jsspec.ts といった名前で置く(場所は自由)か、__tests__/ 以下に置く

こんだけ。Jest の簡単さも最初はビビったもんだけど、Vite 以降の世界は速さも簡単さもマジで新時代に入ってる。

PetiteVueアプリのmountにはPeeky標準のHappy DOMでは不十分

以下で確認。

  • PetiteVue 0.4.1
  • Peeky 0.13.5
  • Happy DOM 2.24.4

対処法は jsdom-global を利用する。具体的には

  • jsdom, jsdom-global を依存に追加
  • peeky.config.jsimport 'jsdom-global/register.js' とだけ書く

これだけ。

すでに vite.config.js があるならそちらに書いてもよいが、特に設定を用意していないなら vite.config.js をわざわざ新しく設置する必要はない。

この時、peeky config に runtimeEnv: 'dom' の設定を追加してはいけない。あってもよいかもしれないけど、この設定は Happy DOM を有効にする設定であり、どうせ JSDOM に置き換える必要があるため、書かない方がややこしいことになりにくい。

これであとは いちばんシンプルにStimulus ControllerをMochaでテストする方法 (2021-09-17) | あーありがち のように document を書き換えてやれば DOM の準備は ok.

生DOMアプリのテストにはMutationObserverの知識も

どういうことかと言うと、もし DOM 書き換え後の状態を知りたい場合、ちゃんと変更を監視する必要がある。具体的には以下のようなテストコードになる。

it('', () => {
  const observer = new window.MutationObserver(() => {
    expect(...)
  })
  observer.observe(document, { ... })

  const button = document.querySelector('button')
  button.click()
})

こうなると見て分かる通り expect が上の方にあって、後から実際の操作を記述することになるので、ちょっと処理を目で追いにくくなってしまう。

Viteを利用したTypeScriptのテストの感想

そもそも Vite の特徴として tsc や ts-loader のようなものを経由していないから速いというものがあって、

Features | Vite

ドキュメントにも以下のように書かれている。

Vite only performs transpilation on .ts files and does NOT perform type checking. It assumes type checking is taken care of by your IDE and build process (you can run tsc –noEmit in the build script or install vue-tsc and run vue-tsc –noEmit to also type check your *.vue files).

type check しないんですって。

これは一見すると非常に大きなディスアドバンテージのように見えるが、自分としてはこの挙動は特に問題ないと思っている。というのも、現時点ではブラウザは TypeScript は解釈できず、TypeScript の書き手の意図を無視した自由気ままなデータがブラウザから渡ってくる。Jest など真面目に TypeScript として動作するテスティングフレームワークでは、この「ブラウザからの自由気ままなデータ」に対応できているかどうかを確認するためのテストを書くことができない。書けても動かせない。

まぁテストコードを JavaScript で書けばいいんだけど、TypeScript を書き始めたらたぶん全部 TypeScript で書きたくなるだろうし、最初から

  • 型チェックはコンパイルと IDE 支援で
  • テストコードは実際の動作をテスト

します、でよいと思う。だいたい人間が「プロダクトコードは TypeScript で、テストコードは JavaScript で書きます」と決めても、何も考えずに書いて同じ結果になる Vite より遅いんだしね。

More