首页
/ RealWorld 规范仓库实战指南:CLAUDE.md 定位解读、Hurl/Bruno 测试套件运行机制与文档工作流

RealWorld 规范仓库实战指南:CLAUDE.md 定位解读、Hurl/Bruno 测试套件运行机制与文档工作流

2026-09-03 15:19:34作者:毕习沙Eudora

本文以 CLAUDE.md 为主线,结合 Makefilespecs/apispecs/e2edocs/ 的源码与脚本细节,完整讲清楚 RealWorld 规范仓库(spec & docs hub)的定位、目录约定、API 与 E2E 测试套件的运行机制,以及文档站的本地开发流程。读完之后,你既能把这个仓库作为子模块嵌入自己的 RealWorld 实现并跑通全部验证套件,也能理解“Hurl 是 source of truth、Bruno 是生成物”这套测试工程约定的底层原理。

一、仓库定位:这是契约中枢,不是可运行应用

CLAUDE.md 开篇即明确:本仓库是 RealWorld spec & docs hub——它定义每个 RealWorld 前端/后端实现必须遵守的契约,并托管用于验证实现的测试套件,仓库内没有任何可直接运行的应用

顶层目录分工如下:

路径 职责
specs/api/ API 契约:openapi.yml + 后端必须通过的 HurlBruno 测试套件
specs/e2e/ 验证前端的共享 Playwright 套件,外加选择器契约 SELECTORS.mdplaywright.base.ts
docs/ 用 Astro/Starlight 构建的文档站点
Makefile 所有操作入口(make help 查看)
CONTRIBUTING.md 人类贡献流程

这个定位直接决定了后续所有协作规则:specs/ 下的文件是真相源(source of truth),实现方必须向其对齐,而不是反过来。

作为子模块 / vendored 依赖使用时的红线

CLAUDE.md 特别强调了一个高频场景:实现方会把本仓库以 submodule 或 vendored 方式嵌入自己的代码库(E2E 套件在实现方那边就是被当作 ./e2e 消费的),用规范来测试自己的实现。此时有两条硬规则:

  • 修实现,永远不要为了让测试通过而编辑规范或测试本身。 specs/ 下的文件是失败的实现必须向其看齐的真相源;
  • 只有当任务本身明确是“修改 RealWorld 规范”时,才允许修改本仓库文件。

这条规则的意义在于防止“改测试迁就实现”的反模式:一旦测试套件被本地改动,契约就失去了约束力。

二、三条核心约定(Conventions)

CLAUDE.md 给出三条约定,每一条都能在仓库中找到对应的落地证据:

  1. 本仓库内一切操作使用 bun,而非 npm/node Makefile 中所有目标均为 bun ... 命令,例如 bruno-generate 执行 bun specs/api/hurl-to-bruno.jsdocumentation-setup 执行 cd docs && bun install
  2. Hurl 是 API 套件的 source of truth;Bruno collection 由它生成。不要手改 specs/api/bruno/——改 Hurl 文件后重新生成。 specs/api/README.md 中同样声明:Bruno collection 由 make bruno-generate 生成,并通过 CI(make bruno-check)保持同步。
  3. 文档 URL 一律带尾部斜杠(trailing slash)。 这是文档站写作规范,与 docs/astro.config.mjs 中 Starlight 的 sidebar slug(如 specifications/frontend/tests)配合,保证生成的路由 URL 风格一致。

三、API 测试套件:Hurl 主套件与 Bruno 镜像套件

CLAUDE.md 给出的运行命令为(指向一个正在运行的后端,从 specs/api/ 目录执行):

HOST=http://localhost:3000/api ./run-api-tests-hurl.sh    # source of truth
HOST=http://localhost:3000/api ./run-api-tests-bruno.sh    # generated mirror

下面结合两个脚本的源码,把参数与机制讲透。

3.1 Hurl 脚本:run-api-tests-hurl.sh

脚本核心逻辑只有 10 余行,但设计上有几个值得注意的点:

