Plate 测试收割器之 Portable Text Source Routing 全解:200 个外部测试文件如何路由到 Slate v2 行为家族
2026/9/15 1:45:36 网站建设 项目流程

Plate 测试收割器之 Portable Text Source Routing 全解:200 个外部测试文件如何路由到 Slate v2 行为家族

【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate

本文以 docs/editor-test-harvester/portabletext/source-routing.md 为骨架,结合 inventory.md、test-index.md 与 2026-05-29 收割计划,完整解读 Plate 仓库中"编辑器测试收割器(editor-test-harvester)"对 Portable Text 测试资产的家族路由(source routing)机制。读者将掌握路由表 8 列字段的含义、11 个行为家族与 2 个产品策略家族的划分依据、四类动作(refactor-existing / create-new / split / plate-owned)的决策逻辑,以及bun test与 Playwright 验证命令的正确用法。

一、这份文档在收割流程中的位置

source-routing.md 不是一篇孤立的表格,而是 Plate 仓库"编辑器测试收割"体系四件套产物之一。收割器(editor-test-harvester)的工作流由 docs/plans/templates/editor-test-harvester.md 模板约束,其完整流程在 2026-05-29-portable-text-editor-test-harvest.md 中记录为九个阶段:Intake and boundary → Inventory → Test-name extraction → Classification pressure → Behavior extraction → Slate/Plate coverage mapping → Action planning → Ecosystem synthesis → Closure review。

四件产物各司其职:

产物路径内容
reportdocs/editor-test-harvester/portabletext/report.md行为/产品家族矩阵、归属判定、Next slice 交接
inventorydocs/editor-test-harvester/portabletext/inventory.md502 行完整清单与逐文件分类(Runnable / Category / Family / Reason)
test-indexdocs/editor-test-harvester/portabletext/test-index.md200 个可运行文件的 1944 个测试名/场景名锚点
source-routingdocs/editor-test-harvester/portabletext/source-routing.md本文主体:200 个 portable / portable-mixed 文件的家族路由表

关键前提:路由表里的Source列(如packages/editor/gherkin-tests/delete.test.ts)指向的是被收割的外部 Portable Text 仓库(目标../portabletext,MIT 许可),并非当前 plate 仓库内的文件。当前仓库内的packages/目录不包含editor包,因此这些 Source 路径不能直接在当前仓库解析——它们是"待迁移/待对齐"的行为来源。这正是路由表存在的意义:把这些外部测试文件的行为不变量(behavior invariant)逐条归入本仓库 Slate v2(.tmp/slate-v2工作副本)或 Plate 产品的责任范围。

二、路由表 8 列字段语义

路由表的表头固定为 8 列,每一列对应收割决策链上的一环:

含义说明
#行号1~200,与 test-index.md 的序号一致,便于交叉引用
Source外部仓库内的测试文件路径相对于被收割仓库../portabletext
Category类别二值:portable(纯可移植行为)或portable-mixed(行为与产品策略混合)
Family家族编号PT-H01PT-H12行为家族、PT-P01/PT-P02产品策略家族
Family title家族标题一句话描述该家族覆盖的行为面
Action建议动作refactor-existing/create-new/split/covered/plate-owned
Target owner目标归属.tmp/slate-v2下的测试文件、Plate 序列化器包、或 backlog 项
Verification / backlog command验证命令或待办可复制的bun test/ Playwright 命令,或指向 Plate 产品待办

表头之上的元信息(Source、Generated、行数)用于可追溯性:"Portable and portable-mixed files routed: 200" 是本次收割的硬性验收指标之一——验收门槛要求每一个可运行的 portable / portable-mixed 文件都被路由到某个行为家族(见计划文档 Completion threshold)。

三、类别:portable 与 portable-mixed 的分界线

路由表第一道分类是Category,它决定了一个测试文件的行为到底属于"原始编辑器内核(raw Slate)"还是"产品策略(Plate)"。依据 inventory.md 的统计,200 个被路由文件中:portable 94 个、portable-mixed 106 个(该清单同时给出全部 502 行的分类账:portable 94、portable-mixed 106、plate-owned 100、skip 14、harness 188、product-shell 0、uncertain 0)。

  • portable:该文件承载的是可移植的编辑行为不变量——删除、插入、选择投影、void 对象边界、历史与协同等。这些不变量应当下沉到 Slate v2 内核测试中,与 Portable Text 的 schema / API 形态无关。典型如packages/editor/gherkin-tests/delete.test.ts(PT-H05)、packages/editor/src/engine/path/compare-paths.test.ts(PT-H11)。
  • portable-mixed:文件同时压测"原始行为"与"产品策略",需要拆分。inventory.md 为每类混排行给出了具体理由,例如:
    • paste.test.ts→ PT-H06,"raw fragment clipboard behavior mixed with serializer/matcher policy"(剪贴板原始片段行为混入了序列化器/匹配器策略);
    • event.drag.drop.test.tsx→ PT-H07,"native drag/drop substrate mixed with product drag handles and schema objects"(原生拖放底子混入了产品拖拽手柄与 schema 对象);
    • behavior-api.test.tsx→ PT-H12,"raw event/command pressure mixed with Plate plugin or renderer API policy"。

