💯
node:test と ESLint RuleTester の組み合わせ方
ESLint の RuleTester を Node.js 組み込みテストランナー(node:test)で動かすための方法をまとめる。
やりたいこと
- Node.js 組み込みテストランナー
node:test(node --test)を使う - 既存の
RuleTester.run()の書き方はそのまま使う(valid / invalid のオブジェクトでテストを書く)
なぜわざわざ node:test を使うのかって?ロマンですよロマン。
▼「Node.js 組み込みテストランナー」って、何?って人は以下の記事を参照してください。
ツールバージョン
- ESLint: 9.18.0
- Node.js: 22.22.0
-
erasable TypeScript syntax の除去による TypeScript サポート が利用可能なので、ルール本体を除いて TypeScript を利用している。
- ルール本体は、ESLint 側での TypeScript サポートを待つ必要があるので、JS のまま。
-
erasable TypeScript syntax の除去による TypeScript サポート が利用可能なので、ルール本体を除いて TypeScript を利用している。
手順
1. テスト実行前に RuleTester に node:test を繋ぎ込む
--import で、テストファイルよりも先に読み込んで実行する「セットアップ用スクリプト」を指定する。
package.json
{
"scripts": {
"test": "node --import ./test-setup.mts --test"
}
}
-
--import ./test-setup.mts: テスト実行前にtest-setup.mtsを 1 回ロードする -
--test: Node の組み込みテストランナーで*.test.*/*.spec.*を検出して実行する
2. test-setup.mts で RuleTester の describe / it を差し替える
RuleTester は内部で describe と it を呼ぶ。ここを node:test の API に差し替える。
test-setup.mts
import { RuleTester } from 'eslint';
import * as test from 'node:test';
RuleTester.describe = test.describe;
RuleTester.it = test.it;
RuleTester.itOnly = test.it.only;
-
RuleTester.it/RuleTester.describe/RuleTester.itOnlyを、それぞれnode:testのit/describe/it.onlyに差し替える。- 依存性の注入みたいな感じ
3. テストファイルは従来どおり RuleTester.run() で書く
各ルール用の *.test.mts では、RuleTester の通常の使い方のままでよい。
my-rule.test.mts
import { RuleTester } from 'eslint';
import myRule from './my-rule.mjs';
const ruleTester = new RuleTester({
/* 略 */
});
ruleTester.run('my-rule-name', myRule, {
valid: [
/* 略 */
],
invalid: [
/* 略 */
],
});
セットアップで RuleTester.it / RuleTester.describe を差し替えているので、この run() から呼ばれるテストはすべて node:test を通じて実行される。
まとめ
- 実行コマンド:
node --import ./test-setup.mts --testで「セットアップ読み込み → node:test でテスト検出・実行」 - セットアップ:
RuleTester のit/describe(と必要ならonly)をnode:testの API に差し替える - テストコード:
これまで通りruleTester.run(...)で valid / invalid を書く
この形にしておけば、追加のテストライブラリなしで、 node:test と RuleTester を組み合わせて使える。
GitHub 上で同様の構成を取っているプロジェクトについて
結論: 同じ構成(node:test + RuleTester + --import で describe/it 差し替え)を取っている公開プロジェクトは、調査時点では見つかっていない。
関連する事実
- ESLint 本体はテストに Mocha を使い続けている(公式ドキュメント)。node:test への移行は行われていない。
-
RuleTester の describe/it 差し替えは ESLint 側でサポートされている。
- 過去に「差し替えが効かない」バグがあり、ESLint PR #15507 で修正された。
-
typescript-eslint Issue #4422 では、uvu と RuleTester を組み合わせるために
RuleTester.it/RuleTester.describeを差し替える例が議論されている(node:test ではないが、同じ「別ランナーに載せる」考え方)。
- Vitest と RuleTester を組み合わせる目的の eslint-vitest-rule-tester など、別ランナー用の RuleTester ラッパーは存在する。node:test 専用の同様パッケージは見当たらない。
- 「node --test」と「ESLint ルールのテスト」 を同時に扱っている Issue/PR はあるが(例: nodejs/node#16138、eslint-plugin-import#2603)、いずれも「node:test と RuleTester を組み合わせる」構成の事例ではない。
Discussion