恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

wp-calypso Dashboard 测试策略指南:E2E、nock 网络拦截与单元测试实战

  • 首页
  • 资讯中心
  • /
  • wp-calypso Dashboard 测试策略指南:E2E、nock 网络拦截与单元测试实战

相关资讯

广义估计方程GEE实战:重复测量数据建模、相关结构选型与R/Python实现 2026/9/25 13:45:25
等保三级整改实战:3人小队用Cursor一周搞定数十个系统的敏感数据加密 2026/9/25 13:45:25
Dart SDK 中的 Dart Development Service(DDS)实战指南:协议转发、SSE 通信与扩展 RPC 深度解析 2026/9/25 13:45:25

最新资讯

@microsoft/fast-colors 的 interpolateHSL() 函数:基于 HSL 色彩空间的颜色插值 API 实战指南
Atlas 300V 24G部署YOLO实战:从模型转换到推理调优全指南
sinon 异步回调触发指南:深入解析 stub.callsArgAsync(index) 的机制与应用
CPU架构选型实战:x86_64、ARM64与龙架构的生态差异与避坑指南
告别3公里网线:一个巴掌大的盒子如何实现远距离组网
昇腾Atlas 300V 24G推理卡部署YOLOv5实战:从环境配置到性能调优

今日推荐

AI元人文:从工具使用到思维重构的深度探索
Python+CNN车牌识别实战:从数据预处理到模型训练与部署
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

wp-calypso Dashboard 测试策略指南:E2E、nock 网络拦截与单元测试实战

