
Ghost 如何编写 Core 服务端 E2E 测试request agent、fixture 与快照的用法【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/GhostGhost 仓库里有两套 E2E 测试写测试前先要分清是哪一套ghost/core/test/下的服务端 E2E 是 Vitest 套件直接 boot Ghost 并在进程内发请求文档见 ghost/core/test/README.md仓库根目录e2e/下则是 Playwright 浏览器套件验证 Admin 和公开站点完整流程两者互不替代。本文只讲服务端这套当你要为 Admin API、Content API 或 Members API 的新行为补一个端到端测试时如何用框架提供的 request agent、fixture 和快照匹配器把测试写出来并跑通它。先确认测试放在哪个 group服务端 E2E 分为四个主要 group来自 test/README.mdtest/e2e-api/API 边界的行为按 Admin/Content 等 API 再分子目录test/e2e-frontend/前端路由行为test/e2e-webhooks/外发 webhooktest/e2e-server/服务端行为。其中隔离运行的测试使用.isolated.test.js或.isolated.test.ts后缀由独立的e2e-isolatedproject 执行。README 给出的建议是从同一 group 里邻近的测试文件出发因为 boot 选项、agent 选择和清理要求随边界不同而变化。例如写 Admin API 测试可以打开 test/e2e-api/admin/authentication.test.js 看一个现成骨架每个 group 下都有已提交的__snapshots__目录可以对照快照长什么样。这些 DB-backed 套件由 vitest.config.db.ts 驱动配置里显式设置NODE_ENVtesting-mysql注释说明套件在 CI 和本地都跑在 MySQL 上——写新测试前确保你的环境能跑通既有 e2e 套件否则单文件验证没有意义。运行与验证命令所有命令从ghost/core目录执行来自 package.json 的 scripts# 跑完整服务端 E2Ee2e、e2e-api、e2e-isolated 三个 project pnpm test:e2e # 只跑单个测试文件 pnpm test:single test/e2e-api/path/to/test.test.jstest:single对test/*路径会带-c vitest.config.db.ts执行所以单个 e2e 文件用的是同一套 DB 配置。开发循环是写完测试 →pnpm test:single跑目标文件 → 通过后再用pnpm test:e2e确认没有和同 group 其他文件串味。搭建测试骨架request agent框架入口是 test/utils/e2e-framework.js。测试文件按所在目录深度引入它test/e2e-api/admin/下的文件用const {agentProvider, fixtureManager, mockManager, matchers} require(../../utils/e2e-framework);README 中的最小骨架针对test/e2e-api/group/一级目录相对路径深度以实际文件位置为准const {agentProvider, fixtureManager, mockManager, matchers} require(../utils/e2e-framework); let agent; beforeAll(async function () { agent await agentProvider.getAdminAPIAgent(); await fixtureManager.init(members); await agent.loginAsOwner(); });三行各司其职agentProvider.getAdminAPIAgent()负责 boot Ghost。agent 会自动完成以合适默认值 boot Ghost、重置数据库、配置 API base path、提供认证助手。agent.get(/posts/)这类调用不用再拼 URL 前缀。agentProvider还提供getMembersAPIAgent()、getContentAPIAgent()、getWebmentionsAPIAgent()、getGhostAPIAgent()、getAgentsForMembers()、getAgentsWithFrontend()等getAdminAPIAgent()支持{members: true}boot 时带前端和{staffTokenRole: ...}直接以对应角色的 fixture staff token 认证。getAgentsWithFrontend()会起真实 HTTP serverREADME 提示其清理要求与其他 agent 不同使用前先看同 group 邻近测试怎么处理。fixtureManager.init(members)插入测试所需的已知状态见下一节。agent.loginAsOwner()用 fixture 的 owner 完成登录。Admin agent 还有useStaffTokenFor(role)及按角色的便捷方法useStaffTokenForOwner()、useStaffTokenForAdmin()、useStaffTokenForEditor()等见 admin-api-test-agent.js。请求用 async/await 发起然后断言响应状态、body 和相关 header。用 fixture 构造已知状态fixtureManager.init()以具名任务插入数据把 Ghost 放到测试需要的状态。框架默认包含 owner fixture具名任务按需添加例如来自 test/README.mdusers为每个角色创建 staff 用户user:inactive追加一个非激活用户members、posts分别是 authentication.test.js 和 posts 测试实际使用的任务。插入后可以用fixtureManager.get(users, 1)按类型和下标取回具体记录断言时引用真实数据而不是写死值。README 明确旧测试里的localUtils.doAuth()和testUtils.setup()属于旧工具新的端到端测试应使用 fixture manager 和 request agent不要在测试里混用。发起请求并断言请求 agent 是 supertest 的替代drop-in substitution。请求后链式断言实际用例摘自 authentication.test.jsit(Cannot generate reset token without required info, async function () { await agent .post(authentication/password_reset) .expectStatus(400) .matchBodySnapshot({ errors: [ { id: anyErrorId, }, ], }); });要点expectStatus(400)断言状态码204这类空响应体用expectEmptyBodyREADME 的 Test style 一节。matchBodySnapshot()/matchHeaderSnapshot()是 agent 提供的快照匹配器整体 body 或 header 可以逐次运行保持一致地落盘比对但里面变化无常的值——对象 ID、UUID、日期、ETag、资源 location——要替换成快照匹配器。matchers里现成的有见 e2e-framework.jsanyObjectId、anyErrorId、anyUuid、anyISODateTime、anyISODate、anyEtag、anyContentLength、anyLocationFor(resource)、anyBoolean、anyString、anyNumber、anyObject、anyArray、nullable(expectedObject)。README 要求快照匹配器用于“每次运行都会变的值”而排序、副作用这类重要行为要加针对性的显式断言不要整体扔给快照。既然后端有副作用测试也要断言副作用不只是响应。更新快照与核对 .snap 文件首次运行或响应结构变化时快照会缺失或不匹配。README 给出的单测试更新方式是SNAPSHOT_UPDATE1 pnpm test:single test/e2e-api/path/to/test.test.js把路径换成你的测试文件。更新后逐一审查每个改动的.snap文件再提交——README 明确提醒生成的快照不证明响应是正确的快照匹配成功只说明“和上次记录一致”正确性仍由你写的显式断言保证。快照文件存放在测试同级的__snapshots__/下例如 test/e2e-api/admin/snapshots测试命名要保证在快照文件里依然读得懂。处理外发效果mockmockManager负责外部效果来自 test/README.md框架 boot 时禁用真实网络。外部服务一律走针对性 mock 或现成的mockManagerhelper不要依赖真实外呼。出站邮件用mockManager.mockMail()可检查发出的邮件并对 HTML、纯文本、metadata 做快照匹配每个测试之后恢复 mockauthentication.test.js 顶部即演示了const { mockMail, restore } require(../../utils/e2e-framework-mock-manager)的引入方式。出站 webhook 走同样的模式fixtureManager.insertWebhook({event, url}, {integrationType})可插入 webhook 记录。如果确实需要直接用 NockREADME 给了具体纪律匹配预期的 method 和 path请求体是契约的一部分时检查 body动态值路径用预期 path 和格式约束 matcher不要用 catch-all请求次数重要时用.times()避免.persist()可能掩盖非预期请求清理时用nock.cleanAll()移除直接 Nock 拦截器或用mockManager.restore()重置框架托管的状态不要用nock.restore()清理——它会关闭拦截之后需要nock.activate()才能再拦截。期望未被满足时用 Nock 的 pending mocks 诊断。限制与测试风格约束README 的 Test style 一节是新测试的硬约束值得在提交前逐条对照测试保持快速只发该行为所需的请求测试命名在快照文件里保持可读不使用旧测试工具断言响应之外还要断言副作用。另外注意两个边界差异e2e-server/下需要每文件独立状态的测试要用.isolated.test.js/.isolated.test.ts后缀对应e2e-isolatedproject否则普通 e2e project 会在 fork 内共享同一个 bootgetAgentsWithFrontend()起的是真实 HTTP server其清理路径与其他 agent 不同照抄同 group 邻近测试的处理方式即可。下一步单个文件跑绿只是起点。pnpm test:e2e覆盖e2e、e2e-api、e2e-isolated三个 project见 package.json提交前用它确认新测试与同 group 既有文件没有相互干扰CI 侧还有带覆盖率门槛的pnpm test:ci:e2e门槛数值定义在 vitest.config.db.ts。如果你的行为属于浏览器可见流程而不是服务端 API则应转到e2e/目录的 Playwright 套件那套的写法见 docs/contributing/e2e-testing.md。【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考