Jest 30:より高速、より軽量、より優れたテストフレームワーク
このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
本日、Jest 30のリリースをお知らせできることを嬉しく思います。このリリースには、数多くの変更点、修正、改善が含まれています。Jest史上最大級のメジャーリリースの一つではありますが、メジャーリリースまでに3年もかかったことは確かに長すぎると認めます。今後は、より頻繁に メジャーリリースを行い、次の10年にわたってJestを優れたものにしていくことを目指します。
最新情報を飛ばしてすぐに始めたい場合は、npm install jest@^30.0.0を実行し、移行ガイド「Jest 29から30へのアップグレード」に従ってください。
新機能
Jest 30は、明らかに高速化され、メモリ使用量が削減され、数多くの新機能が追加されました。まずは破壊的変更点から見ていきましょう:
破壊的変更
-
Node 14、16、19、21のサポートを終了しました
-
jest-environment-jsdomがjsdom 21から26にアップグレードされました -
TypeScriptの最低対応バージョンが5.4になりました
-
様々な
expectエイリアスが削除されました。eslint-plugin-jestには自動修正機能があり、コードベースを自動的にアップグレードできます -
列挙不可のオブジェクトプロパティが、デフォルトで
toEqualなどのオブジェクトマッチャーから除外されるようになりました -
Jestがデフォルトで
.mtsおよび.ctsファイルをサポートするようになりました -
--testPathPatternが--testPathPatternsに名称変更されました -
最初にrejectされ、後でcatchされるPromiseを適切に処理するようになり、誤検知のテスト失敗を防げるようになりました
-
スナップショットの更新が必要になる可能性がある、スナップショット出力の様々な改善を行いました。Googleがスナップショットで使用していた
goo.glリンクを非推奨化しました。私たちもこの変更を好ましく思っていませんが、すべてのスナップショットを更新する必要があります -
Jest本体がパッケージごとに単一ファイルにバンドルされるようになりました。これによりパフォーマンスが向上しますが、Jestの内部にアクセスするツールを構築している場合は問題が発生する可能性があります
これらはハイライトの一部です。破壊的変更の完全なリストは、CHANGELOGとJest 30移行ガイドで確認できます。
パフォーマンスとメモリ改善
Jest 30は、特にモジュール解決、メモリ使用量、テスト分離に関連する多くの最適化により、実際のパフォーマンス向上を実現します。新しいunrs-resolverを採用したことで、Jestのモジュール解決は機能が豊富になり、標準に準拠し、高速になりました。移行を担当してくれた@JounQinに感謝します。プロジェクトによっては、テスト実行時間が大幅に短縮され、メモリ消費量が削減されるでしょう。例えば、クライアントとサーバーを持つ大規模TypeScriptアプリケーションでは、コードベースの一部でテスト実行速度が37%向上し、メモリ使用量が77%削減されました:
| Jest 29 | Jest 30 | |
|---|---|---|
| Server tests | ~1350s / 7.8 GB max | ~850s / 1.8 GB max |
| Client tests | ~49s / 1.0 GB max | ~44s / 0.8 GB max |
Jest自体は高速ですが、Jestのテスト分離の特性上、ユーザーコードの遅延がパフォーマンス問題を悪化させ、テスト実行を遅くすることがよくあります。テストが未完了のタイマーや他のサービスへの接続などのオープンハンドルを残すと、Jestがハングしたり遅くなったりすることがあります。Jest 30ではこれらの問題を検出・報告する機能が強化され、遅いテストや問題のあるテストを特定・修正しやすくなりました。例えばHappoでは、オープンハンドルをクリーンアップしJest 30にアップグレードすることで、テスト時間が14分から9分に50%短縮されました。
複数のモジュールのエクスポートを単一ファイルに集約する(いわゆる「バレルファイル」)を使用している場合、babel-jest-boost、babel-plugin-transform-barrels、no-barrel-fileなどのツールを利用することをお勧めします。これにより各テストファイルで大量のアプリケーションコードが読み込まれるのを防げ、最大100倍のパフォーマンス向上が期待できます。
テストファイル間のグローバル変数クリーンアップ
Jestはテストファイル間の分離を、各テストを個別のVMコンテキストで実行することで実現し、各ファイルに新鮮なグローバル環境を提供します。しかし各テストファイルの実行後にグローバル変数が適切にクリーンアップされない場合、Jest全体でメモリリークが発生し、テスト実行が遅くなる可能性があります。Jest 30では、テスト実行後に正しくクリーンアップされていないグローバル変数を通知する新機能が導入されました。
将来的にはJestは各テスト実行後に自動的にグローバル変数をクリーンアップします。Jest 30でクリーンアップされていないグローバル変数の警告が表示されない場合、今すぐグローバル変数クリーンアップモードを"on"に設定してこの機能を完全に有効化でき、大幅なメモリ節約とパフォーマンス向上の恩恵を受けられます:
export default {
testEnvironmentOptions: {
globalsCleanup: 'on',
},
};
Jestのデフォルト設定はglobalsCleanup: 'soft'です。この機能を無効にするにはoffに設定できます。共有ユーティリティやキャッシュなど、特定のグローバルオブジェクトをクリーンアップから保護する必要がある場合は、jest-utilを使用して保護対象としてマークできます:
import {protectProperties} from 'jest-util';
protectProperties(globalThis['my-property']);
この機能の実装を提供してくれた@eyalrothに感謝します!
新機能
強化されたECMAScriptモジュール & TypeScriptサポート
JestでのネイティブESM使用時にimport.meta.*とfile://のサポートが追加されました。さらにJest設定ファイルをTypeScriptで記述できるようになり、.mtsおよび.ctsファイルは追加設定なしでネイティブサポートされます。NodeのネイティブTypeScript型除去機能を使用している場合、型を除去するTypeScriptトランスフォーマーの読み込みが不要になり、テスト実行が高速化されます。
スパイとusingキーワード
JestのスパイでJavaScriptの新しい明示的リソース管理構文(using)が使用可能になりました。環境がサポートしている場合、using jest.spyOn(obj, 'method')と記述するとブロック終了時にスパイが自動的に復元されるため、手動でのクリーンアップが不要になります。
test('logs a warning', () => {
using spy = jest.spyOn(console, 'warn');
doSomeThingWarnWorthy();
expect(spy).toHaveBeenCalled();
});
expect.arrayOf
Jest 30では新しい非対称マッチャーであるexpect.arrayOfが導入され、配列の全要素に対して条件や型の検証が可能になりました。例えばすべての要素が数値であることを保証する数値配列の検証ができます:
expect(someArray).toEqual(expect.arrayOf(expect.any(Number)));
新しいtest.eachプレースホルダー: %$
データ駆動テストでtest.eachを使用する際、テストタイトルに特別なプレースホルダー%$を含めるとテストケースの番号を挿入できるようになりました。例:
test.each(cases)('Case %$ works as expected', () => {});
%$はテストのシーケンス番号に置き換えられます。
jest.advanceTimersToNextFrame()
@sinonjs/fake-timersがv13にアップグレードされ、jest.advanceTimersToNextFrame()が追加されました。この新関数により保留中の全requestAnimationFrameコールバックを次のフレーム境界まで進められるようになり、ミリ秒単位の時間を推測せずにアニメーションやrequestAnimationFrameに依存するコードのテストが容易になります。
設定可能なテスト再試行
Jest 30ではjest.retryTimes()が拡張され、再試行の処理方法を制御できる新オプションが追加されました。テストスイート全体が終了するまで待たずに、遅延を指定した り即座に失敗したテストを再試行したりできます:
// Retry failed tests up to 3 times, waiting 1 second between attempts:
jest.retryTimes(3, {waitBeforeRetry: 1000});
// Immediately retry without waiting for other tests to finish:
jest.retryTimes(3, {retryImmediately: true});
jest.unstable_unmockModule()
Jest 30では実験的な新API jest.unstable_unmockModule() が追加され、モジュールのアンモック(特にネイティブESM使用時)をより細かく制御できるようになりました。
jest.onGenerateMock(callback)
新しいonGenerateMockメソッドが追加されました。Jestがモジュールのモックを生成するたびに呼び出されるコールバック関数を登録し、モックがテスト環境に渡される前に変更できるようになります:
jest.onGenerateMock((modulePath, moduleMock) => {
if (modulePath.includes('Database')) {
moduleMock.connect = jest.fn().mockImplementation(() => {
console.log('Connected to mock DB');
});
}
return moduleMock;
});
その他の改善点
カスタムオブジェクトのシリアライゼーション
Jestのマッチャーユーティリティがカスタムオブジェクトに静的なSERIALIZABLE_PROPERTIESを定義することをサポート。スナップショットやエラーメッセージに含めるプロパティを制御でき、出力をより焦点の絞られた関連性の高いものにできます。
非同期セットアップのサポート
setupFilesAfterEnvにリストされたテストファイルがsetupFilesと同様、非同期関数のエクスポートやトップレベルawaitの使用に対応しました。
その他にも多数…
すべての変更点・改善点・新機能は完全なCHANGELOGでご確認ください。
既知の問題
jsdomが仕様準拠を強化する変更を行いました。特にテスト内でのwindow.locationモックなど一部のユースケースが影響を受ける可能性があります。Jestではjsdomベースのカスタムテスト環境構築を容易にする@jest/environment-jsdom-abstractを同梱。jsdomにパッチを適用したい場合はこのjsdomパッチをプロジェクトに適用できます。将来的にはテスト向けに最適化されたjsdomの代替手段を検討する予定です。
今後の展望
Jestは10年間で最も人気のあるJavaScriptテストフレームワークに成長し、数百万の開発者が小さなライブラリから世界最大級のコードベースまで幅広く利用しています。長期間にわたる実運用の中で技術的負債も蓄積し、少数しか利用しない機能のサポートや破壊的変更の最小化によりユーザー混乱を避けてきました。Jestで実現すべき機能のうちコアフレームワークに属さないもの、誤ったテスト手法を助長する可能性のある機能も存在します。チームメンバーの移動により進捗が鈍化した面もありますが、これらの課題を次のように解決していきます:
-
パフォーマンス/技術的負債: 大多数が使わない機能を削除し、Jestの本質的な価値に集中したより軽量で高速なコアへスリム化
-
一貫したリリースサイクル: リリース間隔と非推奨ポリシーの一貫性向上
-
オープン性の強化: 計画の透明性確保と公開場での開発推進、コントリビューター増加の機会創出
-
大胆に進めよう: Jestチームとして、もっと大胆になるべきです。Jestが本来の可能性を発揮するのを妨げている要因は数多くあります。今こそ行動を起こす時です。
素晴らしいことに、Jestは関心の分離が明確なモジュールシステムとしてフレームワークを構築した当初から、これらの原則を実現する準備が整っていました。今は実行の時です。これらについての詳細は近日中にお伝えします!
謝辞
このリリースは、私たちのコミュニティの皆様のご尽力なしには実現しませんでした。心より感謝申し上げます。
@SimenB, @mrazauskas, @Connormiha, @liuxingbaoyu, @k-rajat19, @G-Rath, @charpeni, @dubzzz, @stekycz, @yinm, @lencioni, @phawxby, @lukeapage, @robhogan, @fisker, @k-rajat19, @connectdotz, @alesmenzel, @rickhanlonii, @mbelsky, @brunocabral88, @brandon-leapyear, @nicolo-ribaudo, @dj-stormtrooper, @eryue0220
今回のリリースで初めてJestに貢献してくださった皆様に特に感謝します。皆様のおかげでJestはより良いものになりました!
@eyalroth, @KhaledElmorsy, @mohammednumaan, @bensternthal, @BondarenkoAlex, @phryneas, @jayvdb, @brandonchinn178, @latin-1, @rmartine-ias, @fa93hws, @Dunqing, @gustav0d, @noritaka1166, @andreibereczki, @Dreamsorcerer, @satanTime, @icholy, @ecraig12345, @cgm-16, @sebastiancarlos, @dancer1325, @loganrosen, @zakingslayerv22, @dev-intj, @tez3998, @anbnyc, @pengqiseven, @thypon, @co63oc, @danielrentz, @jonasongg, @andrew-the-drawer, @phryneas, @hyperupcall, @tonyd33, @madcapnmckay, @dongwa, @gagan-bhullar-tech, @ikonst, @ZuBB, @jzaefferer, @brandonnorsworthy, @henny1105, @DmitryMakhnev, @askoufis, @RahulARanger, @Jon-Biz, @fynsta, @KonnorRogers, @BondarenkoAlex, @mouadhbb, @kemuridama, @Avi-E-Koenig, @davidroeca, @akwodkiewicz, @mukul-turing, @dnicolson, @colinacassidy, @ofekm97, @haze, @Vadimchesh, @peterdenham, @ShuZhong, @manoraj, @nicolo-ribaudo, @georgekaran, @MathieuFedrigo, @hkdobrev, @Germandrummer92, @CheadleCheadle, @notaphplover, @danbeam, @arescrimson, @yepitschunked, @JimminiKin, @DerTimonius, @vkml, @ginabethrussell, @jeremiah-snee-openx, @WillianAgostini, @casey-lentz, @faizanu94, @someone635, @rafaelrabelos, @RayBrokeSomething, @DaniAcu, @mattkubej, @tr1ckydev, @shresthasurav, @the-ress, @Mutesa-Cedric, @nolddor, @alexreardon, @Peeja, @verycosy, @mknight-atl, @maro1993, @Eric-Tyrrell22






