Unit Testing Plate
学习如何对 Plate 编辑器和插件进行单元测试。
本指南概述了使用 @udecode/plate-test-utils
对 Plate 插件和组件进行单元测试的最佳实践。
Installation
npm install @udecode/plate-test-utils slate-hyperscript
设置测试
在测试文件顶部添加 JSX pragma:
/** @jsx jsx */
import { jsx } from '@udecode/plate-test-utils';
jsx; // so ESLint doesn't complain
这允许你使用 JSX 语法来创建编辑器的值。
创建测试用例
编辑器状态表示
使用 JSX 来表示编辑器状态:
const input = (
<editor>
<hp>
Hello<cursor /> world
</hp>
</editor>
) as any as PlateEditor;
节点元素如 <hp />
、<hul />
、<hli />
代表不同类型的节点。
特殊元素如 <cursor />
、<anchor />
、<focus />
代表选区状态。
测试转换
- 创建输入状态
- 定义预期的输出状态
- 使用
createPlateEditor
或createPlateTestEditor
来设置编辑器 - 应用转换
- 断言编辑器的新状态
以下是测试粗体格式化的示例:
it('should use custom hotkey for bold', async () => {
const input = (
<editor>
<hp>
Hello <anchor />
world
<focus />
</hp>
</editor>
) as any as PlateEditor;
const output = (
<editor>
<hp>
Hello <htext bold>world</htext>
</hp>
</editor>
) as any as PlateEditor;
const [editor, { triggerKeyboardEvent }] = await createPlateTestEditor({
editor: input,
plugins: [
BoldPlugin.configure({
handlers: {
onKeyDown: ({ editor, event }) => {
if (event.key === 'b' && event.ctrlKey) {
editor.tf.toggle.mark({ key: 'bold' });
}
},
},
}),
],
});
await triggerKeyboardEvent('mod+b');
expect(editor.children).toEqual(output.children);
});
测试选区
测试操作如何影响编辑器的选区:
it('should collapse selection on backspace', async () => {
const input = (
<editor>
<hp>
He<anchor />llo wor<focus />ld
</hp>
</editor>
) as any as PlateEditor;
const output = (
<editor>
<hp>
He<cursor />ld
</hp>
</editor>
) as any as PlateEditor;
const [editor] = await createPlateTestEditor({
editor: input,
});
editor.deleteBackward('character');
expect(editor.children).toEqual(output.children);
expect(editor.selection).toEqual(output.selection);
});
测试键盘事件
使用 createPlateTestEditor
中的 triggerKeyboardEvent
:
it('should extend selection on shift+ArrowRight', async () => {
const input = (
<editor>
<hp>
Hello <cursor />world
</hp>
</editor>
) as any as PlateEditor;
const output = (
<editor>
<hp>
Hello <anchor />wor<focus />ld
</hp>
</editor>
) as any as PlateEditor;
const [editor, { triggerKeyboardEvent }] = await createPlateTestEditor({
editor: input,
});
await triggerKeyboardEvent('shift+ArrowRight');
await triggerKeyboardEvent('shift+ArrowRight');
await triggerKeyboardEvent('shift+ArrowRight');
expect(editor.selection).toEqual(output.selection);
});
测试复杂场景
对于表格等复杂插件,测试各种场景:
describe('Table plugin', () => {
it('should add a row below on Tab in last cell', async () => {
const input = (
<editor>
<htable>
<htr>
<htd>Cell 1</htd>
<htd>
Cell 2<cursor />
</htd>
</htr>
</htable>
</editor>
) as any as PlateEditor;
const output = (
<editor>
<htable>
<htr>
<htd>Cell 1</htd>
<htd>Cell 2</htd>
</htr>
<htr>
<htd>
<cursor />
</htd>
<htd></htd>
</htr>
</htable>
</editor>
) as any as PlateEditor;
const [editor, { triggerKeyboardEvent }] = await createPlateTestEditor({
editor: input,
plugins: [TablePlugin],
});
await triggerKeyboardEvent('Tab');
expect(editor.children).toEqual(output.children);
expect(editor.selection).toEqual(output.selection);
});
});
测试带选项的插件
测试不同的插件选项如何影响行为:
it('should use custom hotkey for bold', async () => {
const handler = jest.fn();
const input = (
<editor>
<hp>
Hello <cursor />world
</hp>
</editor>
) as any as PlateEditor;
const output = (
<editor>
<hp>
Hello <htext bold>world</htext>
</hp>
</editor>
) as any as PlateEditor;
const [editor, { triggerKeyboardEvent }] = await createPlateTestEditor({
editor: input,
plugins: [
BoldPlugin.configure({
shortcuts: {
toggleBold: {
handler,
keys: 'mod+shift+b',
},
},
}),
],
});
await triggerKeyboardEvent('mod+shift+b');
expect(editor.children).toEqual(output.children);
});
Mock 与真实转换
虽然 Mock 对于隔离特定行为很有用,但 Plate 测试通常会在转换后评估实际的编辑器子节点和选择。这种方法确保插件能够正确地与整个编辑器状态一起工作。