关于 validate-ui-scenario
validate-ui-scenario 是针对具体问题,在真实 VS Code 实例中运行一次性验证的技能。它记录各步骤,并生成报告、截图、追踪记录和带字幕的视频,作为可复现证据。
主要功能
- 01用 JavaScript 场景驱动 VS Code
- 02运行已安装、开发版、指定版或 Web 版本
- 03录制视频、追踪记录和步骤截图
- 04生成逐步 HTML 报告
- 05标记需人工处理或受基础设施限制的步骤
适用场景
- 01复现已报告的 VS Code 缺陷
- 02在开发版中验证尚未合并的更改
- 03为测试计划条目附上录制证据
MCP 相关
相关的 `test/mcp` 项目通过 MCP 暴露 UI 检查工具,名称为 `vscode_automation_*`。可将其配置为 MCP 服务,工作目录设为 `test/mcp`,并运行 `npm run start-stdio`。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ vscode --skill validate-ui-scenario安装后在 Claude Code 中输入/validate-ui-scenario确认已加载。
详细介绍
验证 UI 场景
通过真实的 VS Code 实例运行场景,并记录可复现的证据。
可用此方法复现已报告的 Bug、展示修复有效,或为测试计划项目附上录屏。对于每次构建都会运行的确定性回归测试,请编写冒烟测试(参见 smoke-tests 技能)——此技能用于一次性的、源自问题的验证。
场景是一个由 test/scenario/out/runScenario.js 运行的小型 JavaScript 文件。无需进行其他配置:运行器会启动 VS Code、录制视频和跟踪记录、在每个步骤边界截取屏幕截图、生成报告,并为录屏添加每个步骤及其结果的说明。
准备
npm install # once
npm --prefix test/scenario run compile # after any change under test/scenario
运行前请确认 ffmpeg 和 ffprobe 可用。 运行器会在 PATH 和常见安装位置中查找它们,因此即使在编辑器启动后安装 ffmpeg,也能找到。没有它们时,场景仍会运行并保留原始录屏,但视频不会添加步骤标题说明。运行器会在启动时发出警告;如果缺少这些工具,请告知用户如何安装,而不要悄悄返回没有注释的视频:
| 平台 | 安装 |
|---|---|
| Windows | winget install Gyan.FFmpeg |
| macOS | brew install ffmpeg |
| Linux | sudo apt install ffmpeg |
可能需要打开一个新终端,让 PATH 识别这些工具;也可以设置 FFMPEG_PATH 和 FFPROBE_PATH。之后还可使用 node test/scenario/out/renderEvidenceChapters.js <run-dir> 为已有运行结果添加注释。
| 目标 | 标志 | 另外需要 | 用途 |
|---|---|---|---|
| 已安装的 Insiders,否则为 Stable | (none — the default) | 无 | 根据已发布的行为复现报告 |
| 此代码库中的开发构建 | --dev | 匹配的 Electron 运行时、npm run build-fast | 验证尚未合并的更改 |
| 指定的安装 | --build <app-root> | 无 | 固定使用某个确切构建 |
| Web | --web --headless | npm run build-fast -- --client-only | 仅限浏览器的行为 |
如果存在匹配的 Electron 运行时,请重复使用;仅当运行时缺失或不兼容时,才运行 npm run electron。快速构建会刷新输出,但不会进行类型检查;必要时请单独验证类型。
如果没有指定目标标志,运行器会查找已安装的 VS Code Insiders(若找不到,则使用 Stable),并记录所选版本。--build 接受应用根目录——Windows 和 Linux 上的安装目录,或 macOS 上的 .app 捆绑包:
# Windows
--build "C:/Users/<you>/AppData/Local/Programs/Microsoft VS Code Insiders"
# macOS
--build "/Applications/Visual Studio Code - Insiders.app"
每个目标都会使用各自的用户配置文件和扩展目录,因此你的扩展和设置不会泄漏到录屏中;窗口大小也会调整为与录制画布一致,确保录制画面没有空白边缘。证据会记录实际运行构建的质量版本(Insiders、Stable、Dev),因此报告始终会注明验证的产品。已安装的构建只能复现已发布的行为——要验证尚未合并的更改,请在包含该更改的代码库中使用 --dev。
编写场景
将文件保存在其生成的运行记录旁边,例如 .build/vscode-playwright-mcp/<issue>.cjs。.cjs 扩展名很重要:此软件包是 ES 模块软件包,因此名为 .js 的 CommonJS 场景会加载失败。使用默认导出的 ES 模块场景也可以。
const os = require('os');
const path = require('path');
const fs = require('fs');
const workspacePath = path.join(os.tmpdir(), 'issue-250159-workspace');
fs.mkdirSync(workspacePath, { recursive: true });
// The settings tree is virtualized, so only the rows near the viewport exist in
// the DOM. Scroll the whole list, otherwise "the setting is absent" cannot be
// told apart from "the setting is below the fold".
const COLLECT_TITLES = `(async () => {
const editor = document.querySelector('.settings-editor');
const scrollable = editor.querySelector('.settings-tree-container .monaco-scrollable-element');
const titles = new Set();
const collect = () => editor.querySelectorAll('.setting-item-label')
.forEach(node => titles.add(node.textContent.trim()));
collect();
for (let previous = -1; scrollable && scrollable.scrollTop !== previous;) {
previous = scrollable.scrollTop;
scrollable.scrollTop = previous + scrollable.clientHeight;
await new Promise(resolve => setTimeout(resolve, 180));
collect();
}
return [...titles];
})()`;
module.exports = {
id: 'vscode-250159-settings-search',
title: 'Settings search matches across title and description',
source: 'https://github.com/microsoft/vscode/issues/250159',
workspacePath,
steps: [
{
id: 'SS-01',
title: 'Open the Settings editor',
async run(context) {
await context.workbench.quickaccess.runCommand('workbench.action.openSettings2');
await context.page.waitForSelector('.settings-editor', { state: 'visible', timeout: 20000 });
return 'The Settings editor is visible.';
}
},
{
id: 'SS-02',
title: 'Search across title and description',
async run(context) {
await context.workbench.settingsEditor.searchSettingsUI('chat confirm');
const titles = await context.page.evaluate(COLLECT_TITLES);
if (!titles.some(title => /max\s*requests/iu.test(title))) {
throw new Error(`Max Requests is absent. Found: ${titles.join(', ')}`);
}
return 'Max Requests is present in the results.';
}
}
]
};
| 字段 | 含义 |
|---|---|
id、title | 标识运行记录;id 用于命名证据目录 |
source | 场景所依据的问题或测试计划条目 |
workspacePath | 要打开的临时文件夹 |
userSettings | 启动前写入配置文件的设置;使用 --agents 时包括内置 Agents 配置文件 |
extraArgs | 额外的 VS Code 命令行参数 |
extraEnv | 为启动的应用设置的环境变量覆盖项;undefined 会取消设置变量。保持自动化运行器的 HOME 不变,并通过此字段隔离应用发现过程。 |
stepPauseMs | 每个步骤完成后暂停多久,以便看清其说明文字。默认为 1000;场景对时序敏感时设为 0 |
每个步骤都会收到一个包含 app、workbench、code、page 和 skip(reason, options) 的 context。workbench 提供功能辅助工具(settingsEditor、quickaccess、editors、terminal、chat 等);对于这些辅助工具未覆盖的操作,可使用 page,它是 Playwright 页面。
对于响应式布局场景,请使用 context.code.driver.resizeWindow({ width, height })。它会调整当前原生 Electron 窗口的大小(在 Web 上则调整浏览器视口),并返回先前的尺寸以供还原。
- 返回一个字符串,说明该步骤如何通过验证。该字符串会显示在报告中。
- 抛出异常以使步骤失败。异常消息会被记录,运行也会停止。
- 当步骤无法自动验证时,调用
skip(reason, { needs })。运行会停止,结果会报告为aborted,而不是通过。
无法自动化的步骤
在规划阶段、编写场景之前就做出判断,并为每个步骤分类——这两种类型的后果不同:
needs | 含义 | 操作 |
|---|---|---|
human | 需要人员参与:实体硬件、主观判断、无法编写脚本完成的登录 | 报告该步骤,以便有人手动检查 |
infrastructure | 原则上可以自动化,但当前测试框架尚无法做到 | 将其报告为这项技能的增强项,并指出缺少的能力 |
ctx.skip('Comparing physical print output requires a person with a printer.', { needs: 'human' });
ctx.skip('The harness cannot drive native OS file dialogs.', { needs: 'infrastructure' });
被阻止的步骤会记录在 manifest.json 中,在 report.html 的 Needs attention 部分突出显示,在视频说明文字上标记为(SKIPPED - NEEDS HUMAN),并在运行结束时打印出来。在摘要中明确列出这些步骤——绝不要悄悄省略无法执行的步骤,也绝不要弱化断言来让它通过。
运行
node test/scenario/out/runScenario.js <scenario.cjs>
退出码 0 表示所有步骤均通过,1 表示运行失败或已中止,2 表示用法错误。
证据会写入 .build/vscode-playwright-mcp/evidence/<run-id>/:
| 文件 | 内容 |
|---|---|
report.html | 步骤表、结果、嵌入的视频 |
manifest.json | 步骤时间戳、状态、产物路径、环境 |
videos/annotated.mp4 | 带有说明文字栏的录制视频,显示每个步骤及其验证结果 |
videos/*.webm | 原始录制视频 |
*.png | 每个步骤的屏幕截图 |
logs/ | Playwright 跟踪记录、窗口日志和服务日志 |
说明文字栏会添加在录制画面的上方,而不是覆盖在画面上,因此不会遮挡任何录制像素,录制时长也保持不变。每条说明文字都包含步骤编号和 id、步骤状态、步骤标题,以及该步骤报告的验证详情。编辑清单后,使用 node test/scenario/out/renderEvidenceChapters.js <run-dir> 重新渲染。
什么样的证据值得信赖
- 对 DOM 状态、无障碍性、焦点或文本进行断言——截图可以佐证一项声明,但不能证明它成立。
- 通过独立于操作的信号进行验证。自动化调用成功返回,并不代表操作取得了预期结果。
- 注意虚拟化列表。设置树和长列表只会渲染视口附近的行,因此在断定某项内容不存在前,请滚动整个列表。
- 如果问题由竞争条件导致,请明确展示时序——使用强制延迟或重复循环——让录制内容呈现问题发生的时间窗口,而不是寄希望于运气。
- 尽可能在修复前记录失败行为。仅有一次通过的运行,无法证明该场景原本能够捕获这个问题。
汇报结果
总结结果,列出失败或跳过的步骤,链接到 report.html,并说明操作系统、VS Code 版本和质量级别(两者都在 manifest.json 中),以及源问题。将视频拖到评论框中,附加到问题或拉取请求。
除通过/失败结果外,务必分别指出:
- 需要人工参与的步骤,让人知道还有哪些内容尚未验证;
- 因缺少测试框架能力而受阻的步骤,将其明确描述为对本技能的一项具体增强;
- 任何降低证据质量的情况,例如缺少 ffmpeg 导致视频没有字幕。
相关内容
- 交互式探索。
test/mcp也会通过 MCP 提供这些工具(vscode_automation_*),便于你在还不知道要断言什么时检查 UI。将其配置为 MCP 服务,设置cwd为test/mcp,命令为npm run start-stdio。 - 拉取请求上的自动验证。
microsoft/vscode-engineering会在 CI 中运行相同的测试框架:为拉取请求添加~requires-ui-validation标签后,它会研究这项更改,针对确切的合并候选版本运行一个场景,并发布带字幕视频的逐步结果。如果某个场景尚未覆盖,或者你想在提出方案前先在本地迭代,请使用此技能。
- 确认
ffmpeg/ffprobe可用;如果不可用,请在运行前说明,并提供安装命令,避免用户看到没有步骤标题的视频时感到意外。 - 阅读问题并找出可观察的声明:在“设置”编辑器中搜索
chat confirm,应匹配 Max Requests,其描述中提到了确认。 - 添加一个基线步骤(
max requests能找到该设置),这样就不能将失败归因于构建中缺少该设置。 - 编写
.build/vscode-playwright-mcp/issue-250159.cjs并在不带目标标志的情况下运行它,这会使用已安装的 Insiders;读取打印出的报告路径。 - 按步骤汇报结果,链接到
report.html,并附加videos/annotated.mp4。
运行在搜索步骤失败,这就是结果:该问题可以复现。应将其报告为成功复现,而不是场景出错。