はじめに
株式会社HRBrainでフロントエンジニアをやっているしっぽくんです。最近は担当プロダクトの脱monorepoだったりアーキテクチャ見直し、エラーログ解析などの改善作業を業務の傍らやっております。
今回はその中でCI時間の短縮を行ったよ、という話をします。
かなりターゲットは限定的なので、該当する人に届けばいいなと思います。
ターゲット(これらに合致する人向けです)
- 利用技術スタック
- TypeScript を使っている
- テストプラットフォームは
Jest
- TypeScript のトランスパイルに
ts-jest
を使っている
- CI時間が長くなり始めた
TL;DR
-
@swc/jest
でトランスパイルするようにした- CIの実行時間が14分から6分の約半分ほどになった
-
jest.spyOn
は使えないので、jest.mock
に書き直した - より早くしたい場合は
vitest
やBun
への移行を視野に入れよう
テストCIがいつまでも終わらないんだけど?!
弊社では GitHub Actions を使いCIを回しています。日々の開発のなかでプルリクを出しプロダクトにコミットを積み重ねていきますが、軽微な修正でもなかなかCIを終わらないことに気づきました。
え、CI完了までに14分もかかってる?!
テストケースもそれなりにありますが、とはいえ14分はかかりすぎです。豆を挽いてコーヒーを1杯入れる時間すらあります☕️
遅さの原因
端的に言えば ts-jest で型も含めたトランスパイルを行っていることが原因でした。
// jest.config.js
"transform": {
"^.+\\.(ts|tsx)?$": "ts-jest"
},
設定ファイルに書いてたこれ
ではトランスパイルをしないようにすればいいというわけです。
とはいえメイン業務もあるので大きく変更するのは難しいです。(コスパよく対応したい...
そこで @swc/jest
が候補に挙がりました。
To make your Jest tests run faster, you can swap out the default JavaScript-based runner (ts-jest) for a drop-in Rust replacement(opens in a new tab) using SWC.
設定もシンプルでほとんど差し替えする程度でした。(実際には設定ファイルを1つ追加しましたが、環境ごとに書く設定も違うので出しません)
module.exports = {
transform: {
"^.+\\.(t|j)sx?$": "@swc/jest",
},
};
見事に半分以下に!
しかしそう簡単に移行はいかず、エラーがいくつか発生しました。(CI結果も落ちている😭)
立ちはだかる壁
ログを見ると複数のテストがこけており、中身はどれも jest.spyOn をつかっている場所でした。
エラー例: TypeError: Cannot redefine property: xxxx
調べてみると spyOn
ではモジュールとしてインポートしたオブジェクトを書き換えています。 ECMAScript Modules(ESモジュール)ではモジュールの書き換えが基本的には不可能のため spyOn
を利用している箇所で書き換えに失敗した結果になりました。
幸い spyOn
を利用している箇所も少なかったため、 mock
への置換を行うことで対処することにしました。
Jestは最新バージョンでESモジュールに対応しつつあるため、バージョンによっては今回の対応は不要になるかもしれません。
マイグレーション作業を下記で実施しました。
// spyOn実装
import HogeModule from 'hoge'
const spy = jest.spyOn(HogeModule, 'hogeMethod')
expect(spy.hogeMethod).toHaveBeenCalled()
// mock実装
jest.mock('hoge', () => {
...jest.requireActual('hoge'),
hogeMethod: jest.fn()
})
import HogeModule from 'hoge'
expect(HogeModule.hogeMethod).toHaveBeenCalled()
改善結果
最終的には install ステップもキャッシュ対応し実行時間の改善することができました👏
installもcache対応してテスト自体は4分に!
まとめ
遅いなと思ってから実装完了まで2時間半程度(内マイグレーション作業が2時間ほど)で改善できました。
設定ファイルだけ差し替えてCI回すだけならすぐ出来るので、まだ ts-jest
使っているよ!という方は検討してみてください。
ちなみに Vitest
や Bun
への移行でさらに早くなるらしいのでより速さを求める人はこちらを。
参考文献
spyOnの実装