Plate 项目 Lexical 测试收割:用可移植测试索引驱动 Slate v2 行为移植
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
导读
本文讲解 plate 仓库中docs/editor-test-harvester/lexical/这套"测试收割"(test harvest)工作流的核心索引——test-index.md:它以文件级分类(category)、行为家族(family)与落地目标(target)三要素,把上游 Lexical 仓库中 137 个可移植测试文件、1996 个test/describe/it行为指针组织成一张可检索、可审计的移植地图。读完本文,你将掌握这份索引的结构与行指针语义、它与全量清单(inventory.md)和处理台账(slate-processing-ledger.md)如何协同,以及如何在本仓库中用它定位"哪些上游行为值得移植、哪些应拒绝、哪些归 Plate 所有",为 Slate v2 的测试基建做 source-read 与 apply 决策。
一、收割工作流的整体布局:三份文档如何分工
在 docs/editor-test-harvester/lexical 目录下共有三份相互引用的文档,构成一条完整流水线:
| 文档 | 作用 | 与 test-index.md 的关系 |
|---|---|---|
| inventory.md | 全量清单:用一条rg命令枚举上游 Lexical 仓库所有测试文件并逐一分类 | 是索引的上游;只有被标记为portable或portable-mixed的 runnable 文件才会进入索引 |
| test-index.md | 可移植测试名称索引:为每个可移植文件提取全部test/describe/it行,给出文件:行号指针 | 本文主体;inventory.md明确声明"portable 与 portable-mixed 的可运行行已收录进 test-name index" |
| slate-processing-ledger.md | 处理台账:为每个索引文件给出already-applied/covered/defer/plate-owned/reject等最终裁决 | 是索引的消费端;用索引的行指针做 source-read,再回填裁决 |
索引头部自带 provenance 元数据:source report: ./report.md(报告文件不在本仓库内,属于上游生成物)、target: ../lexical(指向被收割的上游 Lexical 源码树,同样不在 plate 仓库内)、generated_at: 2026-05-08、last_consolidated_at: 2026-05-09。头部还记录了合并校验结果:可运行可移植文件数仍为 137、提取行数仍为 1996,无缺失或过期索引文件——这保证了索引与上游源码的同步性可被持续复核。
二、索引规模与质量底线:137 个文件、1996 个行为指针
test-index.md在头部给出三个关键统计,这是评估移植工作量的第一手数据:
Indexed runnable portable and portable-mixed files: 137. Extracted test/describe/it lines: 1996. Files with zero extracted names: 0.解读:
- 137 个文件:全部是
inventory.md中判定为portable(124 个)或portable-mixed(13 个)的可运行文件。product-shell(33)、harness(12)、skip(89)三类被排除在索引之外。 - 1996 行指针:每个指针形如
路径:行号+describe/test/it: 标题,粒度到单个测试用例。 - 0 个空文件:不存在"有文件但未提取到任何测试名"的漏网之鱼,索引完整性有硬性校验。
此外头部特别说明了一个提取器细节:提取器按行指针记录 literal(字面量)、dynamic(动态模板)和 multiline(多行)标题。dynamic 行(如test: testing ${scenario[2]}: ...)仍需在 apply 前阅读本地源码以还原真实语义,但它们不再被"仅按文件名路由"的方式隐藏——也就是说,索引保证了每条动态标题至少有一个可追溯的锚点(文件:行号),读者可以回到源码展开模板变量。索引中大量dynamic or multiline title占位即属于此类,例如AutoLinks.spec.mjs:33、Composition.spec.mjs:176、LexicalMarkdown.test.ts:818。
三、文件条目的三要素元数据:category / family / target
每个文件条目在测试清单之前固定给出三行元数据,这是本索引最有操作价值的部分。以第一个条目为例:
## `../lexical/packages/lexical-code-shiki/src/__tests__/unit/LexicalCodeNodeTabs.test.ts` category: portable family: core package behavior target: .tmp/slate-v2/packages/slate/test; add focused browser proof only when behavior depends on DOM/runtime transportcategory:移植可行性等级
索引中实际出现的取值有portable与portable-mixed两种(这也是它叫"Portable Test-Name Index"的原因):
portable:文件中的行为可在纯模型层验证,优先落入 Slate v2 的packages/slate/test,属于"直接可移植";portable-mixed:文件是产品/插件 e2e 或混合场景,但其中包含可分离的便携不变量(invariant)。例如AutoLinks.spec.mjs、Autocomplete.spec.mjs、CharacterLimit.spec.mjs等被标为portable-mixed,其 target 通常是"packages/slate/test;仅当行为依赖 DOM/运行时传输时才补充浏览器证明"。
注意:portable-mixed不等于拒绝。台账里对混合文件的做法是"从产品文件中拆分出原始不变量"(split a raw invariant out of a product file)。
family:行为家族
family把 137 个文件归并到少量语义桶,便于按主题批量检索。结合 inventory.md 的完整行表,可以归纳出以下家族及其在索引中的分布:
| family | 代表文件 | 说明 |
|---|---|---|
core package behavior | LexicalCodeNode.test.ts、LexicalHistory.test.tsx、LexicalHtml.test.ts、LexicalHeadingNode.test.ts、LexicalQuoteNode.test.ts、lexical-list/src/__tests__/unit/utils.test.ts | 核心包/编辑器单元行为,多数 target 指向packages/slate/test |
serialization-parsing / marks-inline | LexicalListItemNode.test.ts、LexicalListNode.test.ts、formatList.test.ts、LexicalMarkdown.test.ts、CodeBlock.spec.mjs、TextFormatting.spec.mjs、ClearFormatting.spec.mjs、ElementFormat.spec.mjs、Headings*.spec.mjs、Indentation.spec.mjs、List.spec.mjs、Markdown.spec.mjs | 序列化/解析/富文本格式,通常同时指向slate/test、slate-history/test与 playwrightrichtext.test.ts |
clipboard-paste / browser-engine | HTMLCopyAndPaste.spec.mjs、ImageHTMLCopyAndPaste.spec.mjs、LinksHTMLCopyAndPaste.spec.mjs、ListsHTMLCopyAndPaste.spec.mjs、TablesHTMLCopyAndPaste.spec.mjs、TextFormatHTMLCopyAndPaste.spec.mjs、ContextMenuCopyAndPaste.spec.mjs、CopyAndPaste.spec.mjs、ListsCopyAndPaste.spec.mjs、Extensions.spec.mjs、LexicalTabNode.test.ts*、HTMLCopyAndPaste.test.ts | 剪贴板与粘贴,target 指向slate/test/clipboard-contract.ts、slate-dom/test/clipboard-boundary.test.ts、playwrightpaste-html.test.ts |
selection-dom-mapping / void-atom | AutoLinks.spec.mjs、Hashtags.spec.mjs、HorizontalRule.spec.mjs、Keywords.spec.mjs、Links.spec.mjs、Mentions.spec.mjs、Navigation.spec.mjs、Selection.spec.mjs、LexicalSelection.test.*、LexicalCaret.test.ts | 选择/DOM 映射与 void/原子节点,target 增加slate-react/test/editable-behavior.test.tsx |
beforeinput-input / browser-engine | AutoScroll.spec.mjs、Events.spec.mjs、Focus.spec.mjs、Keyboard.spec.mjs、KeyboardShortcuts.spec.mjs、Mutations.spec.mjs、TextEntry.spec.mjs | 输入运行时,target 指向slate-react/test/model-input-strategy-contract.test.ts与 playwright stress |
ime-composition / history-undo-redo | Composition.spec.mjs、regression/8153-safari-ime-delete-selection.spec.mjs | IME 合成与撤销栈,target 增加slate-browser/src/playwright/ime.ts与slate-history/test |
collaboration-remote / history-undo-redo | Collaboration.spec.mjs | 协作,target 为slate/test/collab-history-runtime-contract.ts+ 未来 slate-yjs 浏览器车道 |
tables-grid / selection-dom-mapping | Tables.spec.mjs、LexicalTableCellNode.test.ts、LexicalTableNode.test.tsx、LexicalTableSelection.test.tsx、LexicalTableUtils.test.ts等 | 表格,target 指向 playwrighttables.test.ts与slate/test/transforms/insertFragment |
portable editor behavior | DraggableBlock.spec.mjs、Images.spec.mjs、Placeholder.spec.mjs、Tab.spec.mjs、绝大多数regression/*.spec.mjs | 通用便携编辑行为,多数仅指向packages/slate/test |
mixed portable invariant | Autocomplete.spec.mjs、CharacterLimit.spec.mjs、ColumnLayoutBackspaceAtEnd.spec.mjs、DateTime.spec.mjs、Emoticons.spec.mjs、EquationNode.spec.mjs、MaxLength.spec.mjs、SpecialTexts.spec.mjs、Toolbar.spec.mjs | 混合便携不变量,target 为packages/slate/test+ 按需浏览器证明 |
target:落地坐标
target明确给出"这份文件的行为应该移植到哪里"。它反复出现的几种坐标在 slate-processing-ledger.md 的"Current Slate Owners"一节有完整定义:
| Slate 所有者 | 路径 |
|---|---|
| 核心模型与查询不变量 | .tmp/slate-v2/packages/slate/test |
| 剪贴板模型/DOM 契约 | .tmp/slate-v2/packages/slate/test/clipboard-contract.ts、.tmp/slate-v2/packages/slate-dom/test/clipboard-boundary.ts |
| 文本单元 | .tmp/slate-v2/packages/slate/test/text-units-contract.ts |
| 输入运行时策略 | .tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts |
| DOM 修复策略 | .tmp/slate-v2/packages/slate-react/test/dom-repair-policy-contract.ts |
| 浏览器压力行 | .tmp/slate-v2/playwright/stress/generated-editing.test.ts |
| 粘贴 HTML 浏览器语料 | .tmp/slate-v2/playwright/integration/examples/paste-html.test.ts |
| 富文本浏览器行为 | .tmp/slate-v2/playwright/integration/examples/richtext.test.ts |
| 表格浏览器包含性 | .tmp/slate-v2/playwright/integration/examples/tables.test.ts |
| 协作/历史基座 | .tmp/slate-v2/packages/slate/test/collab-history-runtime-contract.ts、.tmp/slate-v2/packages/slate-history/test/history-contract.ts |
值得注意的规则:默认优先落在模型层packages/slate/test,只有当行为依赖 DOM/运行时传输时才补浏览器证明("add focused browser proof only when behavior depends on DOM/runtime transport")。这是整个收割策略的基石——先锁模型不变量,再按需加浏览器行。
四、行指针的语义与检索方式
索引的每一行测试记录格式统一为:
- `../lexical/<包>/<路径>.test.ts:<行号>` describe/test/it: <标题>三种前缀分别对应测试框架的三层结构:
describe:测试分组(如LexicalCodeNode tests、Tabs、Markdown、ListExtension);test/it:具体用例(二者等价,it是 BDD 风格别名,索引同时保留两种原样拼写,例如LexicalListItemNode.test.ts:1296的it: indents and outdents list item);- 标题可能是 literal、dynamic(含
${...}模板)或 multiline(跨行)。
文件:行号指针是关键——它允许任何 Agent 或工程师通过search_in_files或直接read_file回到上游源码做source-read(通读源码),还原 dynamic 标题的真实参数矩阵。例如LexicalCodeNodeTabs.test.ts:96的testing ${scenario[2]}: ${scenario[0]} => ${scenario[1]} (${direction}),必须在源码中展开scenario数组才能知道它覆盖了哪些 Tab 缩进方向组合。
五、按家族深入:索引覆盖的行为全貌
以下按家族给出索引中的代表性文件与其核心用例,全部取自test-index.md的真实行指针(行号即索引中记录的上游行号)。
5.1 核心包行为(core package behavior)
- 代码块 Tab:LexicalCodeNodeTabs.test.ts(code-shiki) 47/49/96 行覆盖 describe
LexicalCodeNode tests/Tabs与场景化 Tab 用例;lexical-code包的同名文件结构相同。LexicalCodeNode.test.ts是索引中最长的核心文件之一,覆盖构造、createDOM/updateDOM、exportJSONschema、insertNewAfter、$createCodeNode,以及大量 Tab/缩进用例:can tab with collapsed/non-collapsed selection(179/215)、单行/多行 indent/outdent(239/279/319/357)、code blocks can shift lines(459/479)、arrows与rtl code lines(513/514)下的MOVE_TO_END/MOVE_TO_START视觉移动(537/559),以及回归can be registered after initial editor state (regression #7014)(1007)。 - 历史:
LexicalHistory.test.tsx覆盖after clearing、Redo after Quote Node、change, undo, redo, undo, change序列(352)、undoStack selection points to the same editor(437)、Changes to TextNode leaf are detected properly #6409(481),以及SharedHistoryExtension父编辑器创建(541/542)。 - HTML 序列化:
LexicalHtml.test.ts覆盖[Lexical -> HTML]的具名用例(42)、Use provided selection(64)、Default selection (undefined) should serialize entire editor state(111)、段落对齐优先级(186)、DocumentFragment导出(216)。 - 富文本节点:
LexicalHeadingNode.test.ts覆盖构造/DOM/insertNewAfter空/中/尾(101/123/147)、setTag(173)、h2 插入段落后(219);LexicalQuoteNode.test.ts覆盖 QuoteNode 全生命周期。 - 工具:
lexical-list/src/__tests__/unit/utils.test.ts覆盖 1/2/5 层列表深度(17/35/68)、getTopListNode直接/非直接/深层嵌套(113/144/176)、isLastItemInList四种嵌套组合(214/249/275/310)。LexicalUtilsInsertNodeToNearestRoot.test.tsx与LexicalUtilsSplitNode.test.tsx覆盖最近根插入与 split 抛错。
5.2 序列化、解析与标记(serialization-parsing / marks-inline)
- 列表:
LexicalListItemNode.test.ts是索引中行数最密集的文件之一,覆盖构造/DOM、replace()首/中/尾/唯一项(239/294/323/354)、remove()的兄弟嵌套矩阵(401/469/549/629/718/828/939)、insertNewAfter()非空列表项(1063-1204)、setIndent()与小数缩进(1296/1356)、列表分割编号重置/保留(1415/1455)。LexicalListNode.test.ts覆盖append()/splice()包装转换(214-308)、checklist 转 bullet(341)、嵌套清理(367)、子类化$config(462)。 - 列表格式化:
formatList.test.ts覆盖insertList的空/有子 root 选择(84/106)、shadow root 选择(131)、$handleListInsertParagraph空项退出/空白退出/非空白扩展/装饰器扩展/分割(235-343)、$handleIndent嵌套子表创建(389)、$handleOutdent嵌套移除(424)。 - Markdown:
LexicalMarkdown.test.ts覆盖嵌套代码围栏往返(1044/1080)、动态围栏计算(1117)、list marker 记忆(1146-1217)、Enter 触发(1246-1326)、normalizeMarkdown的shouldMergeAdjacentLines两档(1381/1507)、硬换行导入(1601/1641)、空白保留默认模式(1682-1747)。MarkdownTransformers.test.ts覆盖 LINK 前置文本保留(53/68)、贪婪抑制(90)、链接内不建链接(123)。 - 清除格式:
ClearFormatting.spec.mjs覆盖 BIU 清除(39)、链接/引文样式保留(60)、hashtag/mention 保留(107)、对齐与缩进清除(188-252)、跨段落清除(279)。 - 代码块 e2e:
CodeBlock.spec.mjs覆盖 markdown 建块(36)、已有文本包裹(108)、多段/部分段落转换(173/234)、行内转换(300)、语言切换(351)、缩进保持(423)、Tab 行缩进(515)、多行 (un)indent(603)、option+arrow行移动(924)、边界选择防护(1111)、CMD/Ctrl+Left/Right(1267)。 - 标题/引用/格式 e2e:
HeadingsBackspaceAtStart.spec.mjs(19)、HeadingsEnterAtEnd.spec.mjs(18)、HeadingsEnterInMiddle.spec.mjs(23)分别锁定首标题 Backspace 无操作、末尾 Enter 变段落、中间 Enter 分裂;ElementFormat.spec.mjs覆盖链接内缩进/对齐(26)与空段居中(59);Indentation.spec.mjs覆盖最大深度(461-1007)与负缩进回归(1007);List.spec.mjs覆盖 checklist 焦点选项(79/120)、嵌套列表、backspace 出缩进(224/316)、类型互转(1446-1831)、markdown 起始编号(2270)、空项 Enter 出表(2318)等;Markdown.spec.mjs覆盖样式化 markdown 快捷输入(219-333)、undo/redo(308)、内嵌转换(763-1055)、list marker 保持(1055/1069)。 - 文本格式:
TextFormatting.spec.mjs覆盖加粗/斜体快捷键(39/93)、选中加粗(147)、三连击不污染下段(203)、字号增减(532-639)、字体族(660)、多段选择格式化(817)、回归 #2439(1093)、工具栏激活态(1144)、#2523(1182)、多行忽略换行(1240)。
5.3 剪贴板与粘贴(clipboard-paste / browser-engine)
索引中有一整组CopyAndPaste语料:
- HTML 语料(
CopyAndPaste/html/):HTMLCopyAndPaste.spec.mjs覆盖多行 HTML 额外换行(25)、带 BR 的代码块(53)、段落夹在水平线之间(135)、段落中间贴顶层元素(199);ImageHTMLCopyAndPaste.spec.mjs覆盖 figure+figcaption(31)、图片粘贴(134)、多图粘贴+undo(172);LinksHTMLCopyAndPaste.spec.mjs覆盖 anchor 粘贴(37)、链接前/后粘贴(99)、局部内容选择粘贴(130)、空链接 #3193(166)、文本进链接/链接进文本/格式化文本进链接/链接进链接/多块进链接(213-366);ListsHTMLCopyAndPaste.spec.mjs覆盖列表元素(24)、Lexical 嵌套列表(93)、直接嵌套 ul(129)、li 混合内容(217)、checklist(299)、列表中段中间贴(372)、列表内嵌套 div(425);TablesHTMLCopyAndPaste.spec.mjs覆盖 Google Docs(24/95)、Quip(161)、Google Sheets(233)、Merge Grids(306)、嵌套块与行内 HTML(434)、合并单元格与不等行(534)、空行(691);TextFormatHTMLCopyAndPaste.spec.mjs覆盖 BIU(20)与 highlight(70)。 - Lexical 原生语料(
CopyAndPaste/lexical/):ContextMenuCopyAndPaste.spec.mjs(29/56)覆盖右键复制粘贴;CopyAndPaste.spec.mjs覆盖基础复制(35)、标题复制(222)、段落进引用(875)、Google Docs/MS Word 字号(905/933)、剪切空选区保留剪贴板(965);ListsCopyAndPaste.spec.mjs覆盖部分列表项复制(33/139)、列表内粘贴(280-533)、列表末段落(766)。
5.4 IME、合成与输入运行时(ime / beforeinput / input)
Composition.spec.mjs是 IME 语料最全的文件:平假名(35)、阿拉伯语变音符(88)、IME 输入平假名(174)、行间(258)、加粗内(371)、emoji 间(445)、mention 尾/中部(636/746)、mention 后打字不破坏(852)、hashtag(920)、撤销取消(1078)、浮动工具栏不显示(1211)、typeahead 不关闭(1276)、韩语多节点替换(1325)。AutoScroll.spec.mjs:输入时自动滚动(17)。Events.spec.mjs:macOS 自动大写(21)、emoji 后双空格句号 #3953(96)。Focus.spec.mjs:Tab 移出编辑器(20)、点击外部保持选择(34)。Keyboard.spec.mjs与KeyboardShortcuts.spec.mjs:格式/对齐/字号快捷键、清格式、代码块切换、缩进(186-335)。Mutations.spec.mjs:文本 mutation 观察器管理选择(53)、DOM 恢复(156)。TextEntry.spec.mjs:文本插入替换(49)、段间插段(113)、单词删除(353)、首段 backspace(395)、空段与新行选择(600)。- 回归
8153-safari-ime-delete-selection.spec.mjs:Safari IME 结束后 Cmd+A 全选删除(39)、Shift+ArrowUp 多段删除(73)。
5.5 选择、内联原子与 void(selection-dom-mapping / void-atom)
AutoLinks.spec.mjs:URL 化文本转链接(32)、邮箱(63)、非空格破坏链接(92)、粘贴 URL 建链(156/191)、去重(225)、多链接(263/300)、非法链接拒绝(607/655)、unlink 再 link(694)、标点保留(755)、emoji 破坏(896)、Enter 不插多余段(955)。Hashtags.spec.mjs:单个/相邻/批量 hashtag(30/90/195)、格式继承(269)、无效 hashtag 跳过 #5703(329)、粘贴多匹配(420)、导入导出多匹配(444)。HorizontalRule.spec.mjs:创建并移动选择(37)、文本节点尾加 HR(158)、中间分裂文本(210)、列表内分裂(272/341)、复制粘贴(399)、空段删除保留 HR(489)。Images.spec.mjs:装饰器创建与选择移动(40)、增删(219)、任意 URL 添加(391)、拖放(442/535)、选择同步 #2901(577)、Node selection 多选替换(615)、尺寸计算(770)、SVG 渲染(820)。Keywords.spec.mjs、Links.spec.mjs、Mentions.spec.mjs、Navigation.spec.mjs、Selection.spec.mjs、SelectionAlwaysOnDisplay.spec.mjs分别覆盖关键词装饰器、链接全生命周期(转换/段落边界插入/Enter/图片链接/属性粘贴,39-2411)、mention 输入删除矩阵、键盘导航(段落/行/词/emoji 逐词)、选择全域(焦点、行删除、RTL 装饰器、表格选择包含、格式持久化)、失焦保留选择。- 单元层:
LexicalSelection.test.tsx、LexicalSelectionHelpers.test.ts、$sliceSelectedTextNodeContent.test.ts、LexicalCaret.test.ts、docs-traversals.test.ts覆盖选择克隆/切片/rebasing、样式补丁、块类型设置、caret 遍历与点排序。
5.6 表格(tables-grid)
Tables.spec.mjs是索引中最大的单文件(193 行指针),覆盖工具栏插入(93)、单元格输入(137)、首/末格退出(185/231)、嵌套表退出(276/304)、键盘导航(622-761)、Table selection 选择/样式/复制/清除(795-1244)、合并/拆分单元格(2013-3077)、行列插入删除与合并冲突(3222-4263)、列头合并(4521)、粘贴嵌套表开关(5841-7127)、RTL/范围选择包含(7638-7909)。单元层LexicalTableCellNode.test.ts覆盖<th>scope 头推断(285-350)、LexicalTableExtension.test.ts覆盖嵌套表开关(101/141)与colWidths规整(366-410)、LexicalTableMobileSelection.test.tsx覆盖触摸选择、LexicalTableUtils.test.ts覆盖列移动与越界 no-op。
5.7 回归族(regression/*)
索引收录了 20+ 个按 issue 号命名的回归文件,是"历史缺陷即行为资产"的体现:1055-fast-typing-undo、1083-backspace-with-element-at-front、1113-link-newline-at-end、1258-delete-forward、1384-insert-nodes、1730-delete-backword、221-editing-hashtags、230-navigation-around-hashtags、231-empty-text-nodes、3136-insert-nodes-adjacent-to-inline、3433-merge-markdown-lists、379-backspace-with-mentions、399-open-line、429-swapping-emoji、4661-insert-column-selection、4697-repeated-table-selection、4872-full-row-span-cell-merge、4876-unmerge-cell、5251-paste-into-inline-element、5583-select-list-followed-by-element-node、6870-table-left-arrow-selection、6974-delete-character-backward、7163-graphemes、7246-delete-character-backward-list、7266-column-header-merged-cells、7319-delete-character-backward-nodeselection、7354-firefox-decorator-paste、7635-SELECTION_INSERT_CLIPBOARD_NODES_COMMAND、8153-safari-ime-delete-selection。这些文件通常在family上归类为portable editor behavior、selection-dom-mapping / void-atom或ime-composition / history-undo-redo。
六、与 inventory.md 的配合:分类如何决定"进不进索引"
inventory.md 的核心是一条可复现的清单命令:
rg --files ../lexical \ | 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__)(/|$)'第一段枚举测试路径,第二段匹配测试目录/文件命名,第三段排除构建产物与快照。运行结果给出封闭计数:
Counts: total 271; runnable 196; fixture/support 75; portable 124; portable-mixed 13; product-shell 33; harness 12; skip 89; uncertain 0.分类决策树(由Reason列可见):
portable:包单元行为带便携不变量 → 进入 test-index.md;portable-mixed:产品/插件 e2e 但含便携不变量行 → 进入 test-index.md;product-shell:示例应用/框架集成外壳 → 不进索引,除非日后拆出原始不变量;harness:测试辅助工具 → 只借技术,不借行为;skip:工具链/打包/发布/ESM fixture/eslint 插件等 → 无 Slate target;uncertain:0 行,无争议。
清单还提供Plate-Owned Overlay路由表,例如lexical-link/src/__tests__/*与AutoLinks.spec.mjs归 Plate link/autolink 包;lexical-list与List.spec.mjs归 Plate list/checklist;lexical-markdown与Markdown.spec.mjs归 Plate markdown 序列化包;Hashtags/Keywords/DateTime/Emoticons/EquationNode/CharacterLimit/Images 归 Plate 特性插件包;React Composer/typeahead/工具栏外壳归 Plate React 人体工学。这条规则与台账的plate-owned状态一一对应。
七、与 processing-ledger 的配合:从索引到裁决的闭环
slate-processing-ledger.md 是索引的消费产物,其状态词汇表(Status Vocabulary)必须与索引配合理解:
| 状态 | 含义 |
|---|---|
already-applied | 所选 apply 车道已添加或加强对应 Slate v2 证明 |
covered | 现有 Slate v2 已有足够证明行,除非后续审计发现漂移 |
refactor-existing | 加强/拆分/重命名现有 Slate 测试,优先于复制 |
create-new | 新增 Slate v2 单元/浏览器行 |
defer | 行为有效,但需要真机设备、yjs 浏览器、表格模型或后续 owner |
plate-owned | 行为应归 Plate 而非原始 Slate,需指明 Plate 包/文档/示例/backlog owner |
reject | 非便携的原始 Slate 行为目标 |
台账的总体裁决(Verdict)与索引完全对齐:271 个清单行、137 个可运行 portable/portable-mixed 文件、1996 个行指针全部被说明,无遗漏、无过期、无未解决行。核心方法论是一句话:"Do not copy Lexical tests one-for-one. Keep the invariant, steal the strongest proof shape, and reject Lexical internals."(不要一对一复制 Lexical 测试;保留不变量、借鉴最强证明形态、拒绝 Lexical 内部实现细节。)
台账用"Row-Level Source Read"子节展示了索引行指针如何被消费:例如LexicalHistory.test.tsx:352(change, undo, redo, undo, change)→already-applied,新增证明"undo 后的新编辑清除 redo 历史且 redo 变为 no-op";LexicalHtml.test.ts:64(Use provided selection)→covered(现有writeSelection证明已覆盖);CodeBlock.spec.mjs:173(多段转代码块)→covered/refactor-existing(快照 wrap 与浏览器控制已覆盖)。这说明索引不只是目录,而是每一条裁决的追溯依据。
台账末尾给出未来 apply 切片的验证门控命令(verification gates,路径指向外部.tmp/slate-v2工作树,作为说明保留):
cd /Users/zbeyens/git/slate-v2 bun test ./packages/slate/test/text-units-contract.ts bun test ./packages/slate-dom/test/clipboard-boundary.ts bun test ./packages/slate-history/test/history-contract.ts PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/paste-html.test.ts --project=chromium PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/tables.test.ts --project=chromium PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/stress/generated-editing.test.ts --project=chromium -g '<accepted-family>' bun check以及真机设备证明门控:
cd /Users/zbeyens/git/slate-v2 SLATE_BROWSER_RAW_MOBILE_REQUIRED=1 bun test:mobile-device-proof:raw八、实操指南:在本仓库中使用这份索引
- 按家族检索:若你在为 Slate v2 的"选择/内联原子"层补测试,先用
search_in_files在 docs/editor-test-harvester/lexical/test-index.md 中检索family: selection-dom-mapping / void-atom,即可一次性拿到该家族全部候选文件与其target坐标。 - 定位具体行为:用
文件:行号指针回到上游源码做 source-read,还原 dynamic/multiline 标题的真实参数;把不变量与 Slate 现有契约对比。 - 对照裁决:打开 slate-processing-ledger.md,按文件名查该行为的最终状态——
already-applied/covered表示已有归属,defer/plate-owned/reject表示不要直接移植。 - 校验清单:需要确认上游是否新增测试文件时,重跑 inventory.md 中的
rg清单命令,再比对索引头部的 137/1996 统计。 - 执行验证:apply 后按台账的验证门控命令跑模型层
bun test与 Playwright 浏览器行,最后bun check通过才视为闭环。
结语
test-index.md不是一份普通的测试清单,而是 plate 项目"跨编辑器收割"工程方法的浓缩:用category判断可移植性、用family聚合行为主题、用target指定落地坐标、用文件:行号指针保证每条行为都可回源审计。它与 inventory.md(全量分类)和 slate-processing-ledger.md(逐行裁决)共同构成一条"枚举 → 索引 → source-read → 裁决 → apply → 验证"的完整流水线。对于任何想要为 Slate v2 补齐可移植行为证明、或理解 plate 如何吸收上游编辑器测试资产的开发者,这份索引都是入口,而其背后的方法论同样适用于本仓库对 portabletext、prosemirror、tiptap、yjs-collaboration 等其他编辑器家族的收割工作(见 docs/editor-test-harvester 目录结构)。
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考