Action Cable の JavaScript テストを Web Test Runner に移行

rails/rails

Action Cable のフロントエンドテストは、Karma から Web Test Runner へ置き換えられ、Sauce Labs 連携が新しいモジュールに統合されました。テストの振る舞いは変更せず、保守が継続されるツールチェーンへ移行した点が主旨です。

背景

Karma が公式に Deprecated とされ、バグ修正や新機能の受け入れが行われなくなっています。既存の actioncable/karma.conf.js にはブラウザ設定や Sauce Labs 用ランチャーがハードコードされており、CI で観測されるフレークの根本的な対処が困難でした。PR の説明は、メンテナンスが停止したツールチェーンから脱却し、安定した実行基盤を確保したいと述べています。

-const config = {
-  browsers: ["ChromeHeadless"],
-  frameworks: ["qunit"],
-  files: ["test/javascript/compiled/test.js"],
-  client: { clearContext: false, qunit: { showUI: true } },
-  singleRun: true,
-  autoWatch: false,
-  captureTimeout: 180000,
-  browserDisconnectTimeout: 180000,
-  browserDisconnectTolerance: 3,
-  browserNoActivityTimeout: 300000,
-}
-
-if (process.env.CI) {
-  config.customLaunchers = {
-    sl_chrome: sauce("chrome", 70),
-    sl_ff: sauce("firefox", 63),
-    sl_safari: sauce("safari", "16", "macOS 13"),
-    sl_edge: sauce("microsoftedge", "latest", "Windows 11"),
-  }
-  config.browsers = Object.keys(config.customLaunchers)
-  config.reporters = ["dots", "saucelabs"]
-  config.sauceLabs = { testName: "ActionCable JS Client", retryLimit: 3, build: buildId() }
-  function sauce(browserName, version, platform) { /* 省略 */ }
-}

上記の削除に伴い、Karma 固有の設定ファイルはリポジトリから完全に除去されました。

技術的な変更

依存関係actioncable/package.json で大幅に入れ替えられ、@web/test-runner 系列と web-test-runner-qunit が追加され、従来の karma 系列が削除されています。変更点は次の通りです。

@@ -27,24 +27,23 @@
-    "karma": "^6.4.2",
-    "karma-chrome-launcher": "^2.2.0",
-    "karma-qunit": "^2.1.0",
-    "karma-sauce-launcher": "^1.2.0",
+    "@web/test-runner": "^0.20.2",
+    "@web/test-runner-saucelabs": "^0.13.0",
@@
-    "qunit": "^2.8.0",
+    "qunit": "^2.20.0",
@@
-    "test": "karma start"
+    "test": "node test/javascript/run_web_test_runner.mjs"

テスト実行エントリーポイントとして actioncable/test/javascript/run_web_test_runner.mjs が新規追加され、@web/test-runnerstartTestRunner を呼び出して web-test-runner.config.mjs を指定します。コードは以下の通りです。

+/* global process */
+
+import { startTestRunner } from "@web/test-runner"
+import { classifyRun } from "./sauce_labs.mjs"
+
+const argv = ["--config", "web-test-runner.config.mjs", ...process.argv.slice(2)]
+
+startTestRunner({ autoExitProcess: false, argv }).then((runner) => {
+  if (!runner) return
+  process.on("SIGINT", () => runner.stop())
+  process.on("SIGTERM", () => runner.stop())
+  runner.on("stopped", (passed) => {
+    const sessions = Array.from(runner.sessions.all())
+    const { exitStatus, reason } = classifyRun(passed, sessions)
+    if (exitStatus !== 0) console.error(`Action Cable JavaScript tests failed: ${reason}`)
+    process.exit(exitStatus)
+  })
+})

Sauce Labs 連携ロジックactioncable/test/javascript/sauce_labs.mjs に集約され、ランチャー生成と実行結果の分類関数を提供します。主に createSauceLabsLauncherclassifyRun がエクスポートされ、インフラ障害や WebDriver エラーを判別して終了コードを決定します。

