- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
导读
本文以 CKEditor 4 仓库中 tests/plugins/tableselection/manual/integrations/link 目录下的一组手动测试用例(text.md、link.md、edit.md)为骨架,系统讲解 Table Selection(表格选择)插件与 Link(链接)插件集成时的三类典型行为:单元格内文本选区打开链接对话框时 Display Text(显示文本)字段的可见性、多单元格批量创建链接以及选中已有链接的单元格时对话框回显已修改的值。读完本文,你将理解这些行为背后的源码机制(fake selection、getSelectedLink、showDisplayTextForElement与对话框onShow逻辑),掌握如何在 Bender 手动测试环境中验证这些回归场景,并了解配套自动化测试的断言方式。
一、背景:为什么需要 Table Selection 与 Link 的集成测试
CKEditor 4 在 4.7.0 版本引入了 Table Selection 插件(对应 CHANGES.md 中记录的#16755),它允许用户用鼠标在表格中选中任意矩形区域——可以是几个单元格、整行或整列,并通过"伪选区"(fake selection)机制将这些单元格在视觉上高亮(通过给单元格添加cke_table-faked-selection类实现,见 plugins/tableselection/plugin.js)。
当用户把 Link 对话框作用于这种"多单元格选区"时,会引入普通文本选区所没有的复杂情况:
- 选区由多个独立 range 组成,Link 对话框需要决定如何批量应用/编辑链接;
- 单元格内选中的是部分文本(如
foo [bar] baz)时,对话框需要决定是否显示"Display Text"字段(该字段允许用户覆盖链接的显示文本); - 对话框中回显已有链接属性时,需要跳过表格场景下可能出现的
<br>填充节点(bogus node)。
正因为这些边界行为容易回归,仓库在tests/plugins/tableselection/manual/integrations/link/下放置了一组配套的手动测试用例,并在tests/plugins/tableselection/integrations/link/下提供了对应自动化测试(link.js)。
二、三个手动测试用例总览
目录 tests/plugins/tableselection/manual/integrations/link 下共有 3 组配对文件(.md为测试步骤说明,.html为测试夹具与编辑器初始化脚本):
| 用例 | 元数据标签 | 核心场景 | 关注点 |
|---|---|---|---|
| text.md | bug, trac16755, 4.7.0, tp2231 | 单元格内部分文本选区 + 快捷键打开链接对话框 | Display Text 字段是否可见 |
| link.md | bug, trac16755, 4.7.0, tp1723 | 多单元格选区创建链接 | 链接是否应用到每个选中单元格 |
| edit.md | bug, trac16755, 4.7.0, tp2245 | 批量建链后再次编辑单个单元格链接 | 对话框是否回显已修改的值 |
三个用例共享同一组插件依赖声明:
@bender-ckeditor-plugins: wysiwygarea, toolbar, tableselection, link, sourcearea, undo, elementspath其中tableselection与link是被测对象,wysiwygarea、toolbar、sourcearea、undo、elementspath提供标准的编辑、撤销与界面支持。
三、用例一(text.md):单元格文本选区下 Display Text 字段的可见性
3.1 测试步骤与判定标准
原用例 text.md 的内容非常精炼,核心操作只有两步:
- 在编辑器内构造形如
foo [bar] baz的选区——即在单元格文本中选中中间的一部分文本; - 按
ctrl/cmd+l快捷键(即 Link 命令的默认热键)打开链接对话框。
判定标准:
- Expected(期望行为):Display Text 字段可见;
- Actual(缺陷行为,即该用例要回归的 bug):Display Text 字段不可见。
3.2 为什么普通文本选区下 Display Text 应该可见
Display Text 字段对应对话框info页中 id 为linkDisplayText的文本输入框(定义见 plugins/link/dialogs/link.js)。它的作用是:当选中一段文本时,允许用户在对话框里额外指定一个"链接显示文本",用于替换选区原本的内容。
对话框onShow处理函数(plugins/link/dialogs/link.js)中的决定逻辑如下:
var data = plugin.parseLinkAttributes( editor, firstLink ); // Here we'll decide whether or not we want to show Display Text field. if ( elements.length <= 1 && plugin.showDisplayTextForElement( firstLink, editor ) ) { displayTextField.show(); } else { displayTextField.hide(); }即同时满足两个条件才显示该字段:选区内命中的链接元素数量不超过 1 个,且showDisplayTextForElement返回true。
3.3 源码级原理:showDisplayTextForElement 的判定规则
showDisplayTextForElement定义于 plugins/link/plugin.js,其判定逻辑是:
- 若选区内的元素属于
img、table、tbody、thead、tfoot、input、select、textarea这类"不希望出现显示文本"的元素,返回false; - 若有 widget 处于聚焦状态("Widget duck typing"),返回
false; - 若
selection.getRanges().length > 1(多 range 选区,典型的表格多单元格选区),返回false; - 其余情况返回
true。
对于foo [bar] baz这样的单元格内普通文本选区,选区是单个 range,选中的是文本节点而非表格元素,因此应当返回true、显示 Display Text 字段。该手动用例正是用来确保此行为在表格单元格场景下不被破坏。
3.4 对应的自动化测试断言
自动化测试 tests/plugins/tableselection/integrations/link/link.js 中的test create link用例与 text.md 场景互补:它选中单个单元格(通过tableSelectionHelpers.getRangesForCells( editor, [ 1 ] )构造 range),打开对话框后断言:
var displayTextField = dialog.getContentElement( 'info', 'linkDisplayText' ) .getElement().getParent().getParent(); assert.isTrue( displayTextField.isVisible(), '"Display Text" field visibility' );而test create link on multiple cells(link.js)选中[1, 2]两个单元格后,断言恰好相反——Display Text 字段不可见,因为多 range 选区触发了showDisplayTextForElement中的ranges.length > 1分支。
四、用例二(link.md):多单元格批量创建链接
4.1 测试步骤与判定标准
link.md 要求在每个编辑器上依次执行:
- 使用 Table Selection 选中多个单元格,例如从 "Cell 1.1.1" 到 "Cell 1.3.1" 的 1×3 纵向选区;
- 点击工具栏上的 Link 按钮;
- 在 URL 输入框中输入
foobar.com; - 点击 OK 提交。
判定标准:
- Expected:链接被应用到每一个选中的单元格;
- Unexpected(缺陷):链接只被应用到第一个单元格。
用例末尾还提供了键盘操作替代方案:"Use test case 1, but instead clicking Link button usectrl/cmd+lhotkey",即用快捷键代替点击按钮重跑一遍,验证两条入口路径行为一致。
4.2 批量插入链接的源码路径
当多单元格选区打开对话框并提交时,onOk处理函数(plugins/link/dialogs/link.js)会先检查this._.selectedElements(由onShow阶段plugin.getSelectedLink( editor, true )收集):由于表格选区下没有已存在的链接,selectedElements为空数组,于是走insertLinksIntoSelection( editor, data )分支。
insertLinksIntoSelection(plugins/link/dialogs/link.js)的核心逻辑是:
- 取
editor.getSelection().getRanges(),表格伪选区对应的是每个单元格一个 range 的多 range 结构; - 遍历每个 range,对非折叠选区先
range.shrink( CKEDITOR.SHRINK_TEXT )收缩选区; - 用
editor.editable().extractHtmlFromRange( range )提取并清空选区内容(该方法比range#deleteContents更擅长处理表格单元格场景,见代码内注释); - 移除 range 内嵌套的
a元素,避免链接叠加; - 最后通过
style.applyToRange( range, editor )将a样式应用到每个 range。
正是"对每个 range 分别 applyToRange"的设计,保证了多单元格批量建链时链接会覆盖所有选中单元格,而非只有第一个。
4.3 自动化测试佐证
test create link on multiple cells(link.js)选中[1, 2]两个单元格,在对话框中设置 URL 为ckeditor.com并点击 OK,随后与夹具 link.html 中table-with-links的期望 HTML 做整树对比:
<td><a href="http://ckeditor.com">Cell 1.2</a></td> <td><a href="http://ckeditor.com">Cell 1.3</a></td>即两个单元格都被包上了a元素,验证了"链接应用到每个选中单元格"这一预期。
五、用例三(edit.md):已有链接单元格的对话框回显(tp2245)
5.1 测试步骤与判定标准
edit.md 验证的是"编辑已有链接"路径,步骤较多:
- 选中第一行的两个单元格;
- 按 "Link" 按钮或
Ctrl/Cmd + L; - 将 URL 设为
foo,并把协议改为https://; - 点击 OK(此时两个单元格各获得一个
https://foo的链接); - 只选中第二个单元格;
- 再次按 "Link" 按钮或
Ctrl/Cmd + L打开对话框。
判定标准:
- Expected:对话框显示的是修改后的值(URL 为
foo、协议为https://); - Unexpected(缺陷):对话框显示的是默认值。
该用例的元数据标签为tp2245,对应源码 plugins/link/plugin.js 中的关键注释:
// Skip bogus to cover cases of multiple selection inside tables (#tp2245). range.shrink( CKEDITOR.SHRINK_ELEMENT, true, { skipBogus: true } );5.2 为什么回显会失败:bogus 节点问题
对话框回显依赖plugin.getSelectedLink( editor, true )(plugins/link/plugin.js)收集选区命中的所有a元素。该方法对每个 range 执行:
range.shrink( CKEDITOR.SHRINK_ELEMENT, true, { skipBogus: true } ); link = editor.elementPath( range.getCommonAncestor() ).contains( 'a', 1 );表格单元格在 CKEditor 中常以<br>作为填充节点(bogus filler)。若不跳过 bogus,收缩后的 range 公共祖先可能落在错误的节点上,导致elementPath().contains( 'a' )找不到链接,getSelectedLink返回空——对话框于是拿不到任何已有链接,parseLinkAttributes只能回显默认值。这正是 edit.md 中 "Unexpected: Default values are shown" 的根因,skipBogus: true是它的修复。
自动化测试test get link info from the cell with <br> filler(link.js)直接复现该场景:夹具table-with-br的单元格内容是<a href="https://cksource.com">Cell 1.1</a><br>(见 link.html),选中该单元格后断言对话框中 URL 为cksource.com、协议为https://——与手动用例 edit.md 的期望完全一致。
5.3 编辑回显的完整链路
当getSelectedLink成功收集到链接后,onShow中(plugins/link/dialogs/link.js)还会做一件事:若选中了唯一的、带href的链接,且当前不是表格选区(!selection.isInTable()),则把真实选区收拢到该链接元素上,以免破坏表格的伪选区;随后parseLinkAttributes填充对话框各字段,点击 OK 后走editLinksInSelection(plugins/link/dialogs/link.js 起)批量改写每个a元素的属性。
自动化测试中的test edit link (text selected)(link.js)与test getSelectedLink for table selection (links)(link.js)进一步验证:多单元格选区下getSelectedLink( editor, true )能返回全部链接(断言links.count() === selectedLinks.length,且逐个元素相等),且修改 URL 后所有单元格的链接都被同步更新。
六、测试环境与运行方式
6.1 三种编辑器形态的夹具
三个手动用例的.html夹具结构一致,均包含三种编辑器形态(以 text.html 为例):
- Classic editor:
CKEDITOR.replace( 'editor1' ),默认的 iframe 式编辑器; - Divarea editor:
CKEDITOR.replace( 'editor2', { extraPlugins: 'divarea' } ),通过divarea插件把编辑区渲染为div而非 iframe; - Inline editor:
CKEDITOR.inline( 'editor3', { extraPlugins: 'floatingspace' } ),页面内联编辑,配合floatingspace提供浮动工具栏。
三个用例都要求在这三种形态上重复执行,确保行为与编辑器容器实现无关。
6.2 Bender 测试标签与环境跳过
每个.md文件的头部是 Bender 手动测试的元信息:
@bender-ui: collapsed:测试运行器默认折叠 UI 元素;@bender-tags: bug, trac16755, 4.7.0, tp2231(text 用例):标记为 bug 回归用例、关联 trac 工单16755、目标版本4.7.0、内部跟踪号tp2231(link 用例为tp1723,edit 用例为tp2245);@bender-ckeditor-plugins: ...:声明测试所需的插件列表。
夹具脚本中还有两处环境保护(见 text.html):
if ( bender.tools.env.mobile ) { bender.ignore(); } bender.tools.ignoreUnsupportedEnvironment( 'tableselection' );即移动端环境直接忽略该测试,且在不支持tableselection插件的浏览器(如旧版 Safari 等)上自动跳过。测试分组与运行配置定义在 bender.js(如'Plugins'组以tests/plugins/**为扫描路径)。
七、回归意义与测试体系小结
把三个手动用例放在一起看,它们覆盖了 Table Selection × Link 集成的三条关键行为链:
- text.md(tp2231):单元格内部分文本选区 → Display Text 字段应可见,防止
showDisplayTextForElement在表格场景误判; - link.md(tp1723):多单元格选区 → 新建链接应覆盖全部单元格,防止
insertLinksIntoSelection只处理第一个 range; - edit.md(tp2245):已链接单元格 → 对话框应回显真实值,防止 bogus 节点导致
getSelectedLink空返回。
这三条链路在 plugins/link/plugin.js、plugins/link/dialogs/link.js 与 plugins/tableselection/plugin.js 中均有对应实现,并且都被 tests/plugins/tableselection/integrations/link/link.js 的自动化用例以 HTML 断言或对话框字段断言的方式固化下来。手动测试用于人工验证交互体验,自动化测试用于持续回归,两者互为补充——这也是 CKEditor 4 测试体系处理复杂插件交互的典型模式。
八、扩展阅读:相关的自动化测试工具函数
手动用例依赖的选区构造逻辑,在自动化侧由 tests/plugins/tableselection/_helpers/tableselection.js 提供:tableSelectionHelpers.getRangesForCells( editor, cellsIndexes )遍历td, th并分别为指定下标单元格创建setStartBefore/setEndAfter的 range,从而在测试中精确模拟 Table Selection 的多 range 选区;markCells则可为单元格添加标记类以便断言。理解这两个辅助函数,有助于把本文的手动步骤翻译成可重复的自动化断言。
- 前端
- UI组件
【免费下载链接】ckeditor4
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.
相关推荐
CKEditor 4 Table Selection 与 Link 插件集成:多单元格批量加链接的实现原理与手动测试指南
CKEditor 4 Table Selection 与 Link 插件集成:多单元格批量加链接的实现原理与手动测试指南 导读 本文围绕仓库中 tests/pl
前端UI组件CKEditor 4 image2 与 link 插件集成:Link 对话框 Display Text 字段的显隐机制与手动验证指南
CKEditor 4 image2 与 link 插件集成:Link 对话框 Display Text 字段的显隐机制与手动验证指南 导读 本文围绕 CKEdi
前端UI组件CKEditor 4 Table Selection 插件单元格选择光标(cursor: cell)的实现与手动测试指南
CKEditor 4 Table Selection 插件单元格选择光标(cursor: cell)的实现与手动测试指南 导读 本文以 CKEditor 4 仓
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考