Coze Studio 前端单测组件 Mock 清单与实现解析:以 database-creator 的 mock-components 为例
Coze Studio 前端单测组件 Mock 清单与实现解析以 database-creator 的 mock-components 为例【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio本指南围绕 Coze Studio 前端 monorepo 中frontend/packages/data/memory/database-creator/__tests__/mock-components目录下的组件 Mock 清单展开说明在 Vitest 环境下如何隔离半设计体系组件库coze-arch/bot-semi中 UITable、Form、Modal、Toast 等 19 类组件以保证数据库创建/编辑弹窗DatabaseModal的单元测试稳定运行。读完本文你将掌握 Coze Studio 前端包的组件 Mock 清单结构、关键 Mock 组件的源码实现思路以及在测试文件中通过vi.mock挂载这些 Mock 的具体方法。一、为什么需要一份组件 Mock 清单coze-data/database-creator是 Coze Studio 前端 monorepo 中的核心数据包负责“创建或编辑数据库信息”create or edit database info其介绍见 frontend/packages/data/memory/database-creator/README.md。该包通过 database-modal.test.tsx 对DatabaseModal弹窗进行单元测试测试框架采用 Vitest见 vitest.config.ts基于coze-arch/vitest-config的webpreset并启用了coverage.all。问题在于DatabaseModal内部依赖了大量来自组件库coze-arch/bot-semi的 UI 组件这些组件包含复杂的 DOM 结构、弹层、国际化与样式逻辑在 jsdom 测试环境中难以完整渲染且不稳定。为此测试目录下专门维护了mock-components/文件夹用一份简洁的 readme 清单记录需要被 Mock 的全部组件名并配以 17 个轻量级 Mock 实现文件。这份清单相当于“Mock 契约”测试文件中凡是出现清单中的组件都必须有对应的 Mock 替代实现。二、组件 Mock 清单全览清单原文位于 readme.md全文如下mock 以下组件 UITable, UITableAction, Button, Switch, Tooltip, Image, Form, Banner, withField, Popover, Spin, Icon, Popconfirm, Divider, TextArea, UIButton, Modal, Toast清单共列出 19 个条目含 18 个具名组件 withField高阶组件。结合同目录下实际存在的实现文件可将清单映射为如下表格清单条目对应 Mock 文件Mock 形态UITablemock-ui-table.tsx渲染型执行 render 函数UITableActionmock-table-action.tsx渲染型Button / UIButtonmock-button.tsx、mock-ui-button.tsx渲染型透传 onClickSwitchmock-switch.tsx交互型点击切换状态Tooltipmock-tooltip.tsx透传型Imagemock-image.tsx透传型Form / withFieldmock-form.tsx事件总线型EventEmitterBannermock-banner.tsx透传型Popovermock-popover.tsx渲染型Spinmock-spin.tsx透传型Iconmock-icon.tsx占位型Popconfirmmock-popconfirm.tsx渲染型直接暴露确认按钮Dividermock-divider.tsx占位型TextAreamock-textarea.tsx渲染型受控 inputModalmock-modal.tsx渲染型可见性判断Toastmock-toast.tsx无操作型no-op其中“渲染型”指 Mock 会忠实执行组件库的渲染语义如表格列render函数“透传型”指仅将 props 中的children与回调原样传出“占位型”指只输出稳定文本/空节点“无操作型”指导出空函数仅保证调用不报错。这四种形态覆盖了真实组件在测试中最常被依赖的行为面。三、核心 Mock 实现剖析3.1 MockForm 与 withField用 EventEmitter 模拟表单双向绑定表单是数据库编辑弹窗中最复杂的交互载体。真实Form组件提供字段注册、校验、值变更通知等能力Mock 版本用约 110 行代码实现了一个简化的事件总线表单见 mock-form.tsx。核心是一个模块级EventEmittermock-form.tsx#L26-L47提供fire/on/off三个方法用Mapstring, ArrayFunction维护监听器。withField高阶组件将内部受控组件包装为“字段”export const withField (Comp, field) { const onChange useCallback(v { eventEmitter.fire(change, field.valueKey, v); }, []); return (props) { ... Comp onChange{v { if (props.validate(v.target.value) ! undefined) { return; } onChange(v.target.value); }} /; }; };withField用useCallback缓存onChange在值变更时向事件总线广播change事件同时保留validate校验钩子——校验失败返回非undefined时直接短路不触发变更。这保持了“校验通过才更新值”的真实表单语义。MockForm本身则用React.forwardRef暴露formApiexport const MockForm React.forwardRef((props, ref) { const valuesRef useRef(props.initValues); useImperativeHandle(ref, () ({ formApi: { validate: (_fields) true }, })); useEffect(() { eventEmitter.on(change, (...args) { valuesRef.current[args[0]] args[1]; props.onValueChange(valuesRef.current, args[1]); }); ... }, []); return {props.children}/; });MockForm将初始值存入valuesRef订阅事件总线上的change事件把最新值合并进valuesRef.current并回调onValueChange(values, changeValue)——前一个参数是完整表单值后一个是本次变更的字段值。useImperativeHandle暴露的formApi.validate恒返回true让测试中调用formRef.current.formApi.validate()的代码路径可以直接通过。Mock 还以静态属性形式挂载了Form.TextArea与Form.Select两个子组件mock-form.tsx#L114-L159TextArea是受控input内部用useState以initValue[props.field]初始化并广播变更Select将每个optionList选项渲染为button点击即广播对应字段的新值同时渲染label.extra附加元素。这样测试中screen.getByText()/fireEvent.click()可以直接命中 Mock 渲染出的原生元素。3.2 MockUITable忠实执行列 render 函数真实UITable的核心语义是“按列渲染数据”Mock 版本将这一语义压缩到极致见 mock-ui-table.tsxexport const MockUITable (props) { const { columns, dataSource } props.tableProps; return ( {columns.map(column { const { title, dataIndex, render } column; return ( div key{dataIndex} {title} {dataSource.map((data, index) render(undefined, data, index))} /div ); })} / ); };注意两点其一Mock 假设真实调用方以tableProps包裹列配置与数据源这与DatabaseModal中表格组件的实际使用方式一致其二Mock 会真实调用每列的render(text, record, index)渲染函数并执行其返回值因此测试能够断言表格中由render生成的按钮、标签等交互元素。这与直接渲染表格库的“行为面”保持了一致不 Mock 掉业务渲染逻辑只 Mock 掉容器框架。3.3 MockModal 与 MockPopConfirm把确认流程摊平成按钮弹窗类组件在测试中最关键的是确认/取消流程。MockModalmock-modal.tsx在visible为false时渲染no visible文本为true时渲染标题、children以及两个原生buttononCancel绑定cancelTextonOk绑定okText。测试可据此用fireEvent.click(screen.getByText(确认))触发确认回调验证保存逻辑。MockPopConfirmmock-popconfirm.tsx则直接渲染title、content、children并将onConfirm绑定到okText按钮——把真实组件“点击触发气泡→再确认”的两步操作摊平成一步简化了删除确认等流程的测试成本。3.4 MockSwitch 与 MockToast最小交互与完全静默MockSwitchmock-switch.tsx渲染为原生button文案为switch on/switch off点击时调用onChange(!checked)让测试可以验证开关状态的翻转MockToastmock-toast.tsx则将error/waring/success/info四个方法全部实现为空函数其中waring拼写沿用了调用方的原始命名保证业务代码中的提示调用在测试环境下静默通过。MockButtonmock-button.tsx则只保留onClick透传渲染为原生button避免组件库的样式类与事件绑定逻辑进入测试环境。四、清单在测试文件中的落地方式清单并非孤立存在其落地入口在 database-modal.test.tsx。测试文件通过两层vi.mock将真实依赖替换为清单中的 Mock第一层Mock 国际化与埋点等纯逻辑依赖如coze-arch/i18nI18n.t直接返回 key、coze-arch/report-events、coze-arch/bot-tea。第二层Mock 组件库本体database-modal.test.tsx#L63-L84vi.mock(coze-arch/bot-semi, async () { const actual: object await vi.importActual(coze-arch/bot-semi); const { MockPopover } (await vi.importActual( ./mock-components/mock-popover.tsx, )) as any; const { MockTextArea } (await vi.importActual( ./mock-components/mock-textarea.tsx, )) as any; ... return { ...actual, Popover: MockPopover, TextArea: MockTextArea, Popconfirm: MockPopconfirm, ToolTip: MockTooltip, }; });这里用vi.importActual保留组件库其余未 Mock 的部分...actual再按清单逐项覆盖Popover、TextArea、Popconfirm、ToolTip等条目实现“部分 Mock”而非“全量替换”。测试用例如MockButton、MockSwitch等则在渲染后通过testing-library/react的fireEvent.click/screen.getByText与之交互。五、Mock 清单的维护约定与注意事项结合仓库现状这套 Mock 机制有几条值得注意的约定清单即契约新增测试用例时若DatabaseModal未来引入新的bot-semi组件需要先在 readme.md 清单中登记再补对应mock-*.tsx实现否则vi.mock覆盖不全会导致测试环境渲染真实组件库而失败。废弃内容隔离__tests__/readme.md明确说明“这轮单测不包括 database-create-from-excel因为这个文件夹下的内容是废弃内容”因此 Excel 导入相关组件的 Mock 不在本清单范围内维护时不要为已废弃模块补充 Mock。Mock 粒度分层业务逻辑列render、表单校验、确认回调保持真实执行框架行为弹层、样式、国际化、埋点才 Mock 掉——这是该清单能同时保证测试稳定性与断言有效性的关键。语义化查询Mock 组件大多渲染为原生button/input或稳定文本如no visible、switch on/off测试断言应优先使用这些稳定输出避免依赖组件库内部 class 名。六、小结mock-components/readme.md虽只有一份组件名清单但它与同目录 17 个 Mock 实现文件、以及database-modal.test.tsx的vi.mock调用共同构成了一套完整的“组件库隔离测试”方案MockForm用事件总线复刻表单双向绑定MockUITable忠实执行列渲染函数MockModal/MockPopConfirm摊平确认流程MockToast静默化提示。这套清单驱动的 Mock 机制既保证了coze-data/database-creator在 Vitest 下的稳定运行也为 Coze Studio 其他前端包agent-ide、workflow、studio等同构包编写 UI 单测提供了可直接复用的范式。【免费下载链接】coze-studioAn AI agent development platform with all-in-one visual tools, simplifying agent creation, debugging, and deployment like never before. Coze your way to AI Agent creation.项目地址: https://gitcode.com/GitHub_Trending/co/coze-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考