Files
mnote/scripts/TESTING_REFERENCE.md
T

23 KiB
Raw Blame History

mnote 测试参考

这份文档面向 /mnt/Data1T/mnote/scripts 目录下的现有测试脚本,目标不是重新设计测试体系,而是把当前已经在用的 smoke、回归脚本、截图取证和人工复核方式整理成一套可执行参考。

当前结论先说在前面:

  • scripts/ 里的主力仍然是 Playwright smoke + Node 断言
  • mnote 来说,最有价值的不是把所有测试都换成“浏览器插件式控制”,而是把已有 smoke 的结果变得更可看、更易复核。
  • /doko 适合作为 smoke 之后的“真实页面直观复核层”,不是用来替代 smoke。
  • 2026-05-20 起,默认主入口固定按 http://127.0.0.1:3000 理解;历史记录里的 3001 只代表当时临时 mnote-web 实例,不再作为默认验收入口。
  • 历史 smoke 分为 currentretired/debug 两类维护;退役脚本不应进入默认回归,除非脚本自身要求显式环境变量。
  • 2026-05-27 起,默认 smoke 基线只覆盖 3000 Rust SSR + leptos-tiptap + local-first 主路径;Convex export、Convex 兼容、Next、3104、BlockNote 默认路径脚本不再放在默认候选里。
  • 依赖 /api/dev/seed 的 browser smoke 默认使用 npm run dev:hotdev:hot 默认启用 MNOTE_WEB_ALLOW_DEV_FIXTURES=1desktop:hot 与生产启动仍默认关闭。修改 Node 启动脚本或环境变量后必须重启 dev:hot 主进程,不能只等待 cargo-watch 重载 Rust。

0. 当前 smoke 状态清单

这一节用于避免历史脚本被误当作当前架构主链验收。

0.0 2026-05-26 默认基线

建议日常 smoke 先跑这一组,确保当前主入口、认证、文档 island、Page Aggregate、local-first 和关键 runtime surface 没断:

node scripts/task114-rust-web-gateway-entry-smoke.js
node scripts/task159-auth-entry-smoke.js
node scripts/task164-desktop-hot-local-folder-main-entry-smoke.js
node scripts/task166-local-first-managed-workspace-no-convex-smoke.js
node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js
node scripts/task490-runtime-surfaces-smoke.js

其中 task490-runtime-surfaces-smoke.js 是轻量浏览器 smoke,验证页面设置、Page AI drawer 打开/关闭、Page AI stop-run abort、slash menu、block handle menu 能在当前 leptos-tiptap 文档页工作;它使用 mock run 覆盖停止按钮,不要求真实模型返回,也不替代更重的页面设置、OpenHub/Page AI 或编辑器菜单专项脚本。