发布时间:2026/9/25 13:45:25
wp-calypso Dashboard 测试策略指南:E2E、nock 网络拦截与单元测试实战 前端CMS【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址https://gitcode.com/gh_mirrors/wp/wp-calypso点击查看免费下载wp-calypso 的 dashboard新多站点托管控制台即 my.wordpress.com是一个典型的 UI 密集型前端应用测试策略直接关系到迭代时的可靠性、可维护性与性能。client/dashboard/docs/testing.md 系统性地定义了该模块从 E2E 到单元测试的完整实践E2E 测试复用 Calypso 既有基础设施specs 与 Page Object 分离单元测试则以testing-library/react加nock网络拦截为核心并辅以清晰的代码规范ES import 代替内联require、Query Cache 数据注入等。本文以该文档为主体结合仓库中的真实实现test-utils.tsx、dashboard-page.ts 与 test/e2e/specs/dashboard/dashboard__basic-and-routing.spec.ts深入展开帮助你直接把这些策略落地到 dashboard 的日常开发中。E2E 测试复用 Calypso 既有基础设施当前方案specs 与 Page Object 分离dashboard 的 E2E 测试直接复用 Calypso 的整套基础设施其核心理念是把**测试用例specs与页面对象Page Object以及可选的 components**分离开来Page Object 代表某个页面如DashboardPage并提供用于交互与断言的具体方法specs 则只负责描述业务场景。仓库中对应的两个目录分别为test/e2e/specs/dashboard/ —— 存放 dashboard 的 E2E 用例如dashboard__basic-and-routing.spec.tspackages/calypso-e2e/src/lib/pages/dashboard-page.ts —— 定义DashboardPage页面对象。以真实用例 dashboard__basic-and-routing.spec.ts 为例可以看到 specs 如何只关注业务步骤把页面操作全部委托给pageDashboardtest( As a WordPress.com user, I can see the new Multi-site Dashboard page as a list of my sites, async ( { accountGivenByEnvironment, clientRestAPI, page, pageDashboard, } ) { await test.step( Given I am authenticated as ${ accountGivenByEnvironment.accountName }, async function () { await snoozeAccountRecoveryInterstitial( clientRestAPI ); await accountGivenByEnvironment.authenticate( page ); } ); await test.step( When I visit the dashboard page, async function () { await pageDashboard.visit(); } ); await test.step( Then I see the WordPress.com Multi-site Dashboard page (list of sites), async function () { expect( await pageDashboard.isLoaded() ).toBe( true ); expect( await pageDashboard.getHeadingText() ).toEqual( Sites ); } ); } );对应的DashboardPage在 dashboard-page.ts 中封装了如下能力visit()跳转到 dashboard 入口并自动尝试关闭欢迎弹窗因为它会遮挡main内容随后等待main区域可见dismissWelcomeModal()在 3 秒内轮询Meet the new WordPress.com Hosting Dashboard标题与Try it out按钮弹窗未出现时静默跳过isLoaded()断言主内容可见且 URL 包含 dashboard 地址用于校验页面是否真正加载完成getHeadingText()获取页面首个 heading 文本如用例中断言SitesnavigateToSection( name )/visitPath( path )按导航项名称点击或直接访问子路径如me/non-existent-pageis404Page()判断当前是否为 404 页配合expect.poll()使用因为 404 标题可能不会立即出现。这种抽象带来的收益正如文档所说系统已经解决了大量既有难题尤其是用户认证。你不需要在每条用例里重复处理登录态只需通过accountGivenByEnvironment.authenticate( page )这样的环境注入即可。代价是这套基础设施特别是让 Playwright 跑起来所需的 secrets 解密缺少集中的文档说明学习成本集中在测试框架本身而不是业务逻辑。下一步方向轻量化的取舍文档明确记录了对未来方向的思考考虑更轻量、更少抽象的方式去掉 Page Object。理由是新 dashboard 并不值得为此增加额外复杂度。这意味着后续 dashboard 的 E2E 用例可能趋向于直接在 specs 中操作 Playwright 的page对象。不过截至当前仓库状态DashboardPage及其目录结构仍然是 dashboard E2E 的事实标准新用例应优先沿用现有模式以保持一致。单元测试面向用户视角的集成测试使用render()渲染带完整上下文的组件dashboard 的组件测试推荐用testing-library/react测试前端的整块切片从而写出更贴近用户视角的断言。关键入口是 client/dashboard/test-utils.tsx 中导出的render()函数。它会在渲染组件时自动包上完整的 Context Provider让 hooks 正常工作包括QueryClientProvider基于tanstack/react-query默认关闭查询重试AppProvider应用级配置默认使用APP_CONTEXT_DEFAULT_CONFIGAnalyticsProvider自动注入recordTracksEvent、recordPageView两个 jest mock测试可直接断言埋点AuthContext.Provider默认注入一个测试用户testuser/testexample.com也可通过 options 覆盖RouterProvider用createTestRouter包一层带Suspense的根路由。因此测试代码无需手动wrap任何 Provider直接调用即可import { render } from ../../test-utils; import { SiteLogs } from ../index; render( SiteLogs logTypephp siteSlugtest-site / ); expect( await screen.findByText( Something happened ) ).toBeVisible();上面的断言取自 client/dashboard/sites/logs/test/index.test.tsx 的真实用例展示了渲染组件 → 等待真实文本出现的用户视角测试方式。render()同时支持options覆盖选项类型说明userUser替换默认测试用户默认{ ID: 1, username: testuser, ... }queryClientQueryClient传入自建 QueryClient用于预置缓存数据见下文configAppConfig覆盖应用配置默认APP_CONTEXT_DEFAULT_CONFIG用 nock 拦截网络请求dashboard 的查询queries与变更mutations都通过 HTTP 调用https://public-api.wordpress.com因此单元测试用nock拦截这些请求即可无需 mock React Query 本身import nock from nock;重要约定nock.cleanAll()已在全局的afterEach中被调用所以你的测试文件里不需要再写afterEach( () nock.cleanAll() )写多了反而冗余。URL 路径规则由 API namespace 决定使用apiNamespace: wpcom/v2的 API → 路径以/wpcom/v2/…开头无 namespace 的 REST API → 路径以/rest/v1.1/…开头。拦截查询GETnock( https://public-api.wordpress.com ) .get( /wpcom/v2/sites/${ siteId }/hosting/error-logs ) .query( true ) // 匹配任意 query string .reply( 200, { data: { logs: [], total_results: 0, scroll_id: null } } );.query( true )表示不关心具体查询参数只要路径匹配即可。真实的 dashboard 测试中也常见.persist()让同一 mock 在多次请求中持续生效例如 logs/test/index.test.tsx 中对用户偏好、站点信息与 PHP 错误日志三个接口的拦截。拦截变更POSTconst scope nock( https://public-api.wordpress.com ) .post( /rest/v1.1/me/preferences, ( body ) { // 可选在这里检查请求体 return true; } ) .reply( 200, { calypso_preferences: {} } ); // …触发变更… // 可选断言 scope 内所有 endpoint 都被调用过 expect( scope.isDone() ).toBe( true );DELETE 请求wpcom.req.post( { method: DELETE, … } )实际发送的是 HTTP DELETE所以要用.delete()而不是.post()nock( https://public-api.wordpress.com ) .delete( /wpcom/v2/sites/${ productionSiteId }/staging-site/${ stagingSiteId } ) .reply( 200, {} );Tips避免nock.delay()—— 它会留下未关闭的句柄触发 Jest did not exit 警告用scope.isDone()断言请求确实发生过防止mock 没被命中的假绿不关心具体 query string 时一律用.query( true )。断言请求体在 body 回调里用 Jest matcher要在拦截变更时校验请求体内容直接在 nock 的 body 回调里使用 Jest matcher 即可最后再用scope.isDone()确认请求真的发出const scope nock( https://public-api.wordpress.com ) .post( /rest/v1.1/me/preferences, ( body ) { expect( body ).toEqual( expect.objectContaining( { my_key: strict string check, some_string: expect.any( String ), pi: expect.closeTo( 3.14 ), } ) ); return true; } ) .reply( 200, { calypso_preferences: {} } ); // …触发变更… await waitFor( () { expect( scope.isDone() ).toBe( true ); } );这里可以组合多种 Jest 异步匹配器expect.any( String )只校验类型、expect.closeTo( 3.14 )校验浮点近似值、expect.objectContaining( … )做部分匹配用waitFor包裹isDone()断言可以避免时序抖动。Mock 查询缓存数据注入 QueryClient而不是 mock React Query不要 mocktanstack/react-query或automattic/api-queries。如果某个需要 mock 的数据无法在网络层完成例如 staging site 的删除进度这类前端状态就创建一个全新的QueryClient通过render()的queryClient选项传入import { QueryClient } from tanstack/react-query; import { render } from ../../test-utils; const queryClient new QueryClient(); queryClient.setQueryData( [ staging-site, 1, is-deleting ], true ); render( MyComponent /, { queryClient } );核心原则是能 mock 网络请求就优先 mock 网络请求见上一节只有无法在网络层表达的状态才退回到 QueryClient 缓存注入。这样既避免了过度 mock 导致测试与真实行为脱节又能覆盖那些纯前端驱动的中间状态。Mock 模块用 ES import而不是require()为什么不能用内联require()Jest 会把jest.mock()调用提升hoist到所有 import 之上因此文件顶层的 ES import 拿到的已经是 mock 后的版本。反过来如果你在测试体内用内联require()去取 mock一来多此一举二来会触发 ESLint 规则typescript-eslint/no-require-imports报错// ❌ 错误用惰性 require 去取 mock test( saves preferences, () { // eslint-disable-next-line typescript-eslint/no-require-imports const { userPreferencesMutation } require( automattic/api-queries ); userPreferencesMutation.mockReturnValue( /* … */ ); } );正确写法是顶层 import 类型断言// ✅ 正确顶层 import 类型断言 import { userPreferencesMutation } from automattic/api-queries; jest.mock( automattic/api-queries ); test( saves preferences, () { ( userPreferencesMutation as jest.Mock ).mockReturnValue( /* … */ ); } );什么时候才需要延迟加载只有真正用到jest.resetModules()、jest.isolateModules()或jest.doMock()时延迟加载才有意义——即便如此也优先用await import()而不是require()。唯一的例外mock factory 里用jest.requireActual()jest.mock()的 factory 在 import 初始化之前执行因此它无法引用顶层 import。需要在 factory 里访问真实模块时使用jest.requireActual()jest.mock( some-module, () { const { createElement } jest.requireActual( react ); // … } );工具函数的测试取舍先判断复杂度dashboard 里有一部分工具函数只做了解构或单个布尔运算。文档给出的决策流程是先检查复杂度它是否涉及正则、日期解析、校验逻辑或多个边界情况如果否为使用该工具的组件写集成测试即可不要为它单独建测试文件。例如简单的isP2()应该由类似button is disabled for P2s的集成测试来覆盖而不是自己的单测文件。如果是才写独立的单元测试重点覆盖边界情况。这条规则的目的是保持测试资产精简把简单的工具函数测试消化进组件的用户视角断言中既节省了维护成本又让测试更接近真实行为只有真正存在复杂逻辑的工具函数才值得独立成文件。小结dashboard 测试的分层心法综合 testing.md 与仓库实现可以总结出 dashboard 测试的四条主线E2E 层复用 Calypso 现有基础设施specs Page Object认证等难题交给框架解决保持用例专注于业务场景集成层render()一键注入全部 Provider配合nock在网络层拦截https://public-api.wordpress.com的请求用用户可见的文本与行为做断言状态层不 mock React Query需要预置状态时注入自建QueryClient的缓存数据规范层坚持顶层 ES import jest.mock()拒绝内联require()工具函数按复杂度决定是否独立成测试文件。遵循这套策略dashboard 的每一次迭代都能在可靠与低成本维护之间取得平衡——这正是文档开篇所强调的作为 UI 密集的前端项目E2E 是迭代时建立信任的关键而单元测试侧的网络拦截与 Provider 注入则让日常功能开发更快、更稳。赞分享前端CMS【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址https://gitcode.com/gh_mirrors/wp/wp-calypso点击查看免费下载相关推荐x265入门指南5分钟快速安装并开始你的第一个HEVC视频编码x265入门指南5分钟快速安装并开始你的第一个HEVC视频编码 想要高效压缩视频文件同时保持卓越的画质吗x265 HEVC编码器正是您需要的终极解决方案音视频视频处理roadmap.sh测试策略单元测试与E2E测试roadmap.sh测试策略单元测试与E2E测试 概述 roadmap.sh作为开发者学习路径平台采用现代化的测试策略确保代码质量和用户体验。项目基于Ast文档教程知识库ApolloPatcher开发者指南从零开始构建iOS越狱插件ApolloPatcher开发者指南从零开始构建iOS越狱插件 ApolloPatcher是一款为Reddit客户端Apollo打造的iOS越狱插件支持在应创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号