MooTool Next-Compose 实战:JSONPath 选择弹层 `JsonPathPickerDialog` 的提取与「使用」交互单测
桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载导读本文围绕 MooTool 下一代跨平台版本next-compose中 JSON 工具模块的JsonPathPickerDialog弹层重构展开为兼顾可测试性与「使用此路径」仅选路径、不自动查询的交互语义DIFF-319项目将原本内联在JsonScreen中的路径选择对话框提取为独立 Compose 组件并通过语义化contentDescription、会话状态封装与桌面 Compose UI 测试把「使用」与「双击选路径」两条行为链路固化为可回归的自动化用例。读完本文你将掌握该组件从提取、状态驱动、无障碍对齐到交互单测与场景帧证据的完整实现思路可直接迁移到自身 Compose 桌面项目的弹层测试与行为封装中。一、背景为什么要把PathPickerDialog从JsonScreen中提取出来在重构之前JSONPath 选择弹层PathPickerDialog是直接内联在JsonScreen里的。随着功能演进它暴露出两个问题体量过大不利于单测弹层既承担路径列表加载、选中态维护又要处理预览与确认/取消逻辑内联在 2200 行的JsonScreen中见 JsonScreen.kt很难被 Compose 测试独立挂载和驱动交互语义需要回归保护Electron 版JsonPathPicker的「使用」与双击共用onChoose(path)——只把路径写入输入框并关闭弹层不触发 JSONPath 查询、不把节点预览写进结果区。Compose 端若在此处行为漂移会导致 DIFF-319「仅选路径、不自动查询」的回归。因此 DIFF-457 的核心动作是把弹层提取为独立组件让回归验证落到可重复执行的单测上。二、组件提取JsonPathPickerDialog的结构与状态驱动2.1 新增独立组件文件新增 JsonPathPickerDialog.kt对外暴露一个internal的 ComposableComposable internal fun JsonPathPickerDialog(container: AppContainer, session: JsonSession, onChanged: () - Unit)三个入参各有明确职责参数类型职责containerAppContainer提供 i18n 翻译container.t(key, params)与全局能力弹层内所有文案统一走翻译键sessionJsonSession承载编辑区文本、jsonPath、pathPickerOpen、pathPickerSelection、pathResult、notice等会话状态是弹层的唯一数据源onChanged() - Unit状态变更后的通知回调由JsonScreen传入{ refresh() }驱动界面刷新调用侧由JsonScreen在pathPickerOpen为 true 时挂载见 JsonScreen.ktif (session.pathPickerOpen) { JsonPathPickerDialog(container, session) { refresh() } }2.2 路径列表的懒加载与兜底弹层组合时并不会预先持有完整路径树而是基于当前编辑器文本即时计算val entries runCatching { JsonEngine.listPaths(session.editor.text, translator) }.getOrDefault(emptyList()) val entryPaths entries.map { it.path }解析失败的场景编辑器里不是合法 JSON通过runCatching兜底为空列表弹层表现为无条目可选不会崩溃路径枚举逻辑在 JsonEngine.kt 的listPaths中实现核心是collectPaths的递归遍历JsonEngine.kt数组节点生成$path[index]形式label 为[index]对象节点键名若匹配^[a-zA-Z_$][\w$]*$则生成$path.key否则生成$path[键名]带 JSON 引号每个节点产出JsonPathEntry(path, label, preview(node), depth)四元组模型定义见 JsonModels.kt。2.3 打开弹层时自动对齐当前选中路径弹层通过LaunchedEffect在打开时把选中项对齐到会话当前jsonPath避免旧pathPickerSelection残留LaunchedEffect(session.pathPickerOpen, session.jsonPath, entryPaths) { if (!session.pathPickerOpen) returnLaunchedEffect val initial jsonPathPickerSelectionForOpen(session.jsonPath, entryPaths) if (session.pathPickerSelection ! initial) { session.pathPickerSelection initial onChanged() } }对齐规则实现在 JsonInspectorPathUi.kt 与 JsonInspectorResult.ktinternal fun jsonPathPickerInitialSelection(jsonPath: String, entryPaths: ListString): String entryPaths.find { it jsonPath } ?: entryPaths.firstOrNull() ?: jsonPath优先级当前jsonPath存在于路径树 → 选中它不存在则选中第一个路径条目连条目都没有则原样保留jsonPath。注意此时只改选中态不写入、不查询。2.4 布局与预览区弹层尺寸固定为 760×480 dp主题化mooDialogSurface圆角卡片内部为左右两栏见 JsonPathPickerDialog.kt左栏weight(0.9f)LazyColumn渲染JsonPathListRow条目单击仅更新pathPickerSelection双击走applyPathPickerChoice双击语义见下文 DIFF-458 部分中缝1 dp 分隔线右侧预览区用 1 dp 边框线隔离右栏weight(1.1f)展示选中路径等宽字体、11 sp与节点预览等宽字体、11 sp预览文本通过jsonPathNodePreview懒计算并随editor.revision与预览路径变化而重建val previewText remember(session.editor.revision, previewPath) { jsonPathNodePreview(session.editor.text, previewPath, translator, current?.preview.orEmpty()) }预览格式化由 JsonEngine.kt 的pathPickerPreview提供对齐 ElectronJsonPathPicker的formatPreview字符串节点返回原文不带 JSON 引号对象/数组节点走 pretty-print路径失效或缺失时返回空字符串。三、「使用」按钮语义化contentDescription与「仅选路径」行为3.1 无障碍语义对齐「使用」按钮通过Modifier.semantics显式声明contentDescriptionJsonPathPickerDialog.ktmodifier Modifier.semantics { contentDescription container.t(json.pathPicker.use) }文案键json.pathPicker.use在 Translator.kt 中登记为中文「使用该路径」。这一设计同时服务两类消费者Compose UI 测试测试可用onNodeWithContentDescription(zh.t(json.pathPicker.use))精确点击按钮无障碍与同窗口其他可点击控件的语义保持一致屏幕阅读器可朗读出按钮含义。按钮可用性由canUse current ! null决定——只有选中项确实存在于路径树中时「使用」才可点击有效拦截选中了一个不存在路径的非法提交。相关弹层内 i18n 键还有json.pathPicker.title选择 JSONPath、json.pathPicker.path路径、json.pathPicker.preview预览。3.2 点击后的状态变换applyPathPickerChoice「使用」按钮点击后调用会话级的统一行为封装JsonInspectorResult.ktinternal fun JsonSession.applyPathPickerChoice(path: String, pathAppliedNotice: String) { jsonPath path clearJsonPathQueryResult() notice pathAppliedNotice pathPickerOpen false }这一步完成了 DIFF-319 强调的 Electron 对齐语义状态字段变更结果含义jsonPath写入选中路径路径输入框反映新选择pathResult清空不触发 JSONPath 查询也不把节点预览塞进结果区notice置为json.notice.pathApplied中文「已应用 JSON Path」仅以提示形式告知用户路径已应用pathPickerOpen置为 false弹层随即关闭与之形成对照的是检查器内联路径树的单机预览行为applyInlinePathTreePreviewJsonInspectorResult.kt会写入jsonPath并把预览写入pathResult。也就是说弹层「使用」走的是纯净选择语义内联树单击走的是预览语义两者刻意区分由 DIFF-319 与 DIFF-457 共同固化。四、交互单测useButtonAppliesPathWithoutQuery的完整链路4.1 测试骨架新增 JsonPathPickerDialogInteractionTest.kt以runDesktopComposeUiTest(width 800, height 520)挂载真实MooTheme与对话框用createTempDirectory构造临时产品目录走AppPaths.resolve(...).ensureCreated()创建SettingsRepository、AppDatabase、HistoryRepository、LegacyMigrationRowRepository、SessionStore最终组装出与生产等价的AppContainersession直接以JsonSession()构造并预置状态session.editor.setText({store:{books:[{title:One}]}})固定测试 JSONsession.pathPickerOpen true打开弹层session.pathPickerSelection $.store.books[0].title预置选中路径session.pathResult [stale]预置一条过期查询结果用于验证使用后必须被清空。4.2 断言矩阵waitForIdle() onNodeWithContentDescription(zh.t(json.pathPicker.use)).performClick() assertFalse(session.pathPickerOpen) assertEquals($.store.books[0].title, session.jsonPath) assertEquals(, session.pathResult) assertEquals(zh.t(json.notice.pathApplied), session.notice)这条测试把 DIFF-319 的行为契约翻译成 5 个显式断言弹层关闭pathPickerOpen false路径写入jsonPath $.store.books[0].title查询结果被清空pathResult 即不自动查询的直接证据——如果弹层「使用」触发了查询预置的[stale]会被新结果覆盖而非清空提示为「已应用 JSON Path」测试通过后deleteRecursively()清理临时目录。从源码调用链看测试点击按钮后实际执行的是 JsonPathPickerDialog.kt 的onClick其中val entry current ?: returnMooButton的守卫与canUse共同保证非法状态不可提交。4.3 双击路径行的补充回归DIFF-458DIFF-458 在弹层单测中追加了双击链路doubleTapRowAppliesPathWithoutQuery通过onNodeWithContentDescription($.store.books[0].title).performTouchInput { doubleClick() }触发断言与「使用」完全一致关闭弹层、写入路径、清空pathResult、仅设置pathApplied提示。其实现基础是 JsonPathListUi.kt 中JsonPathListRow的.semantics(mergeDescendants true) { contentDescription entry.path } .pointerInput(entry.path) { detectTapGestures(onTap { onTap() }, onDoubleTap { onDoubleTap() }) }mergeDescendants true保证整行路径作为单一语义节点暴露给测试与辅助功能detectTapGestures同时承载单击仅改选中与双击应用路径两种手势。至此弹层的「使用」与「双击」两条入口共用同一applyPathPickerChoice语义与 ElectrononChoose(path)完全对齐。五、场景帧捕获capturePathPickerUseButtonFocusRing除行为断言外DIFF-457 还新增了 JsonPathPickerCaptureTest.kt 用于产出 Compose 场景帧证据同样以runDesktopComposeUiTest(width 800, height 520)挂载弹层{a:1,b:2}简单 JSONwaitForIdle()后onRoot().captureToImage().toAwtImage()抓取整帧写盘路径为docs/evidence/2026-09-15-inspector-screencapture/windows/148-compose-json-path-picker-use-tab-focus.png先mkdirs()再ImageIO.write断言file.length() 3_000防止写出空白/损坏帧。该证据图片同时记录了「使用」按钮在 Tab 焦点下的焦点环渲染属于对非产品主窗的独立 Compose 场景帧供 UI 评审与回归对照六、验证命令与回归结果在next-compose目录下执行桌面测试全量验证./gradlew :composeApp:desktopTest --offlineDIFF-457 落地时全量桌面测试通过615/615随后 DIFF-458 追加双击用例后扩展至 616/616。--offline表示不访问远程依赖仓库、纯本地离线构建适合在 CI 受限或网络隔离环境下稳定复现。七、设计要点小结弹层组件化是可测试性的前提JsonPathPickerDialog(container, session, onChanged)的签名让测试能以真实AppContainer 手工构造的JsonSession独立挂载弹层而不必启动整个JsonScreen状态封装收敛行为契约applyPathPickerChoice把仅选路径、不查询、关闭弹层、置提示四项语义收敛为单一函数使「使用」与「双击」天然复用同一契约杜绝分支漂移语义化贯穿 UI 与测试contentDescription同时服务onNodeWithContentDescription定位与无障碍朗读是 Compose 桌面端可测性即可访问性的典型实践证据帧沉淀 UI 回归场景帧捕获测试把无法用断言表达的视觉细节焦点环、布局落盘为证据文件供跨平台对照与评审追溯。如需继续深入可进一步阅读同目录下的相关 DIFF 记录DIFF-319「仅选路径、不自动查询」语义、DIFF-458 双击路径行回归以及弹层依赖的核心实现 JsonEngine.listPaths 与 JsonInspectorResult。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool Compose 桌面版 JSONPath 选择器弹层对齐 Electron 布局规格解析与实现验证MooTool Compose 桌面版 JSONPath 选择器弹层对齐 Electron 布局规格解析与实现验证 MooTool 在 Electron 前端桌面应用开发工具Penrose 词云示例实战用 Style 约束与目标函数排版文本标签Penrose 词云示例实战用 Style 约束与目标函数排版文本标签 本指南以仓库中 word cloud 示例 https://link.gitcode.桌面应用开发工具MooTool Compose 版 JSONPath 弹层双击执行查询的设计演变从 DIFF-285 到 DIFF-319 的交互收敛MooTool Compose 版 JSONPath 弹层双击执行查询的设计演变从 DIFF 285 到 DIFF 319 的交互收敛 导读 本文围绕 Moo桌面应用开发工具上一篇DDrawCompat终极指南让经典DirectX游戏在现代Windows上完美运行下一篇一键解决Windows DLL缺失问题Visual C运行库完整安装指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