0.1 当前主链优先脚本

  • 入口与认证:task114-rust-web-gateway-entry-smoke.jstask159-auth-entry-smoke.jstask097-homepage-entry-smoke.js
  • Rust SSR 文档页 / Page Aggregatelocal-first 默认优先 task167-local-markdown-title-body-options-no-convex-smoke.jsPage Aggregate browser conversion / compat fallback 改动补跑 task522-page-aggregate-compat-fallback-contract.jscloud/control-plane 文档可补跑 task110-page-title-single-truth-smoke.jstask-page-aggregate-body-sync-smoke.jstask-page-aggregate-options-sync-smoke.jstask-page-aggregate-refresh-persistence-smoke.js
  • leptos-tiptap runtime surfacetask490-runtime-surfaces-smoke.js;需要验证保存回读可补跑 task121-rust-web-editor-island-hydration-smoke.js,但它仍使用 /api/tree/commands create 准备文档,不作为无 Convex 默认基线;需要验证浮层互斥和更多菜单状态时再跑 task158-e30-menu-state-smoke.js
  • local-first 本地工作区:task164-desktop-hot-local-folder-main-entry-smoke.jstask166-local-first-managed-workspace-no-convex-smoke.jstask167-local-markdown-title-body-options-no-convex-smoke.jstask436-local-markdown-open-document-external-change-smoke.jstask443-local-markdown-asset-upload-smoke.jstask451-local-markdown-conflict-resolution-ui-smoke.jstask452-local-search-index-browser-smoke.jstask453-local-folder-page-ai-changed-files-smoke.jsWorkspacePath / ObjectIdentity runtime 消费统一改动补跑 task524-workspace-object-identity-matrix-smoke.jstask452 只覆盖普通本地搜索、settings API、tag/backlink API 和旧 local-index UI 不复活;资料库问答、PDF/Office/image source ingestion 与引用回跳改跑 WeKnora / provider-neutral knowledge-rag 脚本。
  • WeKnora / OpenHub 资料库:task781-knowledge-bases-registry-smoke.jstask785-weknora-create-kb-folder-ingest-search-smoke.jstask787-weknora-default-lightrag-legacy-smoke.jstask772-openhub-weknora-kb-ui-smoke.js 覆盖默认 provider、知识库列表、摄取、搜索、引用桥接与 legacy LightRAG guard。旧 task529/530/531/534 LightRAG 脚本只作为 legacy fallback / 历史对照,不进入默认回归。旧 task526-local-folder-ocr-api-smoke.js / OCR sidecar 链路已退役并软归档;/api/search/documents 不作为 WeKnora、LightRAG legacy、LiteParse、OCR sidecar 或 evidence.sqlite 的资料库问答 fallback。
  • local Markdown conflict regressiontask510-local-markdown-conflict-regression-group.js 串联真实冲突、连续上传、新建页面、外部恢复、多 tab CAS 与上传 409 孤儿策略;可用 MNOTE_CONFLICT_REGRESSION_TASKS=a.js,b.js 做定点子集。
  • tree realtime / live cachetask446-tree-rename-dual-browser-live-smoke.jstask447-tree-move-order-dual-browser-live-smoke.jstask448-tree-resync-recovery-dual-browser-smoke.jstask449-tree-sse-reconnect-snapshot-recovery-smoke.js
  • 资源对象与 mindmaptask455-local-folder-mindmap-clean-smoke.jstask456-resource-object-shell-sync-smoke.jstask166-mindmap-phase6-block-smoke.jstask167-mindmap-kmind-parity-smoke.jstask168-mindmap-put-validator-smoke.jsPage AI mindmap skill / 资源生成改动补跑 task503-mindmap-skill-capability-smoke.js,真实 mindmap resource tab / Page AI target 改动补跑 task525-page-ai-mindmap-resource-target-smoke.js
  • Page AI / agent history / ChatOnlytask502-page-ai-agent-selector-context-smoke.js 覆盖 Page AI agent/context/target picker、skills source 和 run payloadopencode WebUI embed 改动补跑 task763-page-ai-opencode-embed-smoke.js,只验证真实登录、Page AI 抽屉、opencode iframe/host chrome 和 changed file/open/refresh DOM hook,不 mock 聊天成功;raw local resource target 改动补跑 task520-page-ai-raw-resource-target-smoke.jstask504-page-ai-history-agent-filter-smoke.js 覆盖 Page AI 历史按 agent 过滤;ChatOnly / provider session 绑定改动优先跑 task512-chatonly-doubao-sync-smoke.js,跨 provider 同步补跑 task513-chatonly-provider-sync-smoke.js
  • Dev hot / OnlyOffice live bridgeSidebar dev hot reload 入口改动补跑 task514-sidebar-dev-hot-reload-gating-smoke.jsOnlyOffice live bridge session / scope / HTTP 工具边界改动补跑 task515-onlyoffice-live-scope-http-smoke.jsbridge session/token/queue/current/close 和 docKey/pageOrigin 元数据改动补跑 task516-onlyoffice-bridge-multisession-browser-smoke.jsbridge plugin index / Asc.plugin direct loop / plugin 元数据透传改动补跑 task517-onlyoffice-bridge-plugin-direct-smoke.js;真实 ONLYOFFICE iframe / DocumentServer session、同文档双 tab、resource scope 和非 dry-run 写入落点改动补跑 task518-onlyoffice-real-iframe-session-scope-smoke.jsPage AI 真实 UI 选择 Office target 并冻结 live bridge session 改动补跑 task523-page-ai-onlyoffice-real-target-session-smoke.js
  • local resource lifecycle APItask437-local-folder-asset-trash-lifecycle-smoke.js,现在只验证 local-file:* delete / restore / purge,不再依赖普通 .txt 是否出现在 UI 文件树。