拆分原则(计划文档 Findings 与 Decisions 的原话转述):保持 raw Slate 无观点(不导入 Portable Text schema 或行为 API);剪贴板原始片段/选择行为归 Slate,序列化器与 matcher 归 Plate;列表、序列化、mark、annotation、渲染器、工具栏、插件类行一律路由给 Plate。

四、行为家族全景:11 + 2 个家族

路由表内实际出现的行为家族为 11 个(PT-H01~PT-H09、PT-H11、PT-H12;PT-H10 focus/keyboard 在 report 矩阵中定义,但本批次 200 行中没有路由到它的文件)。另有 PT-P01 / PT-P02 两个产品策略家族,主要承载 plate-owned 行的归属(inventory.md 中约 100 行为 plate-owned)。以下为各家族的标题、含义与代表行:

家族标题覆盖的行为面路由表中的代表行
PT-H01Selection boundary and projection选择边界与投影:range 悬挂、选中端点、根/对象边界gherkin-tests/selection.test.tsengine/point/transform-point.test.tsselectors/selector.get-selection-text.test.tstests/to-engine-range.test.tsx
PT-H02Content roots and containers内容根与容器:可编辑嵌套根、容器内规范化、渲染src/schema/resolve-containers.test.tstests/container-normalization.test.tsxtests/container-rendering.test.tsx
PT-H03Void and object boundary editingvoid/对象边界编辑:孤立图片、行内对象、spacergherkin-tests/block-objects.test.tsengine/node/is-void-node.test.tstests/inline-objects.test.tsx
PT-H04Insert, split, and break placement插入/拆分/换行落点:placement 矩阵、fragment 插入gherkin-tests/insert.block.test.tstests/event.insert.block.test.tsx(38 个场景)、utils/util.block-offset.test.ts
PT-H05Delete and backspace matrix删除/退格矩阵:合并块、边界、词/行删除gherkin-tests/removing-blocks.test.tstests/event.delete.matrix.test.tsxtests/event.delete.backward.test.tsx
PT-H06Clipboard and fragment serialization剪贴板与 fragment 序列化:粘贴、HTML 反序列化gherkin-tests/paste.test.tstests/event.paste.test.tsxtests/upload-images-on-paste.test.tsx
PT-H07Drag/drop and drop target resolution拖放与落点解析:self-drop 抑制、跨容器移动src/editor/resolve-element-drop-position.test.tstests/event.drag.drop.test.tsxtests/event.drag.drop.self-drop.test.tsx
PT-H08History and remote collaboration rebasing历史与远程协同 rebase:undo/redo、远端补丁、选择稳定性gherkin-tests/undo-redo.test.tsxtests/collaborative-editing.test.tsxtests/selection-after-remote-patches.test.tsx
PT-H09IME and composition transportIME/组合输入传输:日文、韩文、格式化边界组合tests/composition.test.ts(日韩 IME、装饰器/注解边界的 25 组测试)
PT-H11Path, point, range, and operation core路径/点/区间/操作内核:comparePaths、parentPath、getNode、dirty paths、operation-to-patchesengine/path/*.test.tsnode-traversal/*.test.tsinternal-utils/operation-to-patches.test.ts
PT-H12Behavior pipeline and extension ordering行为管线与扩展排序:事件 raise/forward/execute、优先级、渲染默认值tests/behavior-api.test.tsx(27 个场景)、tests/event.patches.test.tsx(95 个锚点)、tests/positional-override-*.test.tsx
PT-P01Portable Text 产品策略marks/annotations/comments/decorators/list 属于 Plate 产品策略inventory.md 中 plate-owned 行(annotations.test.tslists.test.ts等)
PT-P02序列化/插件/工具栏策略parser/serializer/plugin/toolbar 属于 Plate 包与文档inventory.md 中 plate-owned 行(html、markdown、docx、block-tools 等包)

体量观察(逐行统计路由表):PT-H12 是最大的家族(约 68 行),主要来自packages/editor/tests/下的事件与行为管线测试;PT-H02 与 PT-H11 各约 30 行;PT-H09 仅 1 行(composition),PT-H06 与 PT-H07 各 3~4 行——后者正是计划文档反复强调的"需要真实浏览器证据、不能只用模型推断"的高风险面。

五、Action 语义:四类动作的决策逻辑

路由表第 5 列Action把家族判定翻译成具体工作指令,其取值在路由表中可归纳为:

动作语义路由表中的典型表述代表行
refactor-existing已有 Slate v2 测试可承载该不变量,先重构归并,避免复制重复测试"refactor-existing into a compact placement matrix before adding duplicates"(先压成紧凑矩阵再加重复)PT-H04 的 insert / split / break 各文件
create-new该行为在 Slate v2 侧尚无覆盖,需新建测试"create-new browser rows after unit resolver gap check"(先查单元解析器缺口再建浏览器行)PT-H07 的 drag/drop 行
refactor-existing/create-new部分覆盖:重构已有并补齐根/对象边界缺口"refactor-existing and fill object/root boundary gaps"PT-H01、PT-H05、PT-H08 多数行
split把混合行为拆给不同 owner:原始行为归 Slate,策略归 Plate"split raw fragment/selection proof from Plate serializers and matchers"PT-H06 的 paste 行
covered/refactor-existing已有契约覆盖,除非缺少 root-aware 变体才补"covered/refactor-existing unless a root-aware variant is missing"PT-H11 的 path/operation 行
plate-owned不进入 Slate v2 执行,路由到 Plate 产品 backlog"plate-owned/refactor-existing only if raw transaction effect hook is accepted"PT-H12 的插件/渲染器行

两条纪律值得注意:一是"refactor-existing before duplicates"——大部分家族要求先强化 Slate v2 已有测试,而不是机械复制外部测试;二是"browser rows require later apply proof"——PT-H07、PT-H06、PT-H09 等浏览器面只承认真实的运行时证据(Playwright),模型推断不足以作为 proof(见计划文档 Open risks)。

六、验证命令解读:bun test 与 Playwright 双轨

路由表最后一列给出了可直接复制的验证命令,分为两条轨道:

轨道一:纯单元/契约测试(bun test)

cd .tmp/slate-v2 && bun test ./packages/slate/test/operations-contract.ts ./packages/slate/test/transforms-contract.ts

这是 PT-H04 / PT-H05 / PT-H11 等单元面的标准命令,一个命令内可并列多个契约文件。命令要求先进入.tmp/slate-v2工作副本——这是收割流程约定俗成的 Slate v2 检出目录(当前仓库根下仅有packages/slate源码包,.tmp/slate-v2由 apply 阶段创建)。PT-H11 家族的完整命令还包含 root-aware 契约家族的四连测:

cd .tmp/slate-v2 && bun test \ ./packages/slate/test/root-location-contract.ts \ ./packages/slate/test/rooted-operation-contract.ts \ ./packages/slate/test/generic-operation-contract.ts \ ./packages/slate/test/operations-contract.ts

轨道二:浏览器集成/压力测试(Playwright + chromium)

cd .tmp/slate-v2 && bun test ./packages/slate-react/test/slate-void-shell-contract.test.tsx && \ PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/editable-voids.test.ts --project=chromium

关键参数语义(结合路由表反复出现的形态归纳):

  • bun test负责 React 层的契约测试(如slate-void-shell-contract.test.tsxprojected-clipboard-contract.test.ts);
  • PLAYWRIGHT_RETRIES=0关闭重试,让失败即时暴露——收割语境下重试会掩盖 flaky 行为;
  • --project=chromium固定浏览器项目,保证跨机器可复现;
  • 集成示例(playwright/integration/examples/*.test.ts)与压力测试(playwright/stress/generated-editing.test.ts)分层,压力行用于 PT-H03/PT-H05 的边界压力面。

不同家族的命令组合在路由表中高度模式化,例如 PT-H01 统一指向selection-rebase-contract.ts+projections-and-selection-contract.test.tsx+view-selection-contract.test.ts,PT-H08 统一指向collab-selection-stress-contract.ts+collab-history-runtime-contract.ts+projected-collab-substrate-contract.test.ts——这相当于为每个家族预定义了"验证处方"。

七、代表性路由案例分析

案例一:PT-H03(void/对象边界)——跨 React 与浏览器双轨验证

gherkin-tests/block-objects.test.ts(孤立图片的方向键、删除、退格场景)被路由为:refactor-existing + 为缺口创建精确的对象边界浏览器行;目标为slate-void-shell-contract.test.tsxplaywright/integration/examples/editable-voids.test.tsplaywright/stress/generated-editing.test.ts。这条路由说明:void 对象边界不变量既要有 React 层契约,也要有浏览器层真实输入证据。

案例二:PT-H06(剪贴板)——split 动作的典型

gherkin-tests/paste.test.tstests/event.paste.test.tsx均为 portable-mixed,动作是 split:"把原始 fragment/选择证据从 Plate 序列化器与 matcher 中拆出"。目标同时列出.tmp/slate-v2的剪贴板契约/粘贴浏览器测试与 "Plate serializer packages"。这就是第二章所述"拆分原则"在具体行上的落地。

案例三:PT-H12(行为管线)——plate-owned 的大本营

tests/behavior-api.test.tsxtests/event.patches.test.tsxrenderer.types.test.tsxpriority.sort.test.ts等 68 行大多标为 plate-owned 或"仅当 raw transaction effect hook 被接受时才重构",验证命令指向transaction-contract.ts(可选)。理由在 inventory.md 中统一表述为 "editor behavior with framework policy mixed in"——事件 API 的 execute/raise/forward/effect 命名是产品 API 压力,不是需要照搬到 raw Slate 的 API。

八、数据来源与可复现性

路由表不是手写清单,而是由可复现流程生成:

  1. 清单命令(记录在 inventory.md):
rg --files ../portabletext \ | rg '(^|/)(__tests__|test|tests|spec|e2e|integration|playwright|cypress|wdio|fixtures)(/|$)|\.(test|spec)\.[cm]?[jt]sx?$' \ | rg -v '(^|/)(dist|build|coverage|node_modules|vendor|fixtures/generated|__snapshots__)(/|$)'
  1. 许可证门:Portable Text 为 MIT/permissive,因此收割产物以 durable 模式落盘在docs/editor-test-harvester/portabletext/(behavior-only 模式才会放入.tmp),并遵循"不复制源文件正文"的卫生约束——产物只记录路径、测试名、行号锚点与全新表述的不变量。

  2. 交叉锚点:test-index.md 为 200 个文件提取了 1944 个file:line name锚点(describe/test/Scenario/Feature),路由表的行号与之一一对应。例如gherkin-tests/delete.test.ts的 15 个锚点直接指向gherkin-spec/delete.feature的 Feature/Scenario 行号。

  3. 验收记录(计划文档 Verification evidence):产物 2026-05-29 重新生成,502 行清单、321 个可运行行、0 新增/0 删除、harvest score 0.94(无维度低于 0.92),并通过autogoal check-complete机械检查。

九、与仓库现状的衔接

  • Slate v2 目标:路由表的目标 owner 集中在.tmp/slate-v2packages/slate/testpackages/slate-react/testpackages/slate-browser/testplaywright/)。当前仓库的 packages/slate 即是 Slate v2 源码本体,收割的 apply 阶段以它为执行基底。
  • Plate 归属:PT-P01/PT-P02 与 PT-H12 的 plate-owned 行指向 Plate 的序列化、列表、schema、插件、工具栏包(如 packages/markdown、packages/html 等目录在 inventory 中大量出现),这些行为不进入 raw Slate 执行。
  • 同类对照:该收割体系同样应用于其他编辑器生态,可参见 docs/editor-test-harvester/tiptap/portable-mixed-routing.md(TipTap 的 63 个 portable-mixed 文件路由),其列结构与判定逻辑一致,便于跨生态横向阅读。

十、给维护者的使用方式

  1. 查行:想知道某个外部测试文件的行为归属,按文件名在路由表Source列检索,得到家族 + 动作 + 验证命令。
  2. 查面:想确认某类行为(如 void 边界、删除矩阵)在 Slate v2 侧是否有覆盖,按Family title聚合,Target owner即覆盖位置清单。
  3. 执行验证:进入.tmp/slate-v2检出后,直接复制Verification / backlog command列运行;浏览器面优先PLAYWRIGHT_RETRIES=0暴露 flaky。
  4. 追溯:需要更细的测试名/场景锚点时,按行号跳转 test-index.md;需要全量分类(含 plate-owned / harness / skip)时读 inventory.md。

需要重申的边界:本文所述 source-routing 是只读分析产物,收割流程明确规定 report-only 阶段不修改.tmp/slate-v2、Plate 包、docs 或构建配置(见计划文档 Constraints 与 Boundaries);所有Source路径属于外部 Portable Text 仓库,不可在当前仓库直接当作文件链接使用。

【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询