通信设备元器件采购:5G基站和光模块的料怎么找?

通信设备元器件采购:5G基站和光模块的料怎么找?

通信设备的元器件有行业独有的三高:高频率、高可靠、长生命周期。一台 5G 基站的元器件要连续工作15-20年、经受-40C 到85C的户外温度循环、扛住雷击浪涌——通信级元器件的采购标准,比消费电子高一个量级。一、通信设备4类核心料射频前端器件&#xff1…

2026/10/16 6:07:48 阅读更多 →
AI协同编程实战:NGINX配置解构与pytest驱动的重构方法论

AI协同编程实战:NGINX配置解构与pytest驱动的重构方法论

1. 这不是“让AI写代码”,而是用AI做真实编程“我如何用 AI 做真实编程”——这句话里最值得拆开细嚼的,是“真实”两个字。不是生成一段能跑通的hello world,不是把Stack Overflow答案喂给大模型再润色一遍,更不是用Copilot自动补…

2026/10/16 6:07:48 阅读更多 →
被动元器件与连接器采购:电阻电容电感的坑在哪里?

被动元器件与连接器采购:电阻电容电感的坑在哪里?

被动元器件(电阻、电容、电感、磁珠)和连接器占 BOM 行数的60-70%,单颗价格几分到几毛,但恰恰是这些"最便宜的料"在量产阶段制造最多麻烦:电容批次容值漂移、电感饱和电流虚标、连接器接触不良。被动件采购的…

