BlockNote 端到端测试专用示例编辑器:testing 示例的设计与 e2e 测试基础设施解析

发布时间:2026/9/24 16:30:22
BlockNote 端到端测试专用示例编辑器:testing 示例的设计与 e2e 测试基础设施解析 前端富文本UI组件AI 应用【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址https://gitcode.com/gh_mirrors/bl/BlockNote点击查看免费下载导读本文围绕 BlockNote 仓库中一个特殊的基础示例examples/01-basic/testing展开它不是一个面向用户的演示应用而是专门为端到端e2e测试设计的“测试编辑器”被仓库的 Playwright 浏览器测试套件直接挂载使用。读完本文你将理解该示例的最小实现含 base64 文件上传兜底逻辑、它如何通过examples别名被 basics.test.tsx 等测试导入渲染、测试工具层选择器常量、等待/快照/截图断言如何工作以及整套 e2e 测试的运行方式与多浏览器实例配置。一、testing 示例的定位为 e2e 测试而生的最小编辑器在 BlockNote 仓库的 examples/01-basic 目录下绝大多数示例01-minimal、02-block-objects、03-multi-column等都承担着“向开发者展示某类 API 用法”的文档职责。而 testing/README.md 用两句话交代了它的唯一使命This example is meant for use in end-to-end tests.也就是说这个示例不是给人看的功能演示而是给机器跑的测试基座。它的价值体现在两方面提供一个稳定、无副作用的编辑器宿主测试需要反复挂载、卸载编辑器实例因此该示例不包含任何外部依赖无后端上传、无协作服务、无 AI 调用保证任何浏览器环境下渲染结果一致与测试基础设施解耦测试代码通过路径别名导入示例组件示例自身不感知测试逻辑职责单一。这一点可以从 tests/src/examples.d.ts 的注释中得到印证e2e 测试通过import App from examples/group/name/src/App挂载示例应用examples别名由 Vite 在运行时解析见下文第五节。二、源码拆解一个带文件上传兜底的最小编辑器src/App.tsx 是整个示例的全部业务代码仅 26 行import blocknote/core/fonts/inter.css; import { BlockNoteView } from blocknote/mantine; import blocknote/mantine/style.css; import { useCreateBlockNote } from blocknote/react; // Uploads a file by encoding it as a base64 data URL. In a real app youd // replace this with an upload to your own backend that returns a URL to the // stored file. async function uploadFile(file: File) { return new Promisestring((resolve, reject) { const reader new FileReader(); reader.onload () resolve(reader.result as string); reader.onerror () reject(reader.error); reader.readAsDataURL(file); }); } export default function App() { // Creates a new editor instance. const editor useCreateBlockNote({ uploadFile, }); // Renders the editor instance using a React component. return BlockNoteView editor{editor} /; }2.1 三处导入样式、UI 外壳与 React 桥接blocknote/core/fonts/inter.css引入编辑器默认字体Inter保证测试环境下文字渲染与生产一致blocknote/mantine的BlockNoteView与blocknote/mantine/style.css使用 Mantine 主题的编辑器 UI 外壳blocknote/react的useCreateBlockNoteReact 侧创建编辑器实例的 Hook。这与 examples/01-basic/01-minimal/src/App.tsx 等基础示例的引入方式保持一致从源码结构看testing示例正是以最小可运行形态覆盖默认编辑器能力。2.2 uploadFilebase64 兜底的文件上传uploadFile是本示例中唯一一段业务逻辑用FileReader.readAsDataURL把文件编码为 base64 Data URL 后作为“上传结果”返回。源码注释明确说明——真实应用中应替换为上传到自有后端并返回存储 URL 的实现。它在测试中的意义在于离线可用e2e 测试尤其是图片类测试无需真实网络直接以 Data URL 注入图片即可结果可断言测试可以通过检查img节点的src是否为data:开头来验证上传流程参见 tests/src/end-to-end/images/images.test.tsx 所在目录的测试套件。2.3 入口与宿主应用入口 main.tsx 用createRoot渲染App /并包裹React.StrictModeindex.html 提供#root挂载点。这些文件都标注了“AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY”说明示例脚手架由仓库脚本统一生成保证所有示例结构一致。三、测试如何挂载该示例以 basics.test.tsx 为例端到端测试套件位于 tests/src/end-to-end共约数十个测试目录basics、colors、comments、copypaste、dragdrop、tables、mobile 等。其中 basics/basics.test.tsx 是直接挂载testing示例的最简案例import App from examples/01-basic/testing/src/App; import { beforeEach, describe, expect, test } from vite-plus/test; import { render } from vitest-browser-react; import { userEvent } from ../../utils/context.js; import { EDITOR_SELECTOR } from ../../utils/const.js; import { waitForSelector } from ../../utils/editor.js; beforeEach(async () { await render(App /); await waitForSelector(EDITOR_SELECTOR); }); describe(Basic typing functionality, () { test(should allow me to type content, async () { const editor await waitForSelector(EDITOR_SELECTOR); await userEvent.click( document.querySelectorAll(${EDITOR_SELECTOR} div)[3] as HTMLElement, ); await userEvent.keyboard(hello world); expect(editor.textContent).toBe(hello world); }); });这个测试完整走通了“渲染示例 → 等待编辑器就绪 → 模拟交互 → 断言结果”的 e2e 标准链路render(App /)来自vitest-browser-react直接把示例组件渲染进真实浏览器 DOM测试运行在浏览器中而非 jsdomwaitForSelector(EDITOR_SELECTOR)轮询等待.bn-editor节点挂载确保 ProseMirror 视图初始化完成userEvent.clickuserEvent.keyboard模拟真实点击与键盘输入hello worldexpect(editor.textContent).toBe(hello world)断言编辑器 DOM 文本与输入完全一致。从源码结构看userEvent来自 tests/src/utils/context.ts 的导出封装它基于浏览器环境下的用户事件模拟实现。四、测试工具层选择器常量与断言工具4.1 选择器常量const.tstests/src/utils/const.ts 集中定义了 e2e 测试依赖的 DOM 选择器它们与 BlockNote 的 DOM 结构约定强相关。核心常量如下常量选择器用途EDITOR_SELECTOR.bn-editor编辑器根节点绝大多数测试的入口BLOCK_CONTAINER_SELECTOR[data-node-typeblockContainer]块容器BLOCK_GROUP_SELECTOR[data-node-typeblockGroup]块组PARAGRAPH_SELECTOR[data-content-typeparagraph]段落块H_ONE_BLOCK_SELECTOR等[data-content-typeheading]...各级标题块IMAGE_SELECTOR/PDF_SELECTOR/TABLE_SELECTOR[data-content-typeimage/pdf/table]多媒体/表格块DRAG_HANDLE_SELECTOR[data-testdragHandle]拖拽手柄SLASH_MENU_SELECTOR.bn-suggestion-menu斜杠菜单suggestion 菜单被传送到编辑器容器内故按类名匹配ITALIC_BUTTON_SELECTOR等[data-testitalic]等格式化工具栏按钮这些选择器是测试与编辑器 DOM 契约的“公共接口”任何 DOM 结构调整都会通过这些常量在测试中暴露。testing示例使用默认主题与默认块架构因此这些选择器对它完全适用。4.2 编辑器断言工具editor.tstests/src/utils/editor.ts 提供了可复用的等待与断言函数waitForSelector(selector, { timeout 5000 })基于vi.waitFor轮询元素未出现时抛错默认超时 5 秒waitForSelectorDetached等待元素从 DOM 移除用于菜单关闭、块删除等场景focusOnEditor点击编辑器使其获得焦点waitForTextInEditor(text)等待编辑器文本包含指定内容getDoc()直接读取全局window.ProseMirror的getJSON()返回 ProseMirror 文档的 JSON 表示——源码注释特别说明测试运行在浏览器内无需page.evaluate往返compareDocToSnapshot(name)将文档 JSON 与./__snapshots__/name.json快照比对实现“文档级快照测试”expectElement(...)/matchPageScreenshot(name)视觉回归断言前者可对任意元素做截图对比后者对document.body整页截图可捕获传送到 body 的菜单/工具栏。matchPageScreenshot的注释还透露了快照命名策略视觉基线由 Vitest 按“浏览器 平台”自动命名而文档 JSON 快照与浏览器无关因此跨 chromium/firefox/webkit 三个实例共享同一份快照。五、e2e 运行基础设施vite.config.browser.ts 关键设计整个 e2e 套件的运行配置集中在 tests/vite.config.browser.ts其中与testing示例直接相关的机制包括5.1 examples 别名与源码级解析alias: { ...blockNoteSrcAliases, shared: path.resolve(__dirname, ../shared), examples: path.resolve(__dirname, ../examples), },examples指向仓库的examples目录因此测试代码里import App from examples/01-basic/testing/src/App会解析到 testing/src/App.tsxblockNoteSrcAliases把每个blocknote/*包core、react、mantine、shadcn 等解析到各自的src/目录即测试运行时直接从源码转译包代码不依赖预先构建的 dist——这使修改包源码无需重建 Docker 镜像即可生效TypeScript 侧的配套声明在 tests/src/examples.d.ts以环境模块declare module examples/*声明默认导出为 React 组件避免 tsc 下沉到示例源码破坏 composite 构建TS6059。5.2 多浏览器实例矩阵配置中注册了五个 Playwright 实例这是理解“测试编辑器为何要在多种环境下保持一致”的关键实例浏览器视口说明chromiumChromium1280×720桌面主实例附加--no-sandbox等容器运行参数firefoxFirefox1280×720桌面兼容性webkitWebKit1280×720桌面兼容性androidChromium移动 UA393×727模拟 Android 12 / Chrome 151isMobile: true, hasTouch: true让 prosemirror-view 走 Android 输入路径iosWebKitiPhone UA393×727模拟 iPhone / iOS 18 Safari覆盖 iOS 输入路径如原生 split 回读桌面实例通过DESKTOP_EXCLUDE排除end-to-end/mobile/**移动实例则用include限定各自专属套件。此外还做了全局兜底配置截图断言全局允许 2% 像素差异allowedMismatchedPixelRatio: 0.02以吸收多浏览器反锯齿/字体渲染差异testTimeout: 30000、retry: 2缓解三浏览器共容器运行的偶发资源争抢fileParallelism: false单浏览器单 worker避免 CPU 饱和导致超时。5.3 测试前置与 iframe 尺寸tests/vitestSetup.browser.ts 在每轮测试前完成两件重要工作将测试 iframe 尺寸设置为与浏览器窗口一致的 1280×720移动实例为 393×727避免 Vitest 默认 iframe 过窄导致菜单换行、截图失真注入样式.bn-container { max-width: 731px; margin: 0 auto; padding-top: 8px; }与 BlockNote 官网示例页的编辑框宽度对齐使截图基线与线上展示一致。六、运行方式脚本与 Docker 工作流6.1 脚本入口tests/package.json 提供了两条 e2e 命令{ scripts: { test:e2e: vp test -c vite.config.browser.ts --run, test:e2e:updateSnaps: vp test -c vite.config.browser.ts --run -u } }test:e2e以--run单次执行全部浏览器测试test:e2e:updateSnaps追加-u更新所有文档 JSON 快照与视觉基线新增/修改基线时使用。6.2 Docker 运行脚本docker-run.shtests/docker-run.sh 是官方推荐的本地执行方式。它的核心设计是“镜像只装依赖、源码运行时挂载”镜像blocknote-e2e安装依赖但不构建任何包见 tests/Dockerfile 配套说明启动时把每个packages/*/src以-v方式绑定挂载进容器与 5.1 节的源码级解析配合编辑包源码后无需重建镜像即可复测脚本会用内容哈希标签自动判断依赖/示例是否变化必要时自动重建镜像典型用法为tests/docker-run.sh [docker 参数] -- [vp 参数]例如tests/docker-run.sh -- -t Basic typing可只跑指定测试。6.3 浏览器测试与单元测试的边界需要说明的是e2e 套件不仅包含tests/src/end-to-end/**/*.test.tsx还会运行各包源码内联的*.browser.test.{ts,tsx}如 canvas 栅格化、Mermaid 渲染等浏览器专属单测见include配置include: [ ./src/end-to-end/**/*.test.tsx, ../packages/*/src/**/*.browser.test.{ts,tsx}, ],这与testing示例无直接关系但解释了为何该配置的include范围覆盖了包目录。七、小结从测试编辑器到测试契约examples/01-basic/testing虽然只有一行业务组件却在 BlockNote 的质量保障体系中扮演枢纽角色对测试代码它是稳定、可复现的渲染宿主src/App.tsx对编辑器 DOM它通过 const.ts 中的选择器与测试建立“DOM 契约”任何样式类或data-*属性的变更都会被测试直接捕获对 CI它与 vite.config.browser.ts 的源码级别名、五实例浏览器矩阵、快照断言共同构成可离线、可并发的回归防线。若你希望在自有项目中复刻这套模式最直接的做法是仿照本示例维护一个“最小测试编辑器”应用导出其 App 组件供测试挂载将编辑器根节点、块类型、工具栏按钮的选择器集中到常量文件中再用浏览器模式测试框架本仓库使用 vite-plus vitest-browser-react Playwright驱动真实输入与截图断言。当编辑器 DOM 契约稳定后这套测试基座即可长期复用于功能回归与视觉回归。相关文件索引示例本体README.md、src/App.tsx、main.tsx直接挂载该示例的测试basics.test.tsx测试工具层const.ts、editor.ts、examples.d.ts运行配置vite.config.browser.ts、vitestSetup.browser.ts、tests/package.json、docker-run.sh赞分享前端富文本UI组件AI 应用【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址https://gitcode.com/gh_mirrors/bl/BlockNote点击查看免费下载相关推荐Multilingual-E5-large-instruct与其他嵌入模型对比为什么选择它Multilingual E5 large instruct与其他嵌入模型对比为什么选择它 Multilingual E5 large instruct是一前端富文本UI组件AI 应用Base UI 端到端测试指南Playwright Vite 的 e2e 基础设施解析Base UI 端到端测试指南Playwright Vite 的 e2e 基础设施解析 端到端e2e测试是验证 Base UI 组件在真实浏览器环境下前端UI组件Kubernetes E2E 测试框架 test/e2e/framework 源码级解析面向 Ginkgo 的端到端测试基础设施Kubernetes E2E 测试框架 test/e2e/framework 源码级解析面向 Ginkgo 的端到端测试基础设施 Kubernetes 仓库中云原生容器编排集群管理微服务上一篇Bitwarden server 如何用 k6 对登录端点做固定 QPS 在线压测并检查延迟阈值下一篇TCP Option Address (TOA)深度解析如何从TCP头部选项高效提取源IPv4地址创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考