0.2 需要退役或拆分的历史脚本

  • task444-convex-workspace-export-local-fixture-smoke.jstask455-convex-export-plan-rollback-smoke.jsexport-convex-workspace-to-local.jsConvex export 迁移验证已退出默认 smoke,已归档到 recycle/scripts/retired-convex-export-smokes-20260526/
  • 注意编号复用:scripts/task444-filetree-create-mindmap-title-cache-smoke.jsscripts/task455-local-folder-mindmap-clean-smoke.js 仍是当前本地 filetree / mindmap 脚本;退役的是带 convex-export 名称的 task444 / task455。
  • 旧 Convex 兼容 smoke 已软删除到 recycle/20260527-legacy-cleanup/convex/scripts/,包括 task163task174task175task427task428task429task430task431task432task433task434
  • task179-tree-create-delete-no-reload-smoke.js:覆盖 /tree debug shell。/tree 已是显式 debug/internal 边界,脚本默认阻断;只有设置 MNOTE_ALLOW_DEBUG_TREE_SMOKE=1 时才可执行。
  • task123-rust-web-tree-live-stream-consumer-smoke.js:只证明 /api/tree/events SSE fallback 仍可用。当前 realtime 主链是 WebSocket push + SSE fallback;验证主链时优先使用 446 / 447 / 448,只有排查 fallback 时再跑 123。
  • task019task021task022 这类早期 UI regression 脚本已软删除到 recycle/scripts/retired-ui-regressions/,只作为历史对照;后续默认不要用于当前 Rust SSR / local-first 主路径验收。

0.3 其他 current 候选脚本

这些脚本不是最小默认基线,但仍属于当前 Rust SSR / leptos-tiptap / local-first 维护面,按改动范围选择性运行:

  • task426-mnote-web-main-no-reload-smoke.js
  • task109-leptos-island-multipage-save-smoke.js
  • task122-rust-web-create-page-ui-smoke.js
  • task125-rust-web-search-server-first-smoke.js
  • task165-rust-web-dual-pane-smoke.js
  • task458-local-create-page-no-conflict-smoke.js
  • task459-local-markdown-attachment-tab-smoke.js
  • task484-local-folder-page-body-refresh-readback-smoke.js
  • task486-local-markdown-save-error-editor-preserves-content-smoke.js
  • task487-local-folder-tree-live-consumer-smoke.js

1. 当前测试分层

按目录里的现状,脚本大致分成四层。

1.1 入口与网关层

这一层主要验证路由、网关、owner、认证入口、基础响应是否正确,特点是快、稳定、适合作为最早执行的守门测试。

代表脚本:

  • task097-homepage-entry-smoke.js
  • task114-rust-web-gateway-entry-smoke.js
  • task159-auth-entry-smoke.js

适用场景:

  • 刚切流 Rust Web
  • 改了入口路由、鉴权、兼容代理
  • 需要先判断“服务有没有活着、入口是不是对的”

1.2 页面交互 smoke 层

这一层是当前最核心的 UI 验证方式:启动页面、登录测试账号、进入真实文档页或工作区,然后通过 Playwright 操作页面并做断言。

代表脚本:

  • task110-page-title-single-truth-smoke.js
  • task112-tree-rust-family-regression-smoke.js
  • task120-rust-web-tree-integration-smoke.js
  • task122-rust-web-create-page-ui-smoke.js
  • task164-page-options-visible-effect-smoke.js
  • task490-runtime-surfaces-smoke.js
  • task165-rust-web-dual-pane-smoke.js
  • task164-desktop-hot-local-folder-main-entry-smoke.js
  • task166-local-first-managed-workspace-no-convex-smoke.js
  • task455-local-folder-mindmap-clean-smoke.js

这一层已经覆盖了当前主线里最重要的部分:

  • tree / sidebar / create page
  • document shell / island hydration
  • 页面设置、双栏、AI、local folder
  • Rust Web 主路径

1.3 Wolai 对标与视觉取证层

这一层不是单纯判断“是否通过”,而是要保留截图、矩阵、对比结论,方便和 Wolai 体验做真实核对。