2026/10/16 6:07:48 阅读更多 →

最新新闻

2026流程管理软件选型指南:从需求定位到评分模型与避坑清单

2026流程管理软件选型指南:从需求定位到评分模型与避坑清单

1. 为什么今年选流程管理软件,比往年更让人头疼过去两年我接触了十多个在做流程管理软件选型的企业项目,发现一个明显的趋势:2026年这个时间节点,选型难度比前几年上了一个台阶。原因倒不复杂——流程管理软件这个赛道&#xff0c…

2026/10/16 6:51:58 阅读更多 →
云短信接口Demo全链路实战:从签名申请到验证码送达的避坑指南

云短信接口Demo全链路实战:从签名申请到验证码送达的避坑指南

简介:面向PHP开发者的阿里云短信接口演示包,专用于验证码、通知及营销消息的快速接入,适合需要为网站或业务系统增加短信能力的初中级开发者。压缩包大小三点三五兆,内含阿里云官方PHP开发工具包核心库以及可直接运行的示例脚本&a…

2026/10/16 6:51:58 阅读更多 →
RAID 0/1/5/6/10选型指南:从写惩罚到重建风险的权衡

RAID 0/1/5/6/10选型指南:从写惩罚到重建风险的权衡

上个星期,某公司的一台四盘位存储服务器在例行巡检时挂起一块黄盘。对方运维第一反应是问我能不能不关机直接换盘,我说可以,因为盘位布局和控制器都支持热插拔。换盘、识别、重建、校验,整套流程走完后,对方又问了一句…

