Open6

Jest から Vitest 移行の対応まとめ

仕事で開発中のシステムのテスト環境を Vitest に移行しました

注意点として、Vitest はまだかなり新しく、Jest と比べ安定してるとは言えないライブラリです
以前は Vitest の GitHub の README に本番環境での利用は非推奨の文言がありました
このコミットで削除されたようですが、バージョンもまだ v0 系なのでしばらくは破壊的変更やバグもそれなりに出る可能性はあります)

移行を決断したポイントは以下です

  • Jest(webpack)のパフォーマンス改善に限界を感じた
    • 現システムで GitHub へ Push するたびに Build、Lint、テストなどを行う CI が走るが、システムの規模が大きく完了に毎回 20 分程度かかる(そのうちテストは 7〜8 分)
  • UI のテスト(Storyshots)は引き続き Jest で行う
    • Storyshots は現状、Jest のみで動くため
    • 移行の対象を UI 以外にフォーカスしたことでハードルがだいぶ下がった
  • Vitest は Jest と互換性が高いので、修正箇所が少なそうだった

結果的に UI 以外のテストを Vitest に移行したところ、CI のテストは 5 分程度になりました
一応この移行のゴールは Jest 依存の完全排除なので、対応が進んだらまたこのスクラップ記事に追記します

環境は全体的に少し古いですが、以下です

  • vitest
    • v0.7.7
  • typescript
    • v3.9.2
  • Node
    • v14.19.1

Node は v14 系だと v14.19.0 以上が必須でした(vitest が v0.7.7 の場合)
現在最新の vitest v0.9.3 だと Node v14.16.0 が必須になります(また変わるかもしれません)

https://github.com/vitest-dev/vitest/blob/v0.9.3/packages/vitest/package.json#L132
Node は v16 系とかを使っておくのが安定かなと思います

typescript も v3 系ですが、vite か vitest の型定義で Template Literal Types を使っている箇所があったので、型チェックも行うなら typescript v4.1 以上が必要になります

Jest のグローバルなオブジェクトや関数

describe や it など
これらはそのままグルーバルに使用したい

以下を設定ファイルに書く

vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  test: {
    globals: true,
  },
});

テストコードで jest を直接呼んでるやつ

たとえば、以下のようにテストコードで直接 jest を書いている

jest.mock(...);
jest.fn(...);

beforeAll(() => {
  jest.useFakeTimers();
  jest.setSystemTime(new Date("2000-01-01 00:00:01"));
});

afterAll(() => {
  jest.useRealTimers();
});

以下で置換できる

import { vi } from "vitest";

vi.mock(...);
vi.fn(...);

beforeAll(() => {
  vi.useFakeTimers();
  vi.setSystemTime(new Date("2000-01-01 00:00:01"));
});

afterAll(() => {
  vi.useRealTimers();
});

排除できない Babel 依存

将来的には排除したいが、今は難しい Babel プラグインは以下で対応

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ["babel-plugin-macros"],
      },
    }),
  ],
});

(現状、ビルド環境も Babel 依存の webpack なので、Vite にしたい)

resolve alias の設定

alias を使っている場合は以下で設定できる

vite.config.ts
import path from "path";
import { defineConfig } from "vite";

export default defineConfig({
  resolve: {
    alias: {
      "@s": path.join(__dirname, "../shared/src"),
    },
  },
});

もし正規表現を使いたい場合は、上記の書き方だと使えないので、以下にする必要がある

vite.config.ts
import path from "path";
import { defineConfig } from "vite";

export default defineConfig({
  resolve: {
    alias: [
      { find: "@s", replacement: path.join(__dirname, "../shared/src") },
      {
        find: /.+\.(jpg|jpeg|png|gif)$/,
        replacement: path.join(__dirname, "../__mocks__/fileMock.js"),
      },
    ],
  },
});
作成者以外のコメントは許可されていません