State of JSの結果で注目を集めているVitestをJestと比較

に公開

https://2024.stateofjs.com/

State of JSのアンケート結果を見て、テスティングライブラリの項目でVitestが注目されているのを知り、Jestとの違いを調べてみました。

Jest

JestはFacebookが開発したテスティングフレームワークで、Reactアプリケーションのテストのために設計されています。強力な機能と広範なコミュニティのサポートにより、JavaScriptエコシステムで広く使用されています。

// sum.js
export function sum(a, b) {
  return a + b;
}

// sum.test.js (Jest)
import { sum } from './sum';

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

Jestはテストファイルを.test.jsまたは.spec.jsとして作成し、testまたはit関数を使ってテストケースを定義します。設定なしでそのまま実行できるのが大きな利点です。

npx jest

Vitest

VitestはViteエコシステムと密接に連携する最新のテストランナーです。高速な実行とシンプルな構成を提供し、特にViteベースのプロジェクトにおいて便利さが注目されています。

// sum.js
export function sum(a, b) {
  return a + b;
}

// sum.test.js (Vitest)
import { describe, it, expect } from 'vitest';
import { sum } from './sum';

describe('sum', () => {
  it('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
  });
});

Vitestも似たような方法で動作しますが、describeやit関数はVitestからインポートします。Viteプロジェクトでは、高速かつ簡単に設定できる点が特徴です。

npx vitest

ライブラリの主な違い

速度

jest

初期実行速度が遅く、特に大規模プロジェクトではパフォーマンスのボトルネックが発生する可能性があります。
CommonJSモジュールシステムを基盤としているため、最新のバンドリング技術と比較すると速度が相対的に遅いです。

// processData.test.js
import { processData } from './processData';
import { fetchData } from './api';

jest.mock('./api'); // fetchDataをモック化

describe('processData', () => {
  it('should return processed data', async () => {
    // fetchDataのモック動作を定義
    fetchData.mockResolvedValue({
      title: 'sample title',
      userId: 1,
    });

    const result = await processData();

    expect(result).toEqual({
      title: 'SAMPLE TITLE',
      userId: 1,
    });
    expect(fetchData).toHaveBeenCalledTimes(1);
  });

  it('should throw an error if fetchData fails', async () => {
    fetchData.mockRejectedValue(new Error('Network Error'));

    await expect(processData()).rejects.toThrow('Network Error');
  });
});

Vitest

Viteの高速なバンドリングとHMR(Hot Module Replacement)を活用することで、テストの速度が非常に速いです。
テスト環境が素早く起動し、コードを変更した後、即座に結果を確認することができます。

// processData.test.js
import { describe, it, expect, vi } from 'vitest';
import { processData } from './processData';
import { fetchData } from './api';

// fetchDataをモック化
vi.mock('./api', () => ({
  fetchData: vi.fn(),
}));

describe('processData', () => {
  it('should return processed data', async () => {
    // fetchDataのモック動作を定義
    fetchData.mockResolvedValue({
      title: 'sample title',
      userId: 1,
    });

    const result = await processData();

    expect(result).toEqual({
      title: 'SAMPLE TITLE',
      userId: 1,
    });
    expect(fetchData).toHaveBeenCalledOnce();
  });

  it('should throw an error if fetchData fails', async () => {
    fetchData.mockRejectedValue(new Error('Network Error'));

    await expect(processData()).rejects.toThrow('Network Error');
  });
});


設定と構成

Jest

Reactプロジェクトと一緒に使用する場合、初期設定が簡単で、多くの機能がデフォルトで提供されます。
しかし、React以外のプロジェクトや最新のツールチェーン(Vite、ES Modulesなど)との統合には追加の設定が必要です。

// jest.config.js
export default {
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
  },
  testEnvironment: 'node',
};

Vitest

Viteベースのプロジェクトと自然に統合され、追加の設定なしで迅速に始められます。
Viteの設定ファイルをそのまま利用できるため、一貫した環境を維持することができます。

// vite.config.js
import { defineConfig } from 'vite';
import { configDefaults } from 'vitest/config';

export default defineConfig({
  test: {
    exclude: [...configDefaults.exclude, '**/node_modules/**'],
  },
});

ES Module対応

Jest

CommonJSをデフォルトとしており、ES Modules(ESM)を使用する場合は追加の設定が必要です。
最新のJavaScript標準との互換性が完全ではない可能性があります。

// package.json
{
  "type": "module",
  "jest": {
    "transform": {
      "^.+\\.js$": "babel-jest"
    }
  }
}

Vitest

ES Moduleをデフォルトでサポートしており、最新のJavaScript標準を使用するプロジェクトに適しています。
ESMサポートが必要なViteベースのプロジェクトで強みを発揮します。

// sum.test.js
import { describe, it, expect } from 'vitest';
import { sum } from './sum';

describe('sum', () => {
  it('works with ES Modules', () => {
    expect(sum(1, 2)).toBe(3);
  });
});

Jestが適している場合

React中心のレガシープロジェクトを扱う場合や、コミュニティのサポートが重要な場合

Vitestが適している場合

Viteベースの最新プロジェクトで、迅速なテスト環境を求める場合

結論

State of JSのアンケート結果からVitestの注目度が高まっていることを確認し、Jestと比較したところ、それぞれの長所と短所が明確に分かりました。
特に、迅速な開発サイクルが求められるプロジェクトでは、Vitestがより適していると感じました。

Discussion