+export const SAUCE_INFRASTRUCTURE_EXIT_STATUS = 3
+export function createSauceLabsLauncher(saucelabsOptions, saucelabsCapabilities, sauceConnectOptions) { /* 省略 */ }
+export function classifyRun(passed, sessions) { /* 省略 */ }

Web Test Runner の設定actioncable/web-test-runner.config.mjs に記述され、テスト対象ファイル、タイムアウト、使用フレームワークとして web-test-runner-qunit を指定しています。CI 環境下では Sauce Labs 用ランチャーを組み込み、ローカル実行時はローカルブラウザが利用されます。

+/* global process */
+import { createRequire } from "module"
+import { createSauceLabsLauncher } from "./test/javascript/sauce_labs.mjs"
+const require = createRequire(`${process.cwd()}/web-test-runner.config.mjs`)
+const config = {
+  rootDir: "..",
+  files: "test/javascript/compiled/test.js",
+  nodeResolve: true,
+  browserStartTimeout: 180000,
+  testsStartTimeout: 180000,
+  testsFinishTimeout: 300000,
+  testFramework: { path: require.resolve("web-test-runner-qunit"), config: {} },
+}
+if (process.env.CI) {
+  const sauce = createSauceLabsLauncher({ user: process.env.SAUCE_USERNAME, key: process.env.SAUCE_ACCESS_KEY, region: "us" }, { build: buildId(), name: "ActionCable JS Client" })
+  config.browsers = [
+    sauce({ browserName: "chrome", browserVersion: "98", platformName: "Windows 10", "wdio:enforceWebDriverClassic": true }),
+    sauce({ browserName: "firefox", browserVersion: "94", platformName: "Windows 10", "wdio:enforceWebDriverClassic": true }),
+    // Safari 省略
+  ]
+}
+export default config

以上の変更により、テスト実行フローは KarmaWeb Test Runner へシフトし、npm test の呼び出しだけで同等のテストが走ります。

設計判断

テストランナー全体の置き換えが採用された理由は、メンテナンスが停止したツールに依存し続けるリスクを回避し、同一のテストコードと QUnit フレームワークをそのまま利用できる点にあります。PR の記述は「フレークの根本的な対処はツールチェーンの変更で容易になる」と示唆しており、実装も CI 条件 (process.env.CI) や Sauce Labs 設定を従来と同様に保持しています。

後方互換性package.jsonscripts.test だけを変更し、テスト対象ファイルや QUnit の使用方法は変更していないため、開発者がテストコードを修正する必要はありません。新しい設定ファイルはランナー固有ですが、プロジェクト外部からは影響が見えにくい構造となっています。

トレードオフとしては、@web/test-runner 系列の依存が追加され、設定ファイルの管理コストが増加する点が挙げられます。一方で、公式にメンテナンスが続くツールを採用することで、長期的な保守性と拡張性が向上すると判断されています。

まとめ

Action Cable の JavaScript テストは Karma から Web Test Runner へ移行し、Sauce Labs 連携ロジックを新モジュールに集約しました。テストの振る舞いはそのままで、メンテナンスが停止したツールへの依存を除去し、安定した実行基盤を提供します。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
5651f605

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文があり、背景・技術的変更・設計判断・まとめという各論が整理され、最後に結論が提示されているため構成は適切です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックはファイル名付きシンタックスハイライトが正しく使用され、PRリンクも [#123](URL) 形式で記述されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的なエンジニア向けの記述で、不要な初心者向け解説はなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の流れがあり、段落はトピックセンテンスで始まり1段落1トピックで構成されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供された Diff と内容が一致しており、抜粋でも誤りはありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語は PR と一致し、誤用や不適切な表現はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的説明は PR の背景・目的・実装内容と整合しており、根拠のない主張はありません。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

全ての事実は PR の情報(タイトル、説明、Diff)で裏付けられ、捏造や推測は見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

コード中のバージョン番号やタイムアウト値などは Diff と一致しています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR タイトルの意味を正確に日本語化しており、一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTS、EOL、リリース日程等の外部情報は一切記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PR の記述と合致しています。