はじめに
どうも。
ビジネスサイド出身・非エンジニアPMのコーディです。
前回、AIを使わずに学習記録アプリを作ってみた話を書きましたが、今回はその続き。
「じゃあ次はテストとCI/CDもちゃんとやろう」
と軽い気持ちで始めたら、
Vite × React × Jest で想像以上にドロドロの沼にハマったので、その記録を書き残します。
何をやろうとしたのか
やりたかったことはシンプルでした。
- Vite + React の個人開発アプリ
- Jest + React Testing Library で下記のテストを書く
- タイトルが表示されている
- フォームに学習内容と時間を入力して登録ボタンを押すと新たに記録が追加されている
- 数が1つ増えていることをテストする
- 削除ボタンを押すと学習記録が削除され、数が1つ減っていることをテストする
- 入力をしないで登録を押すとエラーが表示される
- GitHub Actions で
npm test→ 通ったらデプロイ
「とりあえずJest使ってみよう」と、何も考えずに進めました。
最初は余裕だと思ってた
最初は本当に簡単でした。
- Jest を入れる
- React Testing Library を入れる
- 「タイトルが表示されている」テストを書く
ここまでは問題なし。
「あ、テストって意外とすんなりイケそうじゃね?」
完全に油断してました。
沼の入口:import.meta.env
アプリでは Supabase を使っていて、
環境変数は Vite 標準のこれ。
import.meta.env.VITE_SUPABASE_URL
Jest を実行した瞬間、出てきたエラーがこれ。
最初はこう思いました。
- if 分岐で避ければいい?
- mock すればいい?
- process.env に書き換えればいい?
全部良くない。沼った。
気づいた事実(ここが地獄の本体)
ここで理解したのがこれ。
Jest は
「そのコードが実行されるか」ではなく
「構文として理解できるか」で落ちる
つまり、
if (false) {
import.meta.env
}
これでも 即アウト。
Vite 的には当たり前に使っていた構文が、
Jest 的には「見た瞬間に無理」な存在でした。
ここから沼が連鎖する
ここからが本番でした。
上手いやり方はあるのかもしれませんが。
jest.setup.js が壊れる
- import と require を混ぜると死ぬ
- ESM / CJS の違いで毎回詰まる
Babel 設定が分からなくなる
自分の今回の構成だと、
- .babelrc では JSX が動かない
- babel.config.js にすると "type": "module" で死ぬ
- .cjs にしないとダメ
mockが突然キレる
The module factory of jest.mock() is not allowed to reference out-of-scope variables
→ 変数名を mockSelect みたいにしないと怒られる(Jestの仕様)
※厳密には“mock接頭辞必須”ではなく、ホイスト都合の out-of-scope 制限が原因。回避の1パターンとして mock〜 命名があるみたいな感じらしい。
clearAllMocks と resetAllMocks の罠
- clearAllMocks:呼び出し履歴だけ消える
- resetAllMocks:実装ごと消える
これを理解してないと、
前のテストの mock が次のテストに影響する
number input の 0 問題
if (!time) { ... }
- 0 は falsy
- 未入力と区別できない
- テストだと特に顕在化する
正直、この辺から
「俺はいま何と戦ってるんだ?」状態でした。
一度は通した解:babel-preset-vite
調べまくって、最終的に辿り着いたのがこれ。
npm install --save-dev babel-preset-vite
Babel に「Vite の構文を理解させる」ことで、
-
import.meta.envが Jest でも通る - Vite 側のコードを変えずに済む
これは確かに動きました。
後で調べてみたところ、他の回避策として、Vite側で process.env 互換を用意する方法もあるみたい。(ただしアプリ側の書き方が変わりやすい)
正直しんどかった
ここまでやって思ったのが正直な感想。
- Jest を Vite に無理やり合わせている感覚
- 設定ファイルが増えすぎる
- ESM / CJS / Babel / Jest の前提が全部違う
「テストを書く」より
「テストを動かす」方が難しくなっていました。
結論:Vite なら Vitest の方が自然
今回の結論はこれです。
「Vite プロジェクトなら、最初から Vitest を使った方が幸せそう」
理由はシンプル。
- Vite と同じ実行環境
-
import.meta.envがそのまま使えそう - 設定量が圧倒的に少ない
- mental model が一致する
Jest が悪いわけじゃなくて
Vite × Jest の相性が普通に悪かった感じですね、多分。
学び
僕がプログラミングの勉強を始めた理由にもつながりますが、改めて思い知らされました。
「ちゃんとした意思決定をする」
技術選定とか本当に適当こいちゃダメ。
おわりに
この記事は失敗談だけど、初心者が本気でテストを通しに行ったから書けたものかなと。
いい経験になりました。
同じところで詰まっている人の、時間を1時間でも減らせたらいいなあ。