PowerToys Advanced Paste UI 测试全指南:从手工验收清单到自动化用例实现
Advanced Paste 是 Microsoft PowerToys 中负责「增强粘贴」的模块:它不仅能剥离富文本格式,还能把剪贴板内容即时转换为纯文本、Markdown 与 JSON,并通过 AI 完成自定义格式转换。本文以仓库中的 UI 测试清单文档为核心,完整梳理该模块的验收路径、快捷键约定、测试数据与验证思路,并对照自动化用例代码讲清每条用例在底层是如何被校验的,供测试工程师、贡献者与模块开发者直接复用。
测试范围与前置条件
本文对应的测试清单位于 UITestAdvancedPaste.md,其验收对象集中在以下五条主线:
- Paste As Plain Text:去格式化粘贴,验证格式化信息不会残留;
- Paste As Markdown:把 HTML 等文本转成 Markdown 后粘贴;
- Paste As JSON:把 XML/CSV 等文本转成简单 JSON 对象后粘贴;
- Paste with AI(自定义格式):借助 AI 完成用户自定义的文本变换;
- Clipboard History(剪贴板历史):与系统剪贴板历史(
Win+V)的联动; - 模块禁用:关闭 Advanced Paste 后所有热键应不再生效。
清单还特别注明了一条通用前提(NOTES):使用 Advanced Paste 时,触发/粘贴过程中获得焦点的窗口必须是文本编辑器或具备文本输入框的窗口(例如 Word)。这是因为粘贴动作依赖目标窗口接收焦点并响应合成按键,若焦点在资源管理器或浏览器地址栏以外的非文本区域,用例会因环境问题而非功能缺陷失败。自动化测试同样遵守这一约束——代码中统一用 WordPad(RTF)与 Notepad(文本)作为宿主编辑器。
快捷键约定:手工测试与自动化共用一套按键
清单描述中频繁出现的「activation shortcut」「打开 Advanced Paste 窗口的热键」「Ctrl + 1/2/3」分别指两类快捷键:全局热键与窗口内快捷键。
模块的按键配置集中保存在 PowerToys 的设置(Advanced Paste 对应的 settings.json)。仓库中测试专用的预设文件 settings.json 明确给出了自动化测试运行的按键前提,测试类静态构造函数中的注释也复述了同一组按键:
| 动作 | 全局热键 | 说明 |
|---|---|---|
| 打开 Advanced Paste 主窗口 | Win + Shift + V |
由 advanced-paste-ui-hotkey 定义(win+shift+true, code 86 = V) |
| 直接粘贴为纯文本 | Win + Ctrl + Alt + O |
paste-as-plain-hotkey,测试注释 "paste as plain text" |
| 直接粘贴为 Markdown | Win + Ctrl + Alt + M |
paste-as-markdown-hotkey |
| 直接粘贴为 JSON | Win + Ctrl + Alt + J |
paste-as-json-hotkey |
打开主窗口后,还可以不点按钮而直接用窗口内快捷键触发粘贴:Ctrl + 1 对应 Paste as Plain Text、Ctrl + 2 对应 Paste as Markdown、Ctrl + 3 对应 Paste as JSON。主窗口内各粘贴格式的可视按钮(Paste as plain text、Paste as markdown、Paste as JSON、Clipboard history 等)在自动化中通过 UI Automation 按文本定位,见 AdvancedPasteUITest.cs。
说明:同一组热键既被手工测试执行者遵循,也被自动化用例直接发送(
SendKeys(Key.Win, Key.LCtrl, Key.Alt, Key.O)等),因此手工验收与自动化验收的触发路径完全一致。
用例组一:Paste As Plain Text(去格式化粘贴)
这一组用例验证的是 Advanced Paste 最核心的能力——丢弃一切富文本样式,仅保留字符。清单设计了四种触发姿势,全部围绕「先有富文本,再验证去格式」展开:
- 基线对照:复制一段带有样式差异的富文本(如某个词颜色不同、另一些词加粗或下划线),先用系统标准
Ctrl + V粘贴,确认带完整样式(颜色、加粗等)的富文本被原样粘出; - 直接热键去格式:复制富文本,按 Paste As Plain Text 激活快捷键粘贴,确认粘出的内容无任何格式;紧接着再按一次系统
Ctrl + V,确认这次粘出的仍然是纯文本、而非恢复带样式的原始内容——即去格式结果已替换了剪贴板里的富文本数据; - 窗口按钮路径:再次复制富文本,用热键
Win + Shift + V打开 Advanced Paste 窗口,点击Paste as Plain Text按钮,确认粘贴为无格式纯文本; - 窗口内快捷键路径:再次复制富文本,打开 Advanced Paste 窗口后按
Ctrl + 1,确认粘贴为无格式纯文本。
对照自动化实现(AdvancedPasteUITest.cs 的 TestCasePasteAsPlainText),可以看出该用例如何被自动校验:测试先把预设的富文本样本 PasteAsPlainTextFileRaw.rtf 复制为临时文件交给 WordPad 打开,全选复制后清空编辑区,再依次走上述四种路径完成粘贴并 Ctrl+S 保存,最后用 FileReader.CompareRtfFiles 做逐字符比对。
比对的关键点在于 compareFormatting 参数:
- 第一种路径(基线对照)以
compareFormatting: true与原样本PasteAsPlainTextFileRaw.rtf比较,要求 RTF 原始内容(含全部格式码)完全一致; - 后三种去格式路径则以
compareFormatting: false与PasteAsPlainTextFilePlain.rtf(首次去格式)或PasteAsPlainTextFilePlainNoRepeat.rtf(窗口按钮/快捷键路径)比较,此时只比较 RichTextBox 解析出的纯文本,从而把「是否丢失格式」这一断言收敛为文件内容等价。
工程提示:RTF 文件的「格式保留」无法用字符串直觉判断,
FileReader.CompareRtfFiles用两种比较模式把它拆成了可自动判定的问题——compareFormatting=true比原始 RTF 语法(格式仍在),compareFormatting=false通过RichTextBox.Rtf载入后取.Text比纯文本(格式已被剥离)。该测试因 CI 管道缺少 wordpad.exe 而暂被[Ignore]标记,本地具备 WordPad 的 Windows 环境可重新启用。
用例组二:Paste As Markdown(HTML 转 Markdown 粘贴)
清单要求先进入设置页为「Paste as Markdown」配置直接粘贴热键(即上文表中的 Win + Ctrl + Alt + M),随后同样覆盖三条验证路径:
- 复制一段可转换为 Markdown 的文本(例如 HTML),按设置好的热键直接粘贴,确认内容已被转换为 Markdown 语法;
- 再次复制文本后,用
Win + Shift + V打开窗口、点击Paste as markdown按钮,确认转换为 Markdown 后粘贴; - 再次复制文本后,打开窗口按
Ctrl + 2,确认转换为 Markdown。
清单特别标注了一个在复制间隔可能发生的边界行为:如果在两步之间没有复制新内容,之前已粘贴的 Markdown 文本会被再次从剪贴板拾取并二次转换(产生嵌套 Markdown)。也就是说,用例之间必须携带新的复制动作,否则上一轮的结果文本会变成下一轮的输入源,导致验证的不是预期样本——自动化实现严格按「每步先复制源文件内容再执行触发动作」的顺序规避了该陷阱。
对应自动化用例为 TestCasePasteAsMarkdownCase1/2/3(AdvancedPasteUITest.cs),三个 Case 分别执行热键直接粘贴、窗口按钮粘贴、Ctrl+2 窗口内快捷键粘贴,源样本为 PasteAsMarkdownFile.html,期望输出是 PasteAsMarkdownResultFile.txt(内容形如 ## The title Attribute 之类的 Markdown 标题结构),保存后与期望文件做内容一致断言。运行这些用例前,自动化还会先通过 ChangeNotePadSettings 调整记事本「打开文件」行为为独立新窗口,确保窗口定位稳定。
用例组三:Paste As JSON(XML/CSV 转 JSON 粘贴)
JSON 组与 Markdown 组结构完全对称,前置条件同样是先在设置中为「Paste as JSON」配好直接热键(Win + Ctrl + Alt + J),源数据建议使用 XML 或 CSV 文本(其他任意文本也会被转换成简单的 JSON 对象):
- 复制 XML/CSV 文本,按热键直接粘贴,确认转换为 JSON;
- 复制文本 → 打开窗口 → 点击
Paste as JSON按钮,确认转换; - 复制文本 → 打开窗口 → 按
Ctrl + 3,确认转换。
自动化侧对应 TestCasePasteAsJSONCase1/2/3(AdvancedPasteUITest.cs),输入样本为 PasteAsJsonFile.xml,期望结果保存在 PasteAsJsonResultFile.txt。
核对清单时请留意:原清单在 Paste As JSON 组的 Case 2/Case 3 描述中把按钮与结果误写作了 "Paste as markdown",这是从 Markdown 组复制模板时遗留的笔误。以自动化用例的实际操作为准——Case 2 点击的是窗口中的
Paste as JSON文本块(apWind.Find<TextBlock>("Paste as JSON").Click()),Case 3 发送的是Ctrl + Num3,断言均与PasteAsJsonResultFile.txt比较。
用例组四:Paste with AI(自定义格式)
这是清单中唯一依赖云端/本地 AI 服务的一组,全部用例仍为待执行(未勾选)状态,说明其更依赖真实服务的可用性。执行前提依次为:
- 打开设置,启用 Enable Paste with AI 并配置 OpenAI Key;
- 复制任意文本到剪贴板。
随后按以下步骤验收:
- 自定义指令生效:打开 Advanced Paste 窗口,确认 Custom input(自定义输入框)已变为可用;输入指令(例如 "Insert smiley after every word")并按 Enter,观察结果预览区是否按指令在单词之间插入笑脸;再按 Enter 将结果粘贴,确认粘贴内容与预览一致;
- 重新生成与多结果选择:输入任意查询并按 Enter,得到结果后点击 regenerate 按钮确认能生成新结果,从多个结果中选择一个粘贴,确认粘出的是所选结果;
- 自定义动作(Custom Actions):创建若干自定义动作并为其配置热键,确认可用;启用/禁用自定义动作后回到 Advanced Paste 窗口,确认被禁用的动作不再出现在列表中;尝试用不同
Ctrl + <数字>窗口内快捷键触发不同自定义动作;上下移动自定义动作顺序,确认 UI 中顺序同步变化; - 关闭结果预览:在设置中关闭 Custom format preview(对应
ShowCustomPreview),打开窗口输入查询并回车,观察结果是否跳过预览直接粘贴; - 关闭 AI 开关:在设置中禁用 Enable Paste with AI,打开窗口确认 Custom input 输入框随之变为禁用态。
底层行为与源码的对应关系值得展开:设置项 ShowCustomPreview 与 IsAIEnabled(测试配置中分别置为 true 与 false,见 settings.json)。开发者文档 doc/devdocs/modules/advancedpaste.md 明确指出:预览不会额外消耗 AI 配额——AI 调用只发生一次,结果缓存在 GeneratedResponses 中,预览只是展示同一次已生成并本地缓存的回答,粘贴时不再发起新的 API 请求。因此「关闭预览后结果直接粘贴」验收点实质上验证的是缓存命中与 UI 流程分支(先预览再粘贴 vs. 直接粘贴)的切换,而不是二次计费行为。
枚举定义 PasteFormats.cs 把「哪些动作需要 AI、哪些支持预览」显式建模为元数据:如 CustomTextTransformation 标注 RequiresAIService = true、CanPreview = true、RequiresPrompt = true 且支持 Text/Image 剪贴板格式;而三大核心动作 PlainText / Markdown / Json 均为 IsCoreAction = true、RequiresAIService = false、CanPreview = false——这正好解释了测试中「三大核心动作不存在预览」「AI 动作才有预览与 regenerate」的现象差异,也解释了为什么在 AI 未配置时只有核心三动作与本地能力(OCR、另存为文件、转码)可用。
用例组五:Clipboard History(与系统剪贴板历史联动)
Advanced Paste 窗口内置剪贴板历史入口,清单验证它必须与**系统剪贴板历史(Win+V 弹窗,自动化中定位为 "Windows Input Experience" 窗口)**保持数据一致:
- 删除同步:先在设置中启用 Clipboard history,打开 Advanced Paste 窗口点击
Clipboard history,删除其中某一条;随后按Win+V打开系统剪贴板历史,确认同一条目已不存在; - 置顶行为:打开 Advanced Paste 的剪贴板历史并点击某一条(非首条)条目,观察该条目被提到历史顶部;再按
Win+V,确认系统剪贴板历史中同一内容也处于顶部位置; - 开关联动:在设置中关闭 Clipboard history,重新打开 Advanced Paste 窗口,确认
Clipboard history按钮处于禁用状态(点击后不再展开任何历史条目)。
自动化实现(TestCaseClipboardHistoryDeleteTest/SelectTest/DisableTest,见 AdvancedPasteUITest.cs)给出了三个值得复用的关键手法:
- 预置剪贴板内容:通过
SetClipboardTextInSTAMode在 STA 线程上用System.Windows.Forms.Clipboard.SetText写入测试文本(Windows 剪贴板为 COM 对象,跨线程操作必须走 STA,否则会抛ThreadStateException); - 删除用例的自证闭环:删除后打开系统剪贴板历史,断言窗口出现 "Nothing here, You'll see your clipboard history here once you've copied something." 的占位文案,从而用系统 UI 状态证明条目确实被删除;
- 禁用态断言:对已禁用的
Clipboard history按钮执行点击后,用短超时断言窗口内不再出现对应剪贴板内容的Group元素,避免因元素不存在而长时间空等。
用例组六:禁用模块后的热键失效验证
最后一个通用验收点覆盖了模块开关的降级路径:在设置中关闭 Advanced Paste,然后逐一尝试各条 Advanced Paste 热键,确认模块被禁用、热键触发后不发生任何反应(窗口不弹出、粘贴不执行)。
自动化用例 TestCaseDisableAdvancedPaste(AdvancedPasteUITest.cs)把该逻辑固化为两条断言:
- 先向剪贴板写入测试文本,发送主热键
Win + Shift + V后断言全局搜索不到 "Advanced Paste" 窗口(Has<Window>("Advanced Paste", global: true)为假); - 测试结束前会重新在设置中打开模块开关并把状态恢复,避免影响后续用例。
这也提示了该清单的定位:它同时是一份模块可用性回归清单——UI 测试不仅验证功能正确性,也验证「功能关闭后不能产生副作用」这一可访问性与用户预期层面的属性。
测试资产与工程组织
整组 UI 测试围绕固定目录组织,便于复用与扩展:
- 测试工程 AdvancedPaste-UITests.csproj:引用
UITestAutomation公共测试框架,依赖Appium.WebDriver与MSTest;测试程序集输出到<RepoRoot>\<Platform>\<Configuration>\tests\UITests-AdvancedPaste\,并把整个TestFiles\**作为内容拷贝到输出目录(CopyToOutputDirectory=PreserveNewest); - 测试样本目录
TestFiles/(查看全部样本):每种粘贴格式都配了「输入样本 + 期望结果」对:- RTF 三件套:
PasteAsPlainTextFileRaw.rtf(原始富文本)、PasteAsPlainTextFilePlain.rtf(首次去格式后)、PasteAsPlainTextFilePlainNoRepeat.rtf(窗口触发去格式后); - Markdown 对:
PasteAsMarkdownFile.html→PasteAsMarkdownResultFile.txt; - JSON 对:
PasteAsJsonFile.xml→PasteAsJsonResultFile.txt; - 预设配置
settings.json:统一了全部热键与开关状态(默认IsAIEnabled=false、ShowCustomPreview=true、ShowAIPaste=true);
- RTF 三件套:
- 测试执行类 AdvancedPasteUITest.cs:所有用例继承
UITestBase,静态构造函数中把预设settings.json复制到%LOCALAPPDATA%\Microsoft\PowerToys\AdvancedPaste\settings.json,实现「测试前重置模块配置」的幂等性; - 文件断言助手 FileReader.cs:提供按格式比对(RTF 原始码)与按纯文本比对两种模式。
关于清单与自动化的分工,可以总结为一条经验:清单中任何「复制富文本 → 触发 → 保存 → 对比」的步骤,都能在测试类里找到同名同语义的自动化方法(ContentCopyAndPasteDirectly、ContentCopyAndPasteWithShortcutThenPasteAgain、ContentCopyAndPasteCase3/4、ContentCopyAndPasteAsMarkdownCase1/2/3、ContentCopyAndPasteAsJsonCase1/2/3),手工执行者照清单操作即可,而自动化把同样的路径固化为可回归的断言。新增粘贴格式或调整 UI 文案时,这两份资产需要同步维护——例如窗口按钮的定位名(Paste as plain text、Paste as markdown、Paste as JSON、Clipboard history)与多语言资源字符串要保持一致,否则自动化会因找不到元素而失败。
进阶指引
- 想了解各粘贴动作的元数据(是否核心动作、是否需要 AI、是否支持预览、支持的剪贴板格式),见 PasteFormats.cs 与 PasteFormat.cs(后者的
IsEnabled = SupportsClipboardFormats(...) && (isAIServiceEnabled || !RequiresAIService)解释了为何未配置 AI 时 AI 动作不可用); - Advanced Paste 的调试、稀疏包(sparse package)身份与 Phi Silica 本地运行细节,见 doc/devdocs/modules/advancedpaste.md 与 Phi Silica 本地测试指南;
- 模块主界面与交互逻辑源码位于 src/modules/AdvancedPaste/AdvancedPaste(
ViewModels/OptionsViewModel.cs是 AI 预览缓存与粘贴执行的核心),完整源码树见 src/modules/AdvancedPaste。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00