┌──────────────────────────────────────────────────────────┐ │ 📄 shadcn/directory/udecode/plate/(guides)/playwright.cn │ └──────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
Playwright 支持在无头浏览器中进行端到端测试。本指南介绍如何使用 @platejs/playwright 将 Playwright 与 Plate 集成。
按照 Playwright 指南 在您的应用中安装 Playwright,并确保您可以编写基本的端到端测试。
npm install @platejs/playwright playwright
为了让您的 Playwright 测试能够访问和操作编辑器,您需要在编辑器中添加 PlaywrightPlugin:
const editor = createPlateEditor({
plugins: [
// 其他插件...
PlaywrightPlugin.configure({ enabled: process.env.NODE_ENV !== 'production' }),
]
})
这会在 window.platePlaywrightAdapter 上暴露各种工具函数。
句柄 引用浏览器中的 JavaScript 对象。编辑器句柄指的是您的 Plate 编辑器的 editor 实例(JSHandle<PlateEditor>)。
</Callout>
在您的 Playwright 测试中,在与 Plate 交互之前获取编辑器句柄:
const editorHandle = await getEditorHandle(page);
对于多个编辑器,指定可编辑元素:
const editable = getEditable(page.getByTestId('my-editor-container'));
const editorHandle = await getEditorHandle(page, editable);
定位器必须精确匹配一个 [data-slate-editor] 元素。
有了 editorHandle,您现在可以开始为编辑器编写 Playwright 测试了。
使用 getNodeByPath 获取引用特定路径节点的句柄。要断言节点的值,使用 .jsonValue() 将其转换为 JSON。
const nodeHandle = await getNodeByPath(page, editorHandle, [0]);
expect(await nodeHandle.jsonValue()).toBe({
type: 'p',
children: [{ text: '我的段落' }],
});
const firstNodeType = await getTypeAtPath(page, editorHandle, [0]);
expect(firstNodeType).toBe('h1');
在 Playwright 中,您经常需要引用特定的 DOM 元素以断言其状态或执行涉及它的操作。
getDOMNodeByPath 返回与给定路径的 Plate 节点对应的 DOM 节点的 ElementHandle。
const firstNodeEl = await getDOMNodeByPath(page, elementHandle, [0]);
await firstNodeEl.hover();
await clickAtPath(page, elementHandle, [0]);
const selection = await getSelection(page, editorHandle);
expect(selection).toBe({
anchor: { path: [0, 0], offset: 0 },
focus: { path: [0, 0], offset: 7 },
});
要在编辑器中的特定位置输入,您需要使用 setSelection 选择该点。
如果您选择单个点(由 path 和 offset 组成),光标将放置在该点。如果您选择一个范围(由 anchor 和 focus 组成),将选中该范围。如果您选择一个路径,将选中该路径处的整个节点。
在设置选区之前,请确保聚焦编辑器。在 WebKit 中,使用 editable.focus() 聚焦编辑器可能无法正常工作,因此最好的方法是使用 clickAtPath。
// 点击第一个段落以聚焦编辑器
await clickAtPath(page, editorHandle, [0]);
await setSelection(page, editorHandle, {
path: [0, 0],
offset: 2,
});
await page.keyboard.type('你好,世界!');
您可能想要将查询或转换(如 getBlockAbove 或 insertNodes)导入到 Playwright 测试中使用。
不幸的是,这是不可能的。您只能在浏览器上下文中直接与 editor 实例交互(使用 evaluate 或 evaluateHandle),并且无法将导入的函数从 Playwright 的作用域传递到浏览器中。这是因为 editor 对象和 JavaScript 函数都无法充分序列化。
最好的解决方案是以用户相同的方式与编辑器交互,而不使用任何导入的查询或转换。这将使您的 Playwright 测试更有可能捕获应用程序中的错误。
如果这不可行,您可以在 evaluate 或 evaluateHandle 中调用 editor 对象的方法。(如果需要从浏览器返回对 DOM 节点或 JavaScript 对象的引用,请使用 evaluateHandle。如果需要返回 JavaScript 对象的序列化副本,或者不需要返回任何值,请使用 evaluate。)
请注意,虽然这些查询和转换不能直接在 Playwright 测试中使用,但在应用程序代码中使用编辑器实例时它们是可用的。有关如何在应用程序中使用这些方法的更多信息,请参阅编辑器方法文档。
有关 evaluate 和 evaluateHandle 的更多信息,请参阅 Playwright 文档。
await editorHandle.evaluate((editor) => {
editor.tf.insertNodes(/* ... */);
});
有关 evaluate 和 evaluateHandle 的更多信息,请参阅 Playwright 文档。
getEditorHandle获取 Plate 编辑器实例的句柄。
<API name="getEditorHandle"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editable" type="Locator" optional> 可编辑元素的定位器。默认为第一个 [data-slate-editor]。 </APIItem> </APIParameters> <APIReturns type="EditorHandle"> Plate 编辑器实例的句柄。 </APIReturns> </API>getNodeByPath获取指定路径的节点。
<API name="getNodeByPath"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> <APIItem name="path" type="Path"> 节点的路径。 </APIItem> </APIParameters> <APIReturns type="JSHandle<TNode>"> 路径处节点的句柄。 </APIReturns> </API>getDOMNodeByPath获取给定路径的 Plate 节点对应的 DOM 节点。
<API name="getDOMNodeByPath"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> <APIItem name="path" type="Path"> 节点的路径。 </APIItem> </APIParameters> <APIReturns type="ElementHandle"> 对应 DOM 节点的 ElementHandle。 </APIReturns> </API>clickAtPath模拟点击指定路径的节点。
<API name="clickAtPath"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> <APIItem name="path" type="Path"> 要点击的节点的路径。 </APIItem> </APIParameters> </API>getSelection获取当前编辑器选区。
<API name="getSelection"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> </APIParameters> <APIReturns type="Selection"> 当前编辑器选区。 </APIReturns> </API>setSelection将编辑器选区设置为指定范围。
<API name="setSelection"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> <APIItem name="at" type="Location"> 要设置选区的位置。 </APIItem> </APIParameters> </API>getTypeAtPath获取指定路径处节点的类型。
<API name="getTypeAtPath"> <APIParameters> <APIItem name="page" type="Page"> Playwright 页面对象。 </APIItem> <APIItem name="editorHandle" type="EditorHandle"> 编辑器实例的句柄。 </APIItem> <APIItem name="path" type="Path"> 节点的路径。 </APIItem> </APIParameters> <APIReturns type="string"> 路径处节点的类型。 </APIReturns> </API>║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
╚══════════════════════════════════════════════════════════════════════════════════════════════╝