代表脚本:

  • task119-rust-web-wolai-visual-regression-smoke.js
  • task129-wolai-aline-baseline-smoke.js
  • task130task137 一系列 wolai-aline-*
  • task160-wolai-page-settings-shell-smoke.js
  • 页面 AI 旧 /api/ai-agent/run 视觉 smoke 已移入本机 gitignored recycle/scripts/retired-ai-agent-run-smokes/;当前页面 AI 验证优先使用 OpenHub / opencode / Page AI smoke 与 task-page-block-ai-tools-smoke.js。Hermes 相关 smoke 只作为 legacy guard / 历史对照。

这一层最重要的原则不是“文案命中”,而是:

  • 必须有截图
  • 必须能说明视口
  • 必须能说明对比对象
  • 最终仍需要人工看图

1.4 共享 helper 与登录/临时文档支撑层

这部分决定了 smoke 是否能稳定复用。

关键文件:

  • tree-shell-smoke-helpers.js
  • task114-rust-web-gateway-entry-smoke.js

目前 helper 已经沉淀了几个稳定约定:

  • 默认前端入口:MNOTE_UI_BASE_URL,缺省 http://127.0.0.1:3000
  • 默认测试账号:
    • 邮箱:mnote.e2e@example.com
    • 密码:MnoteE2E123!
    • 快捷按钮:测试账号快速登录
  • 通过 API 或 UI 兜底完成认证
  • 为 smoke 自动创建、重命名、清理临时页面

后续新脚本优先复用这些 helper,不要在每个任务里再复制一套登录和清理逻辑。

Dev seed 启动契约

  • 需要 setupWorkspaceAccessseedAiPolicyseedAiRuntime 等测试数据准备能力时,先确认服务由 npm run dev:hot 启动。
  • npm run dev:hot 默认开启 dev fixtures;可用 MNOTE_WEB_ALLOW_DEV_FIXTURES=0 npm run dev:hot 显式关闭。
  • npm run desktop:hot 保持生产近似的安全默认,不自动开放 /api/dev/seed;确需复用时显式执行 MNOTE_WEB_ALLOW_DEV_FIXTURES=1 npm run desktop:hot
  • smoke 遇到 dev_seed_disabled 时不得标记为“功能未验证后跳过”;应先按上述契约重启服务,再重新执行完整 smoke。

2. 当前推荐测试顺序

对本项目,推荐不要一上来就跑最重的 UI 对标脚本,而是按下面顺序推进。

2.1 第一步:入口守门

先跑入口和网关类 smoke,确认不是服务没起或路由错了。

建议优先:

node scripts/task114-rust-web-gateway-entry-smoke.js
node scripts/task159-auth-entry-smoke.js
node scripts/task097-homepage-entry-smoke.js

适用时机:

  • 本地服务刚启动
  • 刚切换分支
  • 改了认证、入口、gateway、compat

2.2 第二步:主路径交互 smoke

入口没问题后,再跑和当前改动最相关的页面交互脚本。

例如:

  • tree / sidebar 改动:task112task120task122
  • document shell / islandtask110task121
  • local-first:优先使用 task164-desktop-hot-local-folder-main-entry-smoke.jstask166-local-first-managed-workspace-no-convex-smoke.jstask167-local-markdown-title-body-options-no-convex-smoke.jstask455-local-folder-mindmap-clean-smoke.js
  • 页面设置:task160task164-page-options-visible-effect-smoke.js
  • 双栏:task165
  • AI:优先使用 OpenHub / opencode / Page AI 当前主线 smoke、task-page-block-ai-tools-smoke.jstask-hermes-page-ai-retirement-guard.js 这类 legacy guardHermes 页面 AI smoke 只作为历史对照。Page AI history / skills / ChatOnly 相关改动补跑 task503-mindmap-skill-capability-smoke.jstask504-page-ai-history-agent-filter-smoke.jstask512-chatonly-doubao-sync-smoke.jstask513-chatonly-provider-sync-smoke.jsOnlyOffice live bridge 改动补跑 task515-onlyoffice-live-scope-http-smoke.jstask516-onlyoffice-bridge-multisession-browser-smoke.jstask517-onlyoffice-bridge-plugin-direct-smoke.jstask518-onlyoffice-real-iframe-session-scope-smoke.js,其中 task516/517 覆盖 bridge session lifecycle 与 docKey/pageOrigin 元数据;Page AI 真实 target picker / Office live session 改动补跑 task523-page-ai-onlyoffice-real-target-session-smoke.jstask155task156task161 等旧 /api/ai-agent/run smoke 只保留在本机 gitignored recycle/scripts/retired-ai-agent-run-smokes/ 做历史对照

