mcpField
D
drive-desktop-app

drive-desktop-app

github.com/reticlehq测试与质量1.3k246 次安装今天更新
代码仓库

关于 drive-desktop-app

用于 Reticle 的技能,可同时观察 Electron、Tauri 的 IPC 与渲染器行为,让桌面应用测试验证后端操作,而非依赖浏览器网络日志。

主要功能

  1. 01观察渲染器与 IPC 活动
  2. 02断言 IPC 命令结果
  3. 03检测 Electron preload 覆盖缺失
  4. 04支持截图和视觉差异比较

适用场景

  1. 01验证 Electron 操作触发 IPC 命令
  2. 02测试 Tauri invoke 流程
  3. 03检查操作后的桌面界面与控制台

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/reticlehq/reticle --skill drive-desktop-app

安装后在 Claude Code 中输入/drive-desktop-app确认已加载。

详细介绍

驱动桌面应用,并证明发生了什么

桌面应用通过 IPC 而非 HTTP 与后端通信。修改 fetch/XHR 无法观察到这些通信,因此,浏览器形态的工具看不到应用发出的任何后端调用:网络日志为空,操作没有正在进行的请求可供等待,而基于网络的断言则会空洞地通过。这从一开始就是一次假通过。

Reticle 同时观察渲染进程和 IPC 边界,因此桌面应用的判定与 Web 应用的判定含义相同。还没设置?请按照 reticle 技能操作:它会安装 Reticle,在 init 修改应用文件前询问用户,并验证一个流程。

Electron:两行代码,无需改动应用代码

// vite.config.ts — desktop:true lets connect() start in a packaged renderer (NODE_ENV=production).
// A default (production-mode) `vite build` ships no Reticle code; to drive a packaged
// renderer with no dev server, build it with `vite build --mode development`
export default defineConfig({
  base: './', // file:// needs relative asset paths
  plugins: [react(), reticle({ desktop: true })],
});
// electron/preload.cjs — FIRST line. This is what makes main-process IPC visible.
require('@reticlehq/electron/preload');

它必须放在 preload 中,而且必须是第一行。contextBridge.exposeInMainWorld 会向渲染进程提供一个深度冻结的对象,因此页面中的任何内容都无法再对其进行插桩。preload 是 ipcRenderer.invoke 仍可写入的最后位置,而且这个 shim 必须在 preload 捕获自身引用之前运行。

沙盒化的 preload 无法解析 node_modules,所以裸 require 会失败。可以打包 preload(electron-vite 和 Forge 默认会这样做),或者设置 sandbox: false。

Tauri:必须配置 CSP,且失败时不会有提示

前端与任何 Web 应用相同。容易被忽略的是,Tauri 的默认 CSP 会在桥接 WebSocket 打开前将其阻止,因此应用运行完全正常,只是永远不会连接:

{
  "app": {
    "security": {
      "csp": "default-src 'self' ipc: http://ipc.localhost; connect-src 'self' ipc: http://ipc.localhost ws://localhost:4400 ws://127.0.0.1:4400"
    }
  }
}

保留 ipc: http://ipc.localhost:Tauri v2 需要它来运行 invoke。这仅用于开发;请从发布配置中移除 ws:// 条目。

观察 IPC 无需修改 Rust 端:invoke('load_todos') 会直接以 ipc://load_todos 的形式到达 Reticle。只有截图和无头模式才需要 reticle-tauri crate,而且它的版本与 npm 包独立管理。

另外:请使用 hash 路由器。 打包后的渲染进程从 file:// 提供服务,基于 history 的路由无法解析。

验证

与 Web 应用使用相同的循环,只需在断言条件中加入 IPC:

reticle_act_and_wait({ sessionId, ref, action: "click", until: { kind: "allOf", predicates: [
  { kind: "net",     urlContains: "ipc://todos:archive", status: 200 },
  { kind: "element", query: { testid: "..." } },
  { kind: "console", level: "error", absent: true },
]}})

IPC 没有状态码。 200/500 是根据命令是否成功映射得到的合成状态码,这样相同的断言条件才能继续工作。在 Tauri 上,你会看到 status: 500 和 statusText: "OK" 同时出现。这不是错误:传输正常响应,而 500 是命令本身的判定结果。ok 才是权威结果。

reticle_look { action: "state" } 会像在 Web 上一样读取实时存储。平台的捕获步骤接好后,reticle_screenshot 和 reticle_visual_diff 就可以使用。Electron 无需额外配置;Tauri 需要该 crate。Tauri 的无头模式通过 RETICLE_HEADLESS=1 启用,截图仍然可用,因为捕获过程渲染的是 Webview,而不是屏幕。

缺少观察器时的表现

Electron preload 缺失时会明确报告,而不是静默失败:判定结果会返回 coverage: partial,并指出缺少的那一行,而不是在盲区中给出干净结果。如果看到这种情况,请先添加 preload 行,再相信任何结果。

如果应用运行正常,但看不到 IPC 调用:在 Electron 上,shim 的 require 不是第一行。在 Tauri 上,会观察到来自 @tauri-apps/api/core 的 invoke,但不会观察手写的 postMessage 协议。

诚实性

桌面应用中的 unknown 也不代表通过。不要为了把红色判定改成绿色而放宽 IPC 断言:桌面应用中的假通过,正是这套接线要消除的问题。


完整的桌面应用参考文档:curl https://docs.reticle.sh/desktop.md。其他所有内容:curl https://docs.reticle.sh/llms.txt。

评论

支持 Markdown