测试用例通过分层验证保障了Brainstorm Server的可靠性:集成测试模拟了完整的启动、服务、交互与监听生命周期;单元测试则深入验证了零依赖WebSocket协议实现的合规性。这套测试体系确保了从HTTP页面渲染、实时通信、文件变更响应到浏览器端事件收集的整个工作流闭环都能正确运行,是Superpowers可视化头脑风暴功能的质量基石。
Brainstorm Server 测试用例解读:HTTP、WebSocket、文件监听和浏览器事件如何验证
Superpowers 的可视化头脑风暴(Visual Brainstorming)功能依赖一个专门的 Brainstorm Server 作为后端。这个服务器的职责是:为浏览器提供内容页面、通过 WebSocket 实时通信、监听文件变化并推送更新,以及收集用户的交互选择。为了确保这个关键组件的稳定与正确,项目采用了两套测试用例:一套集成测试模拟真实使用场景,一套单元测试深入协议细节。理解这些测试,就是理解这个服务的设计意图和质量保障策略。
1. 集成测试:模拟完整的服务器生命周期
server.test.js 是核心的集成测试。它不依赖外部测试框架,通过 spawn 启动真实的服务器进程,并通过 HTTP 请求和 WebSocket 客户端与之交互,验证从启动到运行再到事件处理的各个环节。
测试流程始于 startServer 函数,它通过设置环境变量 BRAINSTORM_PORT 和 BRAINSTORM_DIR 来控制服务器在隔离的临时目录下运行。随后的 waitForServer 会等待服务器在标准输出中打印 server-started JSON 消息,这个信号表明服务已就绪。
服务器启动与状态持久化 的测试是基础。测试验证了启动输出的 JSON 包含正确的 port、url 和 screen_dir 信息。更重要的是,它检查了服务器是否将这份同样的信息(server-info)写入到了 state/ 目录。这个设计允许其他工具或代理通过读取文件来发现服务地址和配置,实现了进程间的解耦。源码 server.cjs 中的 startServer 函数在 server.listen 回调里完成了这两件事。
2. HTTP 服务测试:从等待页面到内容渲染
HTTP 服务测试覆盖了多种场景。当 content/ 目录为空时,服务器应返回一个内置的“等待页面”(WAITING_PAGE)。测试不仅验证了页面状态码和内容,还检查了 helper.js 脚本是否被成功注入。这个注入逻辑在 server.cjs 的 handleRequest 函数中,它会在 </body> 标签前插入包含 WebSocket 客户端代码和交互 API 的脚本。
测试用例中一个有趣的设计点是 完整文档与片段包裹 的处理。如果代理推送的 HTML 文件以 <!DOCTYPE> 或 <html> 开头(通过 isFullDocument 函数判断),服务器会原样提供,但仍注入 helper.js。如果推送的只是一个 HTML 片段(比如一个选项卡布局),服务器会将其包裹在 frame-template.html 这个通用框架模板中。模板提供了统一的样式、状态指示条和布局结构。测试通过检查返回的页面是否包含 indicator-bar 来验证包裹逻辑,同时确保片段内容本身(如 data-choice 属性)得以保留。
服务器总是为根路径 / 提供服务,并且会智能地选择 content/ 目录下修改时间最新的 .html 文件。测试通过在不同时间点创建 older.html 和 newer.html,并验证返回内容来证明这一点。此外,测试还确认服务器会忽略非 .html 文件(如 .json),并且对任何非根路径的请求返回 404。
3. WebSocket 通信测试:事件流与协议健壮性
WebSocket 测试验证了实时双向通信的核心。首先,测试确认服务器能在 / 路径上接受 WebSocket 升级。然后,它测试了用户事件中继:客户端发送的 JSON 事件(如 click)会被服务器在标准输出中以 source: "user-event" 的标签重新输出,这是代理(如 Claude Code)捕获用户选择的关键通道。
更具体地,测试验证了选择事件持久化。当客户端发送包含 choice 字段的事件时,服务器会将其追加写入 state/events 文件。这个文件是状态转移的关键,代理可以轮询或监听此文件来获取用户的最新选择。相反,不包含 choice 的事件(如 hover)则不会写入该文件。测试通过发送不同类型的消息并检查文件是否存在或内容来验证此逻辑。
测试还关注了并发与健壮性。它验证了多个 WebSocket 客户端都能接收到广播的 reload 消息(当文件变化时)。它也测试了当一个客户端断开后,服务器仍能正常广播而不会出错。特别重要的是对畸形 JSON 的处理:客户端发送无效的 JSON 字符串,测试验证服务器不会崩溃,且仍能正常处理后续的 HTTP 请求,这体现了防御性编程的思想。
4. 文件监听与状态管理测试
文件监听是实时更新体验的基础。测试使用 fs.watch 的模拟行为(通过在不同时间写入文件)来验证。服务器应该只对 .html 文件的新建或修改做出反应,向所有客户端广播 reload 消息,并在控制台输出 screen-added 或 screen-updated 的日志。对于非 .html 文件的变化,测试验证服务器保持静默。
一个关键的状态管理逻辑是:当有新屏幕(.html 文件)被添加时,state/events 文件会被自动清除。这确保了每次开始一个新的头脑风暴页面时,之前的用户选择会被清空,避免状态污染。测试通过预先创建 events 文件,然后触发新屏幕添加,最后断言 events 文件被删除来验证此行为。
5. 浏览器端脚本验证与协议单元测试
除了集成行为,测试还对核心的浏览器端脚本和协议实现进行了验证。
helper.js 验证 检查了它是否定义了 toggleSelect、sendEvent、selectedChoice 和 brainstorm 这些关键 API。frame-template.html 验证则确保模板包含了 indicator-bar、claude-content 容器等必要结构,为 UI 提供了正确的骨架。
ws-protocol.test.js 是一套纯单元测试,直接测试从 server.cjs 导出的 WebSocket 协议函数。它验证了:
- 握手:
computeAcceptKey函数能根据 RFC 6455 标准计算正确的Sec-WebSocket-Accept值。 - 帧编码/解码:
encodeFrame和decodeFrame函数能正确处理各种长度的负载,特别是关键的边界值(125、126、65535、65536 字节),因为这决定了负载长度字段使用 1 字节、2 字节还是 8 字节来表示。 - 协议合规性:测试确保服务器发出的帧永远不会设置掩码位(符合 RFC 6455),而客户端发来的帧必须设置掩码位,否则解码函数会抛出错误。
- 关闭与控制帧:正确解码带有状态码和原因的关闭帧,以及对 Ping/Pong 帧的处理。
- 流式解码:
decodeFrame能正确处理不完整的帧头或载荷,返回null而非错误,支持从数据流中逐步解析出多个帧。
package.json 中声明的 ws 依赖仅用于集成测试,作为标准的 WebSocket 客户端来与服务器交互,而服务器自身则是一个零依赖的实现。这体现了清晰的关注点分离:产品代码保持轻量,测试代码则利用成熟库来简化验证。
总结:测试即设计文档
这些测试用例远不止是防止回归的工具,它们共同构成了 Brainstorm Server 的可执行设计文档。通过阅读测试,开发者可以快速理解:
- 服务器的启动流程和配置发现机制(
server-info文件)。 - HTTP 层如何区分完整页面与片段,并应用不同处理策略。
- WebSocket 如何作为用户交互的选择通道,并将关键事件持久化。
- 文件监听如何触发浏览器重置,并管理选择状态的生命周期。
- 底层 WebSocket 协议实现如何严格遵循 RFC 6455 标准。
这套测试体系是 Superpowers brainstorming 技能 和 Server 架构 可靠性的基石,它确保了从终端到浏览器的整个可视化头脑风暴工作流能够稳定、正确地运行。
FAQ
Q: 为什么集成测试使用 ws 包作为依赖?
A: ws 是 Node.js 生态中广泛使用且符合标准的 WebSocket 客户端库,仅在测试 package.json 中作为开发依赖引入。用它来测试 Brainstorm Server 的 WebSocket 功能,可以确保测试的可靠性和标准兼容性,而服务器自身发布时不需要携带此依赖。
Q: 这些测试如何覆盖跨平台场景(如 Windows)?
A: 通过使用 Node.js 核心的 fs 和 child_process 模块,并操作临时目录 (/tmp/...),测试在 macOS 和 Linux 上能直接运行。对于 Windows 的特定问题(如路径分隔符、fs.watch 行为),主要依靠 server.cjs 源码中的兼容性处理(如 path.join),以及在 服务器生命周期文档 中单独说明排错指南。