原则:

  • 只跑和当前改动相关的脚本
  • 不要无差别全量跑
  • 先窄后宽

2.3 第三步:截图证据复核

如果脚本本身已经输出:

  • screenshot
  • screenshotDir
  • measure
  • matrixPath
  • resultPath

那这些产物不应只当“附带文件”,而应作为测试结果的一部分。

推荐做法:

  • 成功时也保留关键截图
  • 失败时至少保留失败前最后一张截图
  • 重要 UI 任务保留整组截图目录

2.4 第四步:/doko 真实页面复核

当 smoke 已经告诉你“逻辑大体通过”,但你仍想确认页面是否真的像人看到的一样时,再补 /doko

/doko 更适合回答这类问题:

  • 首屏布局是不是顺眼
  • Sidebar 层级、图标、文案是否真可读
  • 页面设置弹层是否真的展开到位
  • 登录后工作区是否像预期渲染

/doko 不擅长替代:

  • 稳定断言
  • 自动点击链路
  • 大量重复回归

所以推荐组合是:

smoke 先筛出通过/失败 -> 看截图 -> 必要时再用 /doko 复核真实页面

3. 为什么当前不建议把主线转成“浏览器插件测试”

当前讨论过 codex cli + 浏览器插件 的方向,但对 mnote 现阶段的主要收益并不明显。

原因有三点:

  1. 你当前真正缺的是“页面直观证据”,不是“替换掉 Playwright”
  2. scripts/ 里的 smoke 已经能覆盖多数关键交互,只是证据层不够统一
  3. 浏览器插件路线更适合复用真实 Chrome 当前标签页和真实登录环境,不是当前项目测试的首要瓶颈

因此,现阶段更推荐:

  • 保留 Playwright smoke 作为自动化骨架
  • 补足截图、trace、结果摘要
  • /doko 做人工视角复核

4. 新增或修改 smoke 的写法建议

这里不是要求统一重构旧脚本,而是约束新增脚本尽量沿着同一条路走。

4.1 优先复用 helper

优先从下面两个文件拿能力:

  • tree-shell-smoke-helpers.js
  • task114-rust-web-gateway-entry-smoke.js

尤其是:

  • 登录
  • 创建临时文档
  • 清理临时文档
  • fetchWithTimeout
  • findFreePort
  • waitForGateway

4.2 让脚本输出结构化结果

推荐脚本结束时输出 JSON,至少包含:

{
  "ok": true,
  "baseUrl": "http://127.0.0.1:3000",
  "task": "taskxxx-name",
  "screenshot": "/abs/path/to/file.png",
  "screenshotDir": "/abs/path/to/dir"
}

