ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Zeppelin Notebook Parity 场景注册表:React 迁移下 Notebook 行为对等的验证体系

Zeppelin Notebook Parity 场景注册表:React 迁移下 Notebook 行为对等的验证体系 数据分析数据可视化大数据后端前端任务调度【免费下载链接】zeppelinWeb-based notebook that enables>项目地址https://gitcode.com/gh_mirrors/zeppe/zeppelin点击查看免费下载Zeppelin 的 Angular 前端正在逐步向 React 垂直切片vertical slice迁移迁移的前提是换实现、不换行为。本文介绍的zeppelin-web-angular/e2e/scenarios/notebook-parity.md正是为这一目标建立的Notebook 行为对等parity场景注册表它把 Angular Notebook 的关键行为固化为带 ID、前置条件、可观察结果与证据链的场景清单并由脚本自动生成 Markdown、用 JSON Schema 强制约束、以 Playwright 测试标签双向校验。读完本文你将掌握注册表的数据模型、生成与校验链路、10 个已登记场景的完整细节以及如何用这些场景驱动 React 迁移的质量验收。Notebook Parity 注册表要解决什么问题Zeppelin 前端存在 Angular 与 React 两套实现旧壳zeppelin-web-angular/src/app下的 Angular 组件是当前行为基准source of truth而zeppelin-web-angular/projects/zeppelin-react正在以远程模块方式逐步接管 Notebook 表面。按仓库根 AGENTS.md 的迁移约定一个回归只有在之前的行为从未被写下来时才会变成预期结果——因此迁移要求在 Angular 仍是基准时先把行为写下来。这份注册表承担的就是先把行为写下来的角色。它是一份优先级化prioritized的基线而非完整的 Notebook 功能清单在一个 React 垂直切片被宣告就绪之前必须把每一个受影响的行为登记进注册表并归类其证据。文档本身也明确给出了两条使用纪律Scope note这是优先化基线而非完整 Notebook 清单Coverage notecovered在机械含义上仅指注册表指向了一个匹配的可执行 Playwright 测试标签语义充分性与运行时通过与否仍属于 review 与 CI 证据角色期望只在结果随角色变化时才记录且角色验证记录该期望是否已测试。也就是说注册表解决的是有没有人明确验证过某行为在新实现上仍然一致这一治理问题而不是替 CI 宣称行为一定一致。注册表的三种形态与生成链路同一份数据以三种形态存在全部位于zeppelin-web-angular/e2e/scenarios/目录形态文件作用数据源notebook-parity.json场景注册表的唯一事实来源由人维护模式约束notebook-parity.schema.jsonJSON Schema draft-07定义注册表合法结构发布文档notebook-parity.md渲染产物禁止手改文件头标注Generated by scripts/generate-notebook-parity-scenarios.mjs. Do not edit directly.生成链路由两个脚本驱动见 notebook-parity-scenarios.mjs 与 generate-notebook-parity-scenarios.mjsloadRegistry(webRoot)读取e2e/scenarios/notebook-parity.jsonvalidateRegistry(registry, webRoot)执行全套校验见下节其中checkMarkdown: false用于生成前校验、checkMarkdown: true用于比对产物renderMarkdown(registry)将场景数组渲染为 Markdown 表格 场景明细writeFileSync写回e2e/scenarios/notebook-parity.md。生成命令就是脚本自身报错时给出的提示npm run generate:notebook-parity-scenarios。若 Markdown 与 JSON 不一致validateRegistry会报notebook-parity.md is stale强制提交前重新生成从而保证文档永远等于数据。校验器实际做了什么validateRegistry是这套体系最严谨的部分它把测试与场景一一对应变成机器可查的硬约束Schema 校验用 Ajv 编译 schema 校验整个注册表formatSchemaError会把additionalProperties、minItems、pattern、required、type等错误转换为可定位的location.message格式基准提交存在性reviewedCommit必须是 40 位十六进制并用git cat-file -e commit^{commit}验证当前 checkout 里确实存在该提交当前值为d5b57b12fd0c5e1d885767aabe06b242debf8300ID 纪律场景id全局唯一且必须按字典序严格递增防止乱序追加outcome 的id必须以场景ID-OUTCOME-开头且不重复uncoveredOutcomes必须引用真实存在的 outcome id角色一致性roleExpectations为not-applicable的角色其roleVerification必须是not-applicable反之亦然证据路径存在性implementationEvidence/verificationEvidence中的每个path都必须真实存在于仓库通过resolveRepositoryPath在模块根与仓库根两个候选位置解析测试标签可执行性最硬核的一步testDeclaresExecutableTag用TypeScript AST解析测试源文件——先找playwright/test导入绑定到的test标识符再遍历所有test(...)调用读取第二参数的静态tag字符串并排除位于describe.skip(...)内部的调用isInsideSkippedDescribe。只有注册表中的NB-PARITY-XXX标签确实由某个可执行的test()声明才算covered套件归属covered场景的测试路径必须以zeppelin-web-angular/e2e/tests/notebook/开头且test.tag必须恰好等于场景ID。这一整套校验意味着注册表无法引用不存在的文件、无法指向被跳过或未声明的测试、无法容忍标签与 ID 错位从机制上杜绝了假覆盖。注册表数据模型Schema 要点notebook-parity.schema.json 定义了场景的合法形状理解它才能读懂明细根对象必须有$schema固定指向./notebook-parity.schema.json、reviewedCommit40 位 hex、scenarios至少 1 项scenario 必需字段id^NB-PARITY-[0-9]{3}$、name、area、preconditions、action、observableOutcomes、interpreter、implementationEvidence、verificationEvidence、coveragearea 枚举editor、execution、result、visualization、shortcut、permission、collaboration、navigation、persistence、lifecycle、theme、accessibility——当前 10 个场景覆盖了其中navigation、editor、shortcut、result、persistence、theme六类证据二元组每条 evidence 是{ path, symbol }例如{ path: zeppelin-web-angular/src/app/core/paragraph-base/paragraph-output-state.ts, symbol: ParagraphOutputState }把实现/验证锚点精确定位到文件与符号角色期望roleExpectations对owner、writer、reader、runner四个角色各给allow/deny/not-applicableroleVerification对同一角色集合给verified/unverified/not-applicable且两者相互约束coverage 状态机allOf组合约束这是理解covered/partial/gap的关键covered至少 1 个测试 0 个未覆盖 outcomepartial至少 1 个测试 至少 1 个 issue 至少 1 个未覆盖 outcomegap/blocked0 个测试 至少 1 个 issue 0 个未覆盖 outcome。也就是说有测试不等于covered——只要还有 outcome 没被验证如结果展示模式、可视化字段映射状态就自动降级为partial并强制登记 JIRA issue 与未覆盖 outcome 清单。全量场景清单下表完整对应注册表的索引表含每个场景的测试文件与NB-PARITY-XXX标签角色期望仅在与角色相关时记录IDAreaScenarioCoverageRolesTestsIssuesNB-PARITY-001navigationNotebook container structure is visiblecoverednot-applicablenotebook-container.spec.tsNB-PARITY-001NB-PARITY-002navigationNotebook title can be displayed and editedcoveredowner: allow; writer: allow; reader: deny; runner: not-applicableaction-bar-functionality.spec.tsNB-PARITY-002NB-PARITY-003editorParagraph enters editing mode on double clickcoveredowner: allow; writer: allow; reader: deny; runner: not-applicableparagraph-functionality.spec.tsNB-PARITY-003NB-PARITY-004editorParagraph add buttons are visiblecoveredowner: allow; writer: allow; reader: deny; runner: not-applicableparagraph-functionality.spec.tsNB-PARITY-004NB-PARITY-005shortcutShiftEnter executes a markdown paragraphcoveredowner: allow; writer: allow; reader: deny; runner: allownotebook-keyboard-shortcuts.spec.tsNB-PARITY-005NB-PARITY-010editorHistory inline completion can be dismissed without losing editor focuscoverednot-applicableinline-completion.spec.tsNB-PARITY-010NB-PARITY-011editorThe second Escape after inline completion dismissal blurs the editorcoverednot-applicableinline-completion.spec.tsNB-PARITY-011NB-PARITY-021resultText and table result displays preserve output semantics after paragraph executionpartialowner: allow; writer: allow; reader: deny; runner: allowparagraph-functionality.spec.tsNB-PARITY-021ZEPPELIN-6514, ZEPPELIN-6516NB-PARITY-022resultStreaming interpreter output accumulates while a paragraph is runningcoveredowner: allow; writer: allow; reader: deny; runner: allowparagraph-functionality.spec.tsNB-PARITY-022NB-PARITY-050persistenceNotebook editor persists the latest text after typing stopscoveredowner: allow; writer: allow; reader: deny; runner: not-applicablenotebook-save-timing.spec.tsNB-PARITY-050NB-PARITY-051persistenceNotebook editor does not lose an edit made while a prior save is in flightcoveredowner: allow; writer: allow; reader: deny; runner: not-applicablenotebook-save-timing.spec.tsNB-PARITY-051NB-PARITY-060themeNotebook honors host theme selectiongapnot-applicable无测试ZEPPELIN-6640场景分区详解以下按文档的 Scenario Details 逐项展开每个场景都标注了前置条件、动作、可观察结果OUTCOME以及对应的实现/验证证据。导航与容器NB-PARITY-001 Notebook container structure is visiblearea: navigationcoverage: covered前置条件打开一个可丢弃disposable的 notebook 路由动作渲染 notebook 路由可观察结果NB-PARITY-001-OUTCOME-001notebook 容器可见且带有期望的容器类。验证证据notebook-container.spec.tsNotebook Container Component与 notebook-page.tsNotebookPage。源码印证测试在beforeEach中通过createTestNotebook(page)创建一次性 notebook 再导航进入NotebookPage把.notebook-container、zeppelin-notebook-action-bar、可拖拽侧栏.sidebar-area[nz-resizable]、网格布局段落容器.paragraph-inner[nz-row]、扩展区.extension-area等 DOM 锚点封装为 Locator。同一套件还验证了侧栏宽度约束40800px与点击设置按钮后扩展区可见——这些是 React 切片需要逐一对齐的布局行为。NB-PARITY-002 Notebook title can be displayed and editedarea: navigationcoverage: covered角色期望owner/writer 允许reader 拒绝runner 不适用动作打开标题编辑器并重命名 notebook可观察结果NB-PARITY-002-OUTCOME-001标题编辑器可见且改名后的标题反映在 notebook 头部。验证证据action-bar-functionality.spec.tsNotebook Action Bar Functionality与 notebook-action-bar-page.tsNotebookActionBarPage。说明该场景同时登记了四角色的权限期望但目前owner/writer/reader的roleVerification均为unverified——即权限矩阵已记录、尚未逐角色跑通这正是覆盖注释所说角色验证记录的是该期望是否已测试的实例。段落编辑NB-PARITY-003 Paragraph enters editing mode on double clickarea: editorcoverage: covered前置条件打开一个至少含一个段落的 notebook动作双击段落可观察结果NB-PARITY-003-OUTCOME-001段落代码编辑器变为可见。验证证据paragraph-functionality.spec.tsNotebook Paragraph Functionality与 notebook-paragraph-page.tsNotebookParagraphPage。NB-PARITY-004 Paragraph add buttons are visiblearea: editorcoverage: covered动作检查段落控件可观察结果NB-PARITY-004-OUTCOME-001添加段落的控件在可插入新段落的位置可见。验证证据同上。NB-PARITY-010 History inline completion can be dismissed without losing editor focusarea: editorcoverage: coveredinterpreter: python前置条件notebook 含一个可供给 inline completion 历史文本的 Python 段落并以aiInlineComplete打开路由动作在 Monaco 中键入补全前缀并在补全可见时按 Escape可观察结果NB-PARITY-010-OUTCOME-001补全建议来自 notebook 历史NB-PARITY-010-OUTCOME-002第一次 Escape 关闭建议后 Monaco 输入框仍保持焦点。验证证据inline-completion.spec.tsInline completion与 notebook-keyboard-page.tsNotebookKeyboardPage。源码印证E2E 通过page.goto(/#/notebook/id?aiInlineCompletetrue)开启特性并专门用.monaco-editor .ghost-text-decoration, .ghost-text-decoration-preview定位 Monaco 的幽灵文本ghost text因为幽灵文本没有可访问角色测试断言补全文本收敛为tory)后才按 Escape随后断言inputArea仍toBeFocused()。NB-PARITY-011 The second Escape after inline completion dismissal blurs the editorarea: editorcoverage: coveredinterpreter: python前置条件同 NB-PARITY-010且浏览器为 Chromium动作第一次 Escape 关闭补全第二次 Escape 再按一次可观察结果NB-PARITY-011-OUTCOME-001第一次 Escape 保持 Monaco 焦点NB-PARITY-011-OUTCOME-002第二次 Escape 在 Chromium 中使 Monaco 输入框失焦。源码印证测试显式test.skip(browserName ! chromium, ...)——Monaco 对 Firefox/WebKit 的第二次 Escape 处理不同因此把浏览器差异固化进场景本身而不是让测试悄悄跨浏览器断言失败。快捷键执行NB-PARITY-005 ShiftEnter executes a markdown paragrapharea: shortcutcoverage: coveredinterpreter: md前置条件代码编辑器中有焦点的可丢弃段落动作键入 Markdown 内容并按下 ShiftEnter可观察结果NB-PARITY-005-OUTCOME-001段落执行并渲染出 Markdown 标题结果。验证证据notebook-keyboard-shortcuts.spec.tsParagraphActions.Run与 notebook-keyboard-page.tsNotebookKeyboardPage。源码印证键盘套件基于ShortcutsMapsrc/app/key-binding/shortcuts-map.ts编写页面对象先等待 Monaco 的focused类再派发快捷键效果一律用 web-first 断言。测试输入%md\n# Test Heading\n\nThis is **bold** text.按pressRunParagraph()后先waitForParagraphExecution(0)以状态文本收敛作为运行完成的断言再断言结果区出现headingrole 且名称为 Test Heading。该套件还覆盖了ControlAltA/B插入上下段落、ControlAltK/J移动段落、ControlAltD删除、ControlAltW生成段落链接、ControlSpace自动补全等大量快捷键是整个 parity 矩阵里覆盖面最广的测试文件之一。结果渲染与流式输出NB-PARITY-021 Text and table result displays preserve output semantics after paragraph executionarea: resultcoverage:partialinterpreter: python前置条件notebook 含一个打印文本的 Python 段落与一个返回表格输出的段落动作从段落控件运行段落并检查渲染的结果面板可观察结果共 5 项NB-PARITY-021-OUTCOME-001结果展示变为可见且非空NB-PARITY-021-OUTCOME-002UI 提供 Angular notebook 对返回结果类型暴露的每一种展示模式NB-PARITY-021-OUTCOME-003可视化控件变更保留结果列 → 维度/度量的字段映射NB-PARITY-021-OUTCOME-004可视化选项变更后段落的持久化 config 反映最终配置对象NB-PARITY-021-OUTCOME-005文本与表格结果按行暴露可访问的表格输出使 React 渲染的对比不依赖截图。实现证据paragraph.component.htmlzeppelin-notebook-paragraph-result、progress.component.tsNotebookParagraphProgressComponent、table-transformation.tsTableTransformation、pivot-transformation.tsPivotTransformation、visualization.tsVisualization。未覆盖 outcomeOUTCOME-002、003、004、005 均未覆盖并关联 ZEPPELIN-6514、ZEPPELIN-6516 两个 issue。这是机械 covered ≠ 语义充分的最佳例证当前测试只验证了结果可见非空而展示模式枚举、可视化字段映射持久化、可访问表格逐行输出都还待补。NB-PARITY-022 Streaming interpreter output accumulates while a paragraph is runningarea: resultcoverage: coveredinterpreter: sh前置条件notebook 含一个带延时分批输出的 shell 段落且服务端开启流式输出zeppelin.websocket.paragraph_status_progress.enable为 true动作运行段落并在其结束前后观察结果面板可观察结果NB-PARITY-022-OUTCOME-001段落状态仍为 RUNNING 时第一块输出已可见NB-PARITY-022-OUTCOME-002后续块追加在先前的块之后而非替换它们NB-PARITY-022-OUTCOME-003FINISHED 结果按发射顺序恰好包含每一块各一次。实现证据paragraph-output-state.tsParagraphOutputState、paragraph-base.tsParagraphBase.onParagraphAppendOutput/onParagraphUpdateOutput、AppendOutputRunner.javaAppendOutputRunner。验证证据paragraph-output-state.spec.ts单元测试、paragraph-output-stream.capture.jsonenabled、notebook-paragraph-page.ts。源码印证ParagraphOutputState是这条行为的核心实现——它维护results数组与pendingAppends缓冲append(index, data)把新块拼接到既有data之后并返回更新后的结果对象不替换update(index, type, data)对空 type 声明采用 pending 追加内容一旦finish()置位terminal后续 append/update 一律返回undefined从而保证结束后的结果每块恰好一次。snapshot()还特意保留服务端索引——缺失槽位未获得类型前不截断避免追加竞态导致渲染错位。单元测试与 E2E 双保险且 E2E 依赖服务端配置zeppelin.websocket.paragraph_status_progress.enabletrue这条配置项正是流式输出语义的前置条件。保存时序NB-PARITY-050 Notebook editor persists the latest text after typing stopsarea: persistencecoverage: covered前置条件打开含一个可编辑段落的 notebook用户可编辑该段落动作替换段落文本并停止输入足够久让保存路径确认该编辑可观察结果NB-PARITY-050-OUTCOME-001持久化的段落文本等于最后键入的文本NB-PARITY-050-OUTCOME-002保存断言基于可观察的持久化或线上wire证据而非内部计时器。实现证据code-editor.component.tsNotebookParagraphCodeEditorComponent验证证据notebook-save-timing.util.tsCommitParagraphSocketProbe与 notebook-keyboard-page.ts。源码印证CommitParagraphSocketProbe通过page.routeWebSocket(/\/ws(\?|$)/)代理浏览器与 Zeppelin 的 WebSocket监听COMMIT_PARAGRAPH消息含msgId、noteId、paragraph。断言不是等固定秒数而是expect.poll(...)等待 commit 数量与内容真正做到了基于线上证据。测试还检测COLLABORATIVE_MODE_STATUS与PATCH_PARAGRAPH——一旦 notebook 进入协作模式编辑走PATCH_PARAGRAPHCOMMIT_PARAGRAPH不再出现probe 会直接抛错提示测试前提失效。NB-PARITY-051 Notebook editor does not lose an edit made while a prior save is in flightarea: persistencecoverage: covered前置条件第一个段落保存请求可在其完成前被观察到动作编辑段落、让第一次保存在途再进行第二次编辑可观察结果NB-PARITY-051-OUTCOME-001在途的第一次保存不会覆盖或丢弃第二次编辑NB-PARITY-051-OUTCOME-002稍后的可观察保存或对账reconciliation持久化第二次编辑。实现证据code-editor.component.ts、notebook.component.tsNotebookComponent、paragraph-base.tsParagraphBase验证证据notebook-save-timing.util.tsCommitParagraphSocketProbe。源码印证probe 的holdFirstCommitParagraphResponse()会把第一个COMMIT_PARAGRAPH的服务端PARAGRAPH回执扣留在代理层heldResponsesMap并在此后把服务端消息排进队列queuedResponses以保持顺序随后用releaseHeldResponseWithParagraphTitle(msgId, title)把被扣回执改造成带标记标题的段落快照放行测试据此断言在途回执应用后第二次编辑仍在。这套扣留回执 乱序恢复的机制把真实世界中最棘手的并发保存竞态变成了可重复的确定性测试。主题NB-PARITY-060 Notebook honors host theme selectionarea: themecoverage:gap前置条件用户可从宿主壳选择 light / dark / system 主题动作在 notebook 表面挂载期间切换宿主主题可观察结果NB-PARITY-060-OUTCOME-001notebook 文本保持可读NB-PARITY-060-OUTCOME-002结果与图表输出继承宿主主题令牌tokensNB-PARITY-060-OUTCOME-003所选主题在刷新后持久。实现证据ZeppelinThemeProvider.tsxZeppelinThemeProvider验证证据dark-mode.spec.tsDark Mode Theme Switching。说明该场景当前为gap——没有登记任何匹配的测试标签且关联 ZEPPELIN-6640。按 schema 的状态机gap强制要求 0 测试 至少 1 issue这正是已知缺口要显式记账的工程实践缺口不被静默遗忘而是在注册表里以 issue 形式排队。coverage 状态与角色权限矩阵的工程语义从上面 10 个场景可以看出注册表的 coverage 是一个三值逻辑而非布尔值covered8 个001/002/003/004/005/010/011/022/050/051 中的 9 个意味着存在可执行测试标签且全部 outcome 均已登记验证例如 NB-PARITY-022 从单元测试、捕获流量、E2E 三个层面闭环partial1 个021意味着有测试但语义未满未覆盖的 4 个 outcome 与 2 个 JIRA issue 被显式列出防止团队误把有测试当作已验证gap1 个060意味着已知行为差异尚未有测试通过 issue 登记排队。角色权限维度同样讲究记录与验证分离roleExpectations写明谁应该能做什么如 reader 对编辑类操作一律deny而roleVerification诚实标注unverified当前 10 个场景中所有涉及角色的场景都尚未逐角色跑通。这种期望先行、验证后补的记账方式让 React 迁移的每一个垂直切片都能回答两个问题行为是什么、哪个角色在哪个行为上还没被验证。如何运行与扩展场景单元层核心状态类如ParagraphOutputState在 paragraph-output-state.spec.ts 中用 Vitest 直接构造断言按 AGENTS.md 的约定npm run test:shell覆盖src/与两个库。E2E 层所有场景标签都挂在 Playwright 套件上运行入口为mvnw verify -Pweb-e2e对应 CI 的run-playwright-e2e-tests任务。测试文件通过test(..., { tag: NB-PARITY-XXX }, ...)声明标签因此可以用标签精确筛选场景执行。扩展一个场景的标准流程由校验器倒逼在e2e/scenarios/notebook-parity.json的scenarios数组追加新对象id必须大于已有最大 ID 且遵守NB-PARITY-[0-9]{3}命名area从枚举中选至少提供 implementationEvidence 或 verificationEvidence 之一并按其语义填写coverage在e2e/tests/notebook/下编写对应的 Playwright 测试并声明NB-PARITY-XXX标签注意校验器会检查 AST跳过describe.skip内的调用运行npm run generate:notebook-parity-scenarios重新生成 Markdown提交时validateRegistry含checkMarkdown会校验 schema、ID 顺序、证据路径存在性、标签可执行性与 Markdown 新鲜度任何一环不满足都会阻止合并。小结zeppelin-web-angular/e2e/scenarios/notebook-parity.md表面是一张场景表实质是一套把行为对等工程化的治理机制JSON 作为唯一事实来源、Schema 定义合法形状、脚本生成文档、AST 校验测试标签、状态机区分 covered/partial/gap、角色期望与验证分离。对 Zeppelin 的 Angular → React 迁移而言它是可回溯的行为契约对任何正在做前端框架迁移的团队而言它也是一个可复制的迁移行为记账范式——先写行为再写实现用可执行的证据闭环防止回归。赞分享数据分析数据可视化大数据后端前端任务调度【免费下载链接】zeppelinWeb-based notebook that enables>项目地址https://gitcode.com/gh_mirrors/zeppe/zeppelin点击查看免费下载相关推荐Apache Zeppelin 手动升级指南notebook 与配置迁移全流程Apache Zeppelin 手动升级指南notebook 与配置迁移全流程 本篇指南以 Apache Zeppelin 官方手动升级流程为核心系统讲数据分析数据可视化大数据后端前端任务调度JupyterLab与Notebook对比分析与应用场景JupyterLab与Notebook对比分析与应用场景 本文深入对比分析了Jupyter生态系统中的两大核心编辑器——JupyterLab与Jupyter N开发工具Apache Zeppelin Notebook 授权Notebook Authorization配置与实践指南Apache Zeppelin Notebook 授权Notebook Authorization配置与实践指南 本指南讲解如何在 Apache Zeppe数据分析数据可视化大数据后端前端任务调度上一篇3分钟搞定Chrome浏览器Markdown阅读难题markdownReader完全指南下一篇AGENTS.md 巨型指令文件为何失败用 Progressive Disclosure 拆分指令路由learn-harness-engineering 实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表