HOST="${HOST:-http://localhost:8000}"
UID_VAL="${UID_VAL:-$(date +%s)$$}"
  • HOST:被测后端地址,默认 http://localhost:8000;注意默认不含 /api 前缀,实际使用时(如 CLAUDE.md 示例)要显式带上你的 API 前缀;
  • UID_VAL:默认值为 时间戳 + 进程 PID 拼接的唯一 ID。它作为变量传入 Hurl,用于生成隔离的测试账号。以 specs/api/hurl/auth.hurl 为例,注册请求体是 "username": "auth_{{uid}}""email": "auth_{{uid}}@test.com"——同一后端上并发或重复跑套件时,uid 保证了账号不冲突;
  • 支持位置参数:不带参数时运行 hurl/*.hurl 全部文件,带参数时只跑指定文件,便于定位单个模块(如只跑 hurl/feed.hurl);
  • 实际执行命令为 hurl --test --jobs 1 --variable "host=$HOST" --variable "uid=$UID_VAL" "${FILES[@]}",其中 --jobs 1 表示串行执行,这与测试间存在“先注册、后登录、再验证持久化”的有序依赖(每个 .hurl 文件内请求顺序敏感,如 specs/api/hurl/auth.hurl 中的 Register → Login → Get current user → Update user → Verify update persisted)相配合。

3.2 Bruno 脚本:run-api-tests-bruno.sh

Bruno 版脚本是 Hurl 套件的“镜像”:

BRUNO_SANDBOX="${BRUNO_SANDBOX:-safe}"
bun x @usebruno/cli run "$folder" --env local --env-var "host=$HOST" --sandbox "$BRUNO_SANDBOX"
  • 默认扫描 bruno/ 下的每个文件夹(自动跳过 environments/——它只是环境定义,见 specs/api/bruno/environments/local.bru),也支持传入文件夹名只跑一部分;
  • 通过 --env local 加载环境配置,用 --env-var "host=$HOST" 注入被测地址,--sandbox 控制脚本沙箱级别(默认 safe);
  • bun x @usebruno/cli 临时拉取 Bruno CLI,无需预先安装。

Bruno 版的所有请求文件夹(articles/auth/comments/feed/pagination/errors-*/ 等)与 Hurl 文件一一对应,且文件名带有序号前缀(如 specs/api/bruno/auth/01-register.bru),体现了同样的顺序执行语义。[specs/api/README.md](https://gitcode.com/GitHub_Trending/re/realworld/blob/077acadfef620af681090c336c68ae754a92a797/specs/api/README.md?utm_source=gitcode_repo_files) 还补充了一点:也可以把 bruno/ 文件夹直接拖进 Bruno 桌面应用交互式地运行和检查每个请求。

3.3 生成与校验:make bruno-generate / make bruno-check

CLAUDE.md 给出的两个维护命令在 Makefile 中的定义:

bruno-generate:
	bun specs/api/hurl-to-bruno.js

bruno-check:
	bun specs/api/hurl-to-bruno.js --check

生成器 specs/api/hurl-to-bruno.js 的工作原理可以从源码结构看到:

  • 解析:实现了一个小型状态机解析器(IDLEHEADERSBODY),以 # 注释行作为请求分隔符并作为请求命名来源,识别 GET/POST/PUT/DELETE/PATCH 方法行、Key: Value 头、以及用花括号深度计数定位边界的 JSON body,同时抽取状态码、[Asserts][Captures] 区块;
  • 生成:将解析出的请求写入 bruno/ 目录,按 Hurl 文件划分为文件夹;
  • --check 模式:CI 校验模式,当 bruno/ 目录与 Hurl 文件不同步时让检查失败,从而在 CI 中强制执行“Bruno 目录永远由 Hurl 派生”的约定。

四、E2E 测试套件:实现方如何接入 Playwright 共享套件

CLAUDE.md 对 E2E 的说明是:实现方在自己的配置中扩展 specs/e2e/playwright.base.ts(覆写 baseURLwebServer),并满足 specs/e2e/SELECTORS.md 的选择器契约。

4.1 基础配置提供了什么

playwright.base.ts 导出的 baseConfig 关键项:

  • testDir: './e2e':套件约定放在实现方仓库的 ./e2e 目录——这正是 CLAUDE.md 所说“E2E suite is literally consumed as ./e2e”的含义;
  • fullyParallel: false + workers: 1:严格串行,避免账号/数据相互污染;
  • retries: CI ? 2 : 1forbidOnly: !!process.env.CI:CI 上禁止 .only 意外混入;
  • timeout: 15_000actionTimeout: 5_000navigationTimeout: 10_000trace: 'on-first-retry'screenshot: 'only-on-failure':失败自动留痕;
  • 仅一个 chromium(Desktop Chrome)project。

文件头部的注释直接给出了实现方的接入模板:

import { defineConfig } from '@playwright/test';
import { baseConfig } from './e2e/playwright.base';

export default defineConfig({
  ...baseConfig,
  use: { ...baseConfig.use, baseURL: 'http://localhost:3000' },
  webServer: {
    command: 'npm run start',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120_000,
  },
});

即只需覆写 baseURLwebServer 指向自己的开发服务器,其余行为完全继承。

4.2 选择器契约(SELECTORS.md)

specs/e2e/SELECTORS.md 列出了共享 E2E 测试依赖的全部 CSS 类、HTML 属性、文本标签、路由与接口。任何想使用该套件的实现必须提供其中所有选择器,主要包括:

  • 表单 name 属性username/email/password(Login、Register、Settings 页)、title/description/body(Editor 页)等;
  • 布局与导航类.navbar.navbar-brand.nav-link.banner.container
  • Feed 与文章类.feed-toggle.article-preview.article-meta.article-content.article-page.preview-link.empty-feed-message 等;
  • 标签、评论、Profile 类.tag-list.tag-pill.comment-form.card-block.profile-page 等,测试用 .card:not(.comment-form) .card-block 选择已发布的评论;
  • 此外还约定了按钮/链接的文本内容、路由、调试接口(window.__conduit_debug__)、JWT token 的 LocalStorage key、默认头像行为等。

套件覆盖范围包括鉴权、文章、评论、导航、设置、社交功能、错误处理,甚至基础 XSS 安全检查(对应 specs/e2e/ 下的 auth.spec.tsarticles.spec.tsxss-security.spec.ts 等),docs/src/content/docs/specifications/frontend/tests.md 也明确该套件是“validate your frontend implementation”的共享工具。

五、文档站工作流(docs/)

CLAUDE.md 提供的文档操作命令与 Makefiledocumentation-* 目标一一对应:

make documentation-setup     # cd docs && bun install
make documentation-dev       # cd docs && bun run dev(本地开发服务器)
make documentation-build     # cd docs && bun run build(生产构建)

Makefile 中还有 CLAUDE.md 未逐条列出的 documentation-dev-host(带 --host 暴露到局域网)、documentation-preview(预览生产构建)与 documentation-clean(清理 docs/.astrodocs/distdocs/node_modules)。

docs/astro.config.mjs 可以看到站点的技术构成:Astro + @astrojs/starlight 主题 + Tailwind(@tailwindcss/vite),站点标题为 RealWorld,sidebar 分三大板块——Implementation creation(Introduction / Features / Expectations)、Specifications(Frontend:Templates/Styles/Routing/API/Tests;Backend:Introduction/Endpoints/API response format/CORS/Error handling/Hurl/Tests;Mobile)、Community。内容源文件位于 docs/src/content/docs/ 下,与 sidebar slug 一一对应。配置里还有一个自定义 Vite 插件 removeMdExtension,用于在构建时去掉 URL 中的 .md 后缀,配合前述“文档 URL 带尾部斜杠”的约定,产出干净的路由。

六、当用户问“怎么搭建一个实现”

CLAUDE.md 的最后一条指引同样重要:实现(implementations)在各自独立的仓库中,本仓库不托管任何官方实现。正确的引导方式是:

七、小结:这个仓库的工程约定为什么值得借鉴

CLAUDE.md 篇幅不长,却把一类典型“契约型仓库”的协作规则压缩得非常完整:

  1. 单一真相源 + 生成物:Hurl 是唯一手写源,Bruno 目录是纯派生产物,--check 模式把“不许手改生成物”变成了 CI 可执行的检查;
  2. 不可篡改的验证基准:当仓库以 submodule 形式嵌入实现方时,测试是尺子而不是橡皮泥——修实现、永不改测试;
  3. 最小可继承的配置:Playwright 基础配置把重试、超时、串行、失败留痕等策略固化,实现方只覆写两三个字段即可接入;
  4. 统一工具链bun + make help 作为唯一入口,降低了跨工具链的心智负担。

如果你正在为某个框架写 RealWorld 实现,最直接的起点就是:把本仓库挂到实现仓库的 specs/e2e 路径下,按 make help 与上文脚本参数跑通 Hurl 套件与 Playwright 套件,并逐条对照 specs/e2e/SELECTORS.md 补齐选择器——绿了,即代表你的实现符合 RealWorld 契约。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
903
1.82 K
docsdocs
暂无描述
Markdown
888
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.51 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341