如果没有截图,也应该至少输出:

  • ok
  • baseUrl
  • task
  • 关键对象 id(如 documentIdworkspaceId

4.3 对 UI 任务默认保留截图

满足下面任一条件时,建议默认保留截图:

  • 首屏入口变化
  • Sidebar / tree 结构变化
  • modal / popover / dropdown 变化
  • editor block 行为变化
  • Wolai 对标

推荐命名方式延续现有风格:

  • 01-before-*
  • 02-after-*
  • 03-after-reload-*

这样后续人工复核时不需要重新猜步骤。

4.4 失败信息要面向定位

断言报错要直接描述“哪个状态不对”,不要只写泛化失败。

推荐:

  • 开启宽版后 htmlWide 应为 true,实际 false
  • 测试账号登录后仍停留在 /auth
  • 本地首屏未捕获工作区特征

不推荐:

  • smoke failed
  • assert error

5. 针对当前 mnote 的推荐组合

如果后续只是做日常开发验证,推荐这样选:

5.1 快速检查

适合日常改完立刻看:

node scripts/task114-rust-web-gateway-entry-smoke.js
node scripts/task159-auth-entry-smoke.js

5.2 主路径回归

按当前改动挑 1 到 3 个最相关脚本,例如:

node scripts/task120-rust-web-tree-integration-smoke.js
node scripts/task122-rust-web-create-page-ui-smoke.js
node scripts/task164-page-options-visible-effect-smoke.js

5.3 视觉复核

如果任务明显涉及视觉或交互形态:

  • 先看 smoke 产出的截图
  • 再用 /doko 打开真实页面复核

5.4 Wolai 对标任务

对标任务不要只看断言结果,至少补:

  • 本地 smoke
  • Wolai 基线截图
  • 本地截图
  • 必要时 comparison matrix

6. 对后续演进的建议

这部分不是要求本轮立刻实现,而是后续维护时优先考虑。

6.1 在现有 smoke 上统一证据产物

优先级最高的增强不是“换工具”,而是统一输出:

  • tmp/.../screenshots
  • tmp/.../trace.zip
  • tmp/.../result.json

这样 smoke 从“脚本 pass/fail”升级成“脚本 + 可看证据”。

6.2 把 /doko 固化成复核步骤

适合写进任务流程的话术是:

  • 先跑 smoke
  • 再看截图
  • 仍有疑问时用 /doko 看真实渲染

不要让 /doko 承担自动化断言职责。

6.3 新脚本优先沿当前命名方式继续

目前 taskNNN-...-smoke.js 已经形成了可追踪的任务链,后续建议继续沿用,避免引入第二套命名体系。


如果后续要继续推进,最值得做的不是重写测试体系,而是:

  1. 给最常用的 smoke 补统一截图/trace 产物
  2. 再补一份“如何读取 smoke 结果”的轻量脚本或汇总器

这样能直接解决当前最真实的痛点:A + C,也就是“结果更直观、测试更像真的看过页面”。

7. 脚本纪律:不得直写 control-plane 数据库

所有测试和 smoke 脚本不得直接通过 sqlite3 CLI、node:sqlitebetter-sqlite3 或任何本地 SQLite 库写 control-plane DB。需要写入测试数据时,必须走以下批准路径:

7.1 通过 API seed(推荐)

使用 scripts/lib/control-plane-dev-seed.js 提供的 helper,通过 POST /api/dev/seed 写入:

const { setupWorkspaceAccess, seedAiRuntime } = require("./lib/control-plane-dev-seed");
await setupWorkspaceAccess(requestContext, baseUrl, { ... });

该 helper 调用的是 Rust /api/dev/seed 端点,不直写数据库。 初始环境(测试账号 + workspace)也可通过 control-plane-admin init --backend ... 准备,见 docs/operations/control-plane-turso.md

7.2 通过统一环境变量构建

使用 scripts/lib/control-plane-test-env.jsbuildControlPlaneTestEnv() 获取正确的控制面环境变量:

const { buildControlPlaneTestEnv } = require("./lib/control-plane-test-env");
const controlPlaneEnv = buildControlPlaneTestEnv(dataRoot, process.env);
// 然后传给 spawn(cargo, args, { env: { ...controlPlaneEnv } })

7.3 例外

  • scripts/lib/control-plane-dev-seed.jsscripts/lib/control-plane-test-env.js 本身是批准 helper。
  • scripts/desktop-hot.jsscripts/dev-hot.jsscripts/prod-build-start.js 作为启动基础设施,设置环境变量路径是必要的。
  • rust/crates/ 下的 Rust 代码通过 ControlPlaneStore trait 访问数据库是正常路径。
  • scripts/task-control-plane-admin-libsql-roundtrip-smoke.js 使用 cargo run --bin control-plane-admin,走 Rust admin CLI。
  • sqlite fallback、admin CLI、legacy evidence/local_search 不在脚本纪律约束范围内。
  • OpenHub 自身 SQLite 不绑定本轮 control-plane Turso 切换;OpenHub 数据库迁移独立安排,不在当前首轮范围内。

7.4 违规后果

  • 直接 sqlite3 写 control-plane DB 会导致多个进程同时写同一个 SQLite 文件,增加 WAL 损坏和并发写入冲突的风险。
  • 直接写库的脚本在切换到 Turso/libSQL 后端后将无法运行。
  • 违反此纪律的脚本将被要求改用上述批准路径。

具体约束条目见 AGENTS.md 中"脚本纪律"一节。