smoke-tests について
smoke-tests は、Electron、Web、リモート実行で VS Code のエンドツーエンドのスモークテストを実行・デバッグする方法をまとめています。コントリビューターや CI メンテナー向けに、絞り込み、トレース、シャーディングを説明します。
主な機能
- 01コンパイルあり・なしでのテスト実行
- 02Electron、Web、リモート実行の選択
- 03スイートの絞り込みと Playwright トレース
- 04推定時間に基づくスイート分割
- 05CI ログとスクリーンショットによる調査
活用シーン
- 01指定したエンドツーエンドテストの実行
- 02断続的な CI 障害の調査
- 03失敗実行のトレースとログの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ microsoft/ vscode --skill smoke-testsインストール後、Claude Code で/smoke-testsを入力して読み込まれたか確認します。
詳細
スモークテストの実行
スモークテストは test/smoke/ にあり、エンドツーエンドのユーザーフローを通じて VS Code のインスタンス全体(Electron、Web、またはリモート)を操作します。
スクリプト
npm run smoketest— まずスモークテスト(test/smoke)をコンパイルし、その後実行します。npm run smoketest-no-compile— コンパイル済みのスモークテストを実行します。CI では、明示的なコンパイル手順の後にこれを使用します。
どちらのスクリプトも、-- の後に指定された追加の引数をランナー(test/smoke/test/index.js)に渡します。
よく使うオプション
| オプション | 説明 |
|---|---|
-g <pattern>(エイリアス -f) | テスト名/スイート名に対する grep フィルター(mocha の grep)です。 |
--build <path> | ソースからコンパイルした開発ビルドではなく、パッケージ化されたビルドに対して実行します。 |
--tracing | Playwright のトレースを記録します(失敗時にはスクリーンショットも記録します)。 |
--web | Electron の代わりにブラウザーのスモークテストを実行します。 |
--headless | ヘッドレスブラウザーを使用します(--web と併用)。 |
--remote | リモートのスモークテストを実行します。 |
--shard <index>/<total> | トップレベルのスイートを分割したうちの一つだけを実行します。たとえば、--shard 1/2 のように指定します。スイートは推定所要時間に基づいて各シャードに均等に割り振られます(test/smoke/src/shard.ts を参照)。各スイートは必ず一つのシャードだけで実行されます。 |
# Run everything (Electron, from source)
npm run smoketest
# Run only a subset of suites by name, with tracing (replace <suite name> with your suite, e.g. "Agents Window")
npm run smoketest -- -g "<suite name>" --tracing
# Run against a packaged build (CI style)
npm run smoketest-no-compile -- --tracing --build "/path/to/VSCode-darwin-arm64/Code - OSS.app"
-g パターンはテスト名/スイート名に対して照合されます。たとえば、-g "Agents Window" は3つすべての Agents Window スイート(Agents Window、Agents Window (local AgentHost)、Agents Window (local AgentHost, SDK sandbox))に一致します。対象のスイートを特定できる部分文字列を指定してください。
いずれかのテストが失敗すると、ランナーはゼロ以外の終了コードで終了します。そのため、終了コードが 0 なら、選択したすべてのテストが成功したことを意味します。
PR CI でのシャーディング
GitHub の PR ワークフローでは、Electron スモークテストを複数のシャードに分割しています。.github/workflows/pr-linux-test.yml と pr-darwin-test.yml の electron-smoke-1 および electron-smoke-2 ジョブ、ならびに pr-win32-test.yml の electron-smoke-1 から electron-smoke-3 までのジョブは、最初のシャードで WSL もセットアップし、SMOKE_SHARD_INDEX/SMOKE_SHARD_TOTAL 環境変数を --shard としてランナーに渡します。各ジョブは <OS> / Electron-Smoke (shard 1/2) および <OS> / Electron-Smoke (shard 2/2)、または Windows / Electron-Smoke (shard 1/3) から Windows / Electron-Smoke (shard 3/3) として結果を報告します。Windows では、リモートスモークテストも Windows / Remote (integration) と並行して、独立した Windows / Remote (smoke) ジョブで実行されます。PR Gate ジョブ(pr-gate)は、ワークフロー内のすべてのジョブに対して単一のチェックを報告し、いずれかのシャードが成功しなかった場合は失敗します。プルリクエストでスモークテストが読み取れないパスのみが変更された場合、シャードはスキップされ、ゲートは成功します(.github/actions/detect-changes/detect.ts を参照)。プラットフォームのシャード数を変更するには、そのワークフローで electron-smoke-<index> ジョブを追加または削除し、すべてのジョブの名前と環境変数に含まれるシャード番号を更新します。各シャードの smoke-test-runner.log の先頭付近にある Running smoke test shard <index>/<total> の行には、そのシャードで実行されたスイートが記載されます。
一部の割り当てはワークフローと連動しており、test/smoke/src/shard.ts で定義されています。
- WSL: WSL Dev Container スイートはシャード 1 に固定されており、
pr-win32-test.ymlではシャード 1 のみで WSL をプロビジョニングします。すべてのシャードでVSCODE_SMOKE_TEST_WSL_REQUIREDを設定したままにしてください。これにより、すべてのシャードで同じスイートが登録され、同じ分割が計算されます。Windows では、シャード 1 はvscode-large-runners-windows-8-coreの大規模ランナーではなく、1ES プールで実行されます。GitHub がホストする Windows ランナーでは、WSL2 がディストリビューションをプロビジョニングしている間に断続的にフリーズすることがあり(actions/runner-images#14938)、GitHub がランナーとの通信が途絶えたと報告するまで、チェックが約 45 分間保留状態になります。 - WSL のバージョン: エージェントの Windows Server 2022 イメージに含まれるのは標準搭載の WSL のみであるため、プロビジョニングでは
build/checksums/wsl.txtに固定された WSL リリースをインストールします(build/azure-pipelines/common/wsl.psm1を参照)。バージョンを更新するには、microsoft/WSL releases にある、より新しいwsl.<version>.x64.msiの SHA256 とファイル名をそこに記載します。インストーラーのキャッシュキーはそのファイルを基にしており、pr-node-modules.ymlがmainの GitHub キャッシュを作成します。 - macOS のプロキシ実行: macOS では、PAC プロキシを使用する Agents Window のテストは最後のシャードでのみ実行されるため、バランサーはその実行時間を最後のシャードに割り当てます。
すべてのシャードで同じスイートを登録する必要があります。そうでない場合、スイートがスキップされたり、二重に実行されたりする可能性があります。シャードごとに異なる条件に基づいてスイートを登録しないでください。
実行が完了すると、ランナーは最上位の各スイートの所要時間を、長い順に出力します。アプリの起動(約 20 秒)より大幅に時間がかかるスモークスイートを追加した場合、または出力された所要時間が test/smoke/src/shard.ts の suiteDurations と大きく異なるようになった場合は、シャード間の負荷を均等に保つため、このテーブルを更新してください。
不安定な CI テストを調査するためにスイートを一時的にループ実行する
スモークテストが CI でのみ断続的に失敗する場合は、疑わしいスイートを一時的に連続して何度も実行し、最初の失敗で停止する方法が役立ちます。これにより、関連のない PR で自然に再発するのを待つのではなく、実際の CI 環境で不安定な動作を再現し、そのトレースやスクリーンショットを取得できます。
これはデバッグ用の手段であり、CI に恒久的に追加するものではありません。
- 一時的なブランチに追加してプッシュし、CI を実行します。再現できるまで繰り返し、その後、不安定な動作を修正します。
- マージ前にループを削除してください。残しておくと、実行のたびにプラットフォームごとに約 1 時間追加されます。
- これは特定のスイート専用ではありません。調査対象のスイートに合わせて
-gフィルターを指定してください(以下の例では"Agents Window"を使用していますが、対象に応じて置き換えてください)。
追加する場所
ループは、既存の Electron スモークテストのステップの隣に配置し、同じ条件で実行されるようにします。フレークが再現するプラットフォームのテストステップに追加してください。シャード分割された GitHub PR ワークフローでは、下の例のように単一のシャードでのみ実行される条件も追加し、すべてのシャードで実行されないようにします。
GitHub PR ワークフロー(ソースから実行し、--build は指定しません):
.github/workflows/pr-linux-test.yml(bash。DISPLAY: ":10"を設定).github/workflows/pr-darwin-test.yml(bash。DISPLAYなし).github/workflows/pr-win32-test.yml(PowerShell)
Azure DevOps のテストステップ(--build を指定してパッケージ済みビルドに対して実行):
build/azure-pipelines/linux/steps/product-build-linux-test.ymlbuild/azure-pipelines/darwin/steps/product-build-darwin-test.ymlbuild/azure-pipelines/win32/steps/product-build-win32-test.yml
構成
N 回(例:20 回)ループし、最初に失敗した実行で中断します。余裕のあるタイムアウトを設定してください。約 3 分かかるスイートを N 回連続で実行すると、1 時間ほどかかる場合があります。
Bash(Linux/macOS):
# TEMPORARY: loop the suite to reproduce a flaky failure. Remove before merge.
# Replace <suite name> with the suite you're investigating (e.g. "Agents Window").
- name: 🧪 Smoke test flakiness probe (TEMPORARY)
if: ${{ env.ELECTRON_TESTS == 'true' && env.SMOKE_TESTS == 'true' && env.SMOKE_SHARD_INDEX == '1' }}
timeout-minutes: 60
run: |
for i in $(seq 1 20); do
echo "::group::Smoke probe run $i/20"
npm run smoketest-no-compile -- --tracing -g "<suite name>" || { echo "::error::Smoke test failed on run $i/20"; exit 1; }
echo "::endgroup::"
done
PowerShell(Windows)では各実行後に $LASTEXITCODE を確認し、失敗した場合は exit 1 を実行します。AzDO 版では、フェイルファストのために set -e(bash)/$LASTEXITCODE(pwsh)を使用し、--build "<packaged app path>" を追加します。
フェイルファストにする理由
このループは調査用です。最初の失敗が兆候となります。すぐに停止すれば、失敗した実行のトレースやスクリーンショットを(ログアーティファクト内に)残せます。また、すでにフレークが発生していると分かった実行を終えるために、エージェントの時間を約 1 時間も費やさずに済みます。
CI スモークテストの失敗をデバッグする
どちらの CI システムも、スモークテストランナーのプラットフォーム別ログ(.build/logs ディレクトリ)をダウンロード可能なアーティファクトとして公開します。アーティファクト内の構成はどちらも同じで、異なるのはアーティファクト名とダウンロードツールだけです。
ログアーティファクトのダウンロード
GitHub Actions
GitHub PR ワークフローでは、アーティファクトが logs-<os>-<arch>-<suite>-<attempt> という名前でアップロードされます。<os> は linux/macos/windows、<suite> はジョブを識別する名前(例:electron、browser、remote、または最初の Electron スモークシャードの場合は electron-smoke-shard1)、<attempt> は実行の試行回数です(例:logs-macos-arm64-electron-smoke-shard1-1)。
実行 ID は実行/ジョブの URL に含まれる数値です。…/actions/runs/<run-id>/job/<job-id> の場合は <run-id> を使用します。gh CLI でダウンロードします。
# A specific artifact into ./logs
gh run download <run-id> -n logs-<os>-<arch>-<suite>-<attempt> -D ./logs
# Or every artifact from the run
gh run download <run-id>
gh run view <run-id> を実行すると、実行のジョブ/アーティファクトが一覧表示されます。ブラウザーで実行の概要ページを開き、下部の Artifacts セクションから確認することもできます。
Azure DevOps
アーティファクト名は、生成元のパイプラインによって異なります。
- Product build(
product-build-<os>.yml):logs-<os>-<arch>-<attempt>。suite セグメントはありません。例:logs-macos-arm64-1。 - Suite-split CI build(
product-build-<os>-ci.yml):logs-<os>-<arch>-<suite>-<attempt>。<suite>セグメントはlower(VSCODE_TEST_SUITE)(例:electron)です。そのため、例としてlogs-macos-arm64-electron-1となります(GitHub と同じ形式です)。
<os> は linux/macos/windows、<arch> は x64/arm64、<attempt> は $(System.JobAttempt) です。Azure CLI でダウンロードします。
az pipelines runs artifact download \
--org <ORG_URL> --project <PROJECT_NAME> \
--run-id <BUILD_ID> --artifact-name <artifact-name> \
--path ./logs
VS Code のビルドでは --org https://dev.azure.com/monacotools --project Monaco を指定します。<BUILD_ID> の確認方法については、azure-pipelines スキルを参照してください。
アーティファクトの内容
smoke-tests-<suite>/ の下(実行されたスイートに応じて smoke-tests-electron/、smoke-tests-browser/、または smoke-tests-remote/)には、次のファイルがあります。
smoke-test-runner.log— mocha ドライバーの出力に加え、モック LLM サーバーを使用するスイートでは、リクエスト/レスポンス本文の詳細ログも含まれます(request body:を探してください)。Copilot CLI/Copilot セッションの失敗時には、キャプチャされた Copilot ランタイムログの末尾も記録されます(下記を参照)。<N>_suite_<Suite_Name>/copilot-runtime-logs/process-*.log— Copilot ランタイム(@github/copilotCLI)のプロセスログです。Copilot ランタイムセッションの失敗時に、dumpFailureDiagnosticsがこれを取得します。ハングや「Timed out waiting for response」が発生した場合は、まずこれを確認してください。SDK/CLI が実行した処理(起動、認証、モデルリクエスト、ターンのライフサイクル、パニック/順序が不正なイベント/プロトコルエラー)を記録するため、テストエラーだけでは分からないタイムアウトの原因を説明できます。Agent Host セッション(Agents Window/ローカル AgentHost)では、traceレベルの完全なログが出力されます(chat.agentHost.copilotSdk.logLevel)。Chat Sessions エディター(Copilot CLI/Claude)と Local セッションでは、SDK はプロセス内で実行され、ここには最小限の起動ログ(Server started, waiting for requests)だけが記録されます。これはランタイムが起動したかどうかを確認するのに十分です。モデルやターンに関する詳細な診断情報は、下記のGitHub Copilot Chat.logにあります。(Claude/Codex セッションでは別のランタイムを使用するため、ここには記録されません。)<N>_suite_<Suite_Name>/window2/exthost/<extension>/…log— スイートごとの拡張機能ホストログです(例:GitHub.copilot-chat/GitHub Copilot Chat.log)。診断ログの多くは、スイートがbeforeフックで有効にする設定に左右されます。想定されるログ行が見つからない場合は、スイートのセットアップを確認してください。<N>_suite_<Suite_Name>/playwright-screenshot-*.png— テスト失敗時に取得された最終フレームのスクリーンショットです(スイートを--tracing付きで実行した場合のみ)。
<Suite_Name> は、単語以外の文字を _ に置き換えた mocha スイートのタイトルです。code-oss-logs スキルも参照してください。
他のテスト種別との違い
- ユニットテスト(
.test.ts)→scripts/test.sh/runTestsツール(unit-testsスキルを参照)。 - 統合テスト(
.integrationTest.tsおよび拡張機能テスト)→scripts/test-integration.sh(integration-testsスキルを参照)。 - スモークテスト(
test/smoke/)→npm run smoketest— UI のエンドツーエンドフロー全体。