🧪

Next.jsプロジェクトをJestからVitestへ移行したら実行時間が85%減った話

に公開

圧倒的じゃないか,Vitest は.

Vitest

Test Files  12 passed (12)
Tests       100 passed (100)
Start at    06:01:55
Duration    13.46s (transform 411ms, setup 0ms, collect 2.31s, tests 1.72s, environment 5.70s, prepare 1.05s)

Jest

Test Suites: 12 passed, 12 total
Tests:       100 passed, 100 total
Snapshots:   0 total
Time:        88.807 s
Ran all test suites.

状況

私が担当している新規事業のプロジェクトでは,品質担保のため開発プロセスの早い段階からテストを組み込むこととした.当初,テストツールの選定において Jest と Vitest を検討したが,Next.js で生成される JavaScript のコードと Vitest で生成される JavaScript のコードに互換性の問題があるという情報があったため,初期選定では Jest を採用した.

Jest は長年にわたり JavaScript アプリケーションのテストのデフォルト選択肢であり,特に React エコシステムとの統合が優れているため自然な選択肢であった(後ろ髪を引かれながら自分を納得させた).

移行の動機

開発が進むにつれ,テスト実行にかかる時間が長くなり,開発効率に影響を及ぼすようになった.GitHub Actions での CI 実行結果を見ると,Jest でのテスト実行に約 89 秒もかかっていた.

Test Suites: 12 passed, 12 total
Tests:       100 passed, 100 total
Snapshots:   0 total
Time:        88.807 s
Ran all test suites.

プルリクエスト作成時に謎のコーヒータイムが発生していたため,より高速なテスト実行が可能な Vitest への移行を検討することにした.

Vitest とは

Vitest は,Vite を補完するために作られた JavaScript ユニットテストフレームワークである.Vite はモダンな開発環境に適した高速なビルドツールおよび開発サーバーであり,その特性を活かして Vitest は非常に高速なテスト実行を実現する.

Vitest の主な特徴として,Vite のインフラストラクチャを活用した高速なテスト実行,ES モジュールのネイティブサポート,TypeScript との親和性,ビルトインのモックやアサーションライブラリなどが挙げられる.ちなみに今回のように Vite を使用していなくても Vitest は使用できる.

Jest vs Vitest:主な違い

パフォーマンス面の比較をすると,Jest は設定が複雑でより多くの依存関係を持つ一方,Vitest は軽量で高速なテスト実行が可能である.実際の比較では,同じテストを Jest が 739ms で実行するのに対し,Vitest は 131ms で実行できたという例もある.

また,Vitest は Jest の API と高い互換性を持つように設計されており,これにより移行作業が大幅に簡略化される.今回ももともと書かれていた Jest のコードがあったが,モックなど一部を修正しただけで動作させることができた.

Vitest への移行手順

公式ドキュメントに従って必要なパッケージをインストールする.公式ページには書かれていないが,カバレッジを表示するために @vitest/coverage-v8 をインストールする必要がある.

npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths @vitest/coverage-v8

プロジェクトのルートにvitest.config.tsファイルを作成し,以下の設定を行う.

import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import path from "node:path";

export default defineConfig({
  plugins: [tsconfigPaths(), react()],
  test: {
    environment: "jsdom",
    globals: true,
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
      include: ["src/**/*.{ts,tsx}"],
    },
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
      "~": path.resolve(__dirname, "./src"),
    },
  },
});

この設定では,以下の重要なポイントに注意した.

  1. environment: "jsdom":ブラウザ環境をシミュレートするための JSDOM を使用
  2. globals: true:テスト関数をグローバルに利用可能にする
  3. plugins: [tsconfigPaths(), react()]:TypeScript のパス解決と React のサポートを有効化
  4. alias 設定:プロジェクトのパス設定を Vitest でも使用できるよう設定

また,tsconfig.json にも以下に変更して設定を適用する.

{
  "compilerOptions": {
    // ...その他の設定
    "types": ["vitest/globals"]
  },
  "include": [
    // ...その他のinclude項目
    "vitest.config.ts"
  ]
}

最後に,package.jsonのテスト実行コマンドを更新.

"scripts": {
    "test": "vitest run --coverage"
}

移行の結果

Vitest への移行後,テスト実行時間は劇的に短縮された.GitHub Actions での実行結果は以下の通りである:

Test Files  12 passed (12)
Tests       100 passed (100)
Start at    06:01:55
Duration    13.46s (transform 411ms, setup 0ms, collect 2.31s, tests 1.72s, environment 5.70s, prepare 1.05s)

Jest の約 89 秒から,Vitest では約 13.5 秒へと約 85%の時間短縮に成功した.これにより,CI の実行時間が大幅に短縮された.

移行時の注意点

  • Jest の設定は削除する:jest.config.jsbabel-jest などの依存関係は不要になる.不要なファイル,パッケージなどは削除しておく.

  • テストコードの調整:今回ほとんどのテストコードはそのまま動作したが,一部のモックやマッチャーについては調整が必要であった.

まとめ

Next.js プロジェクトで Jest から Vitest への移行は非常に効果的で,テスト実行時間を大幅に短縮することができた.初期には Jest を選択したものの,プロジェクトの成長に伴い,Vitest のパフォーマンス面でのメリットが明らかになった.

プロジェクトを新規に始める場合でパフォーマンスを重視するなら,Vitest は優れた選択肢である.生成される JavaScript の問題は今のところ発生していない.

今回はプロダクトの管理者機能部分での移行を行ったが,今後は他の部分でも Vitest を導入していく予定である.

追記

別プロジェクトでも同様に移行してみたが爆速で草 w

Vitest

Test Files  12 passed (12)
Tests       119 passed (119)
Start at    03:04:11
Duration    14.48s (transform 546ms, setup 0ms, collect 3.00s, tests 2.31s, environment 5.45s, prepare 1.03s)

Jest

Test Suites: 12 passed, 12 total
Tests:       119 passed, 119 total
Snapshots:   0 total
Time:        93.834 s
Ran all test suites.

以上だ( `・ω・)b

GitHubで編集を提案

Discussion