2026/10/16 6:51:58 阅读更多 →
Git误删急救指南:掌握reflog与restore,30秒找回丢失代码

Git误删急救指南:掌握reflog与restore,30秒找回丢失代码

1. 项目概述1.1 核心场景挖掘Git误删急救,这个标题看着像段子,但凡是真正用Git写过代码的人,一眼就能get到那种心跳骤停的感觉。我自己就经历过:某次临近上线,手一抖执行了git reset --hard,结果把改了三天…

2026/10/16 6:51:58 阅读更多 →
iOS逆向实战:从抓包到还原请求签名与AES加密算法

iOS逆向实战:从抓包到还原请求签名与AES加密算法

做iOS安全测试这些年,我破解过不少App的通信加密,但每次遇到这种"请求带签名动态token"的组合,还是得老老实实走一遍完整的逆向链路。今天把"某藤之恋"这款社交App的请求加密校验算法分析过程完整复盘一下,不…

2026/10/16 6:51:58 阅读更多 →
AI智能降重工具深度测评:从词级替换到语义改写,哪种最实用?

AI智能降重工具深度测评:从词级替换到语义改写,哪种最实用?

查重这事儿,经历过的人都懂那种难受劲儿。自己一个字一个字憋出来的内容,一提交上去,飘红一片,要么重复率超标被导师打回,要么在发稿环节卡住。早年大家习惯靠手动改词换句来降重,费时费力不说,…

2026/10/16 6:50:57 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →