关于 smoke-tests
smoke-tests 说明如何在 Electron、Web 和远程运行模式下执行及调试 VS Code 端到端冒烟测试,面向贡献者和 CI 维护者,涵盖筛选、追踪与分片。
主要功能
- 01编译后或直接运行冒烟测试
- 02选择 Electron、Web 或远程模式
- 03筛选套件并启用 Playwright 追踪
- 04按预计耗时拆分测试套件
- 05利用 CI 日志和截图排查失败
适用场景
- 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) | 按测试/套件标题筛选(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" 会匹配全部三个 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 (smoke) 作业中运行,与 Windows / Remote (integration) 并列。PR Gate 作业(pr-gate)会为工作流中的每个作业报告一个检查项,并在任何分片未成功时失败。如果 PR 仅修改烟雾测试无法读取的路径(参见 .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 使用 1ES 池,而不是较大型的vscode-large-runners-windows-8-core运行器:在 WSL2 配置发行版时,GitHub 托管的 Windows 运行器偶尔会冻结(actions/runner-images#14938),导致检查项待处理约 45 分钟,直到 GitHub 报告与运行器失去通信。 - WSL 版本: Agent 使用的 Windows Server 2022 映像仅包含内置 WSL,因此配置时会安装固定在
build/checksums/wsl.txt中的 WSL 版本(参见build/azure-pipelines/common/wsl.psm1)。要更新版本,请将较新版wsl.<version>.x64.msi的 SHA256 和文件名填入此处;较新版本可从 microsoft/WSL releases 获取。安装程序会按该文件缓存;pr-node-modules.yml会在main上填充 GitHub 缓存。 - macOS 代理运行: 在 macOS 上,PAC 代理的 Agents Window 测试仅在最后一个分片中运行,因此负载均衡器会在该分片中为其预留时间。
每个分片都必须注册相同的测试套件,否则某些套件可能被跳过或运行两次。不要让测试套件的注册依赖于各分片之间不同的任何因素。
运行结束时,运行器会按耗时从长到短打印每个顶层测试套件的耗时。添加的烟雾测试套件如果比启动应用的时间(约 20 秒)长得多,或者打印的耗时与 test/smoke/src/shard.ts 中的 suiteDurations 不符,请更新该表,以保持各分片负载均衡。
暂时循环运行测试套件,以排查 CI 中的不稳定测试
当烟雾测试仅在 CI 中间歇性失败时,一种实用方法是暂时连续多次运行可疑的测试套件,并在首次失败时停止。这样可以在真实 CI 环境中复现不稳定问题并捕获跟踪记录和屏幕截图,而不必等待它在无关 PR 中自然再次出现。
这是一种调试辅助方法,不是永久性的 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 次),首次运行失败时立即中止。设置充足的超时时间——连续运行 N 次每次约 3 分钟的测试套件,大约需要一小时。
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>"。
为何快速失败
该循环用于探测:首次失败就是信号。立即停止可以保留失败运行的跟踪记录/屏幕截图(位于 logs 构建产物中),并避免浪费约一小时的 Agent 时间,去完成一个已经证实存在间歇性故障的运行。
调试 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-<os>.yml):logs-<os>-<arch>-<attempt>——不包含套件字段,例如logs-macos-arm64-1。 - 拆分套件的 CI 构建(
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;查阅 azure-pipelines 技能以了解如何查找 <BUILD_ID>。
产物内容
在 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 自身的操作情况(启动、身份验证、模型请求、轮次生命周期,以及任何 panic / 乱序事件 / 协议错误),能解释仅凭测试错误无法说明的超时情况。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 流程。