LibreChat E2E 测试体系实战:Mock 假模型、Redis 流传输分片与 Bombadil 属性化浏览器探索
2026/9/6 16:57:11 网站建设 项目流程

LibreChat E2E 测试体系实战:Mock 假模型、Redis 流传输分片与 Bombadil 属性化浏览器探索

【免费下载链接】LibreChatEnhanced ChatGPT Clone: Features Agents, MCP, Skills, DeepSeek, Anthropic, AWS, OpenAI, Responses API, Azure, Groq, o1, GPT-5, Mistral, OpenRouter, Vertex AI, Gemini, Artifacts, AI model switching, message search, Code Interpreter, langchain, DALL-E-3, OpenAPI Actions, Functions, Secure Multi-User Auth, Presets, open-source for self-hosting. Active项目地址: https://gitcode.com/GitHub_Trending/li/LibreChat

本文以 LibreChat 仓库的 e2e/README.md 为核心,系统讲解其 Playwright 端到端测试体系的三层能力:免真实凭据的 Mock 测试画像(Profile)、内存/Redis 双流存储模式与 CI 分片策略、基于 Bombadil 的属性化浏览器探索测试,以及用 Playwright codegen 录制并落地为可维护规格(spec)的完整工作流。读完本文,你可以直接在本仓库运行完整的 mock e2e 套件、切换 Redis 传输验证流式保真度、复现并归档 Bombadil 发现的缺陷,并掌握从浏览器录制到提交级测试的转化方法。

一、Mock E2E 画像:免真实 LLM 凭据的安全默认

Mock e2e 画像是生成式测试最安全的默认选择:它使用 e2e/config/librechat.e2e.yaml 启动 LibreChat,通过LIBRECHAT_TEST_RUN_HOOK环境变量注入一个进程内假 LLM,自动创建一个已认证的 e2e 用户,全程不触碰任何真实 Provider 凭据。

1.1 从 npm 脚本到测试服务器的启动链

根目录 package.json 中定义的入口脚本为:

npm run e2e:mock

该脚本实际展开为两步:

npm run e2e:prepare # 等价于 npm run frontend,构建>npm run e2e:mock:redis

从 package.json 可见,该命令等价于cross-env E2E_STREAM_STORE=redis playwright test --config=e2e/playwright.config.mock.ts

2.2 环境变量如何决定存储模式

e2e/setup/env.ts 中的getStreamStoreEnv()是模式分发的核心,支持三种取值:

E2E_STREAM_STORE行为
memory(默认)USE_REDIS=falseUSE_REDIS_STREAMS=falseE2E_REQUIRE_REDIS_STREAMS=false,显式禁用 Redis
redisUSE_REDIS=trueUSE_REDIS_STREAMS=trueE2E_REQUIRE_REDIS_STREAMS=trueREDIS_URI默认redis://127.0.0.1:6379/15(数据库 15),REDIS_KEY_PREFIX默认取自E2E_REDIS_KEY_PREFIX,缺省为LibreChatE2E
redis-cluster同上但USE_REDIS_CLUSTER=trueREDIS_URI默认为 7001/7002/7003 三节点

E2E_REQUIRE_REDIS_STREAMS=true就是文档所说的"fail closed"机制:e2e/setup/start-server.js 启动时会 ping Redis(超时 10 秒),并验证生成 job 管理器没有静默回退到内存,否则测试直接失败而不是带病运行。

2.3 CI 分片与 Redis 传输专项套件

Pull Request CI 的策略是:完整 mock 套件跑内存模式、分 3 片,外加一条聚焦的 Redis 传输套件

npx playwright test --config=e2e/playwright.config.mock.ts --shard=1/3 npm run e2e:mock:redis:transport

分片安全性的依据来自 playwright.config.mock.ts:workers: 1保证每个 shard 只有一个 worker,从而不与同一 shard 内的其他测试争抢同一个认证用户和数据库;CI 下retries: 2forbidOnly生效。

e2e:mock:redis:transport使用派生配置 e2e/playwright.config.redis.ts,它展开 mock 配置后只保留 10 个"跨越流存储边界"的场景,与 README 所列覆盖范围一一对应:

testMatch: [ /completion\.spec\.ts/, // 完成 /deferred-tools-hitl\.spec\.ts/, // HITL 审批 /model-spec-icons\.spec\.ts/, // 模型图标 /steering\.spec\.ts/, // steering(运行中转向) /steering-escalation\.spec\.ts/, // steering 升级 /streaming\.spec\.ts/, // 流式保真 /subagent-activity\.spec\.ts/, /thread-fold\.spec\.ts/, // 线程折叠 /tool-approvals\.spec\.ts/, // 工具审批 /usage\.spec\.ts/, // 用量 ]

Redis 泳道还放宽了断言预算:expect.timeout从 10 秒提到 20 秒、CI 重试 3 次——因为每个流事件都要走真实 Redis 往返,暂停/恢复与重新水合(整 job 重放)路径最接近超时预算。夜间调度和手动 workflow 则会在两种流模式下各跑完整套件、每种模式 2 片。

三、Bombadil 属性化浏览器测试:让随机探索替你找 bug

Bombadil 是 e2e/bombadil/ 目录实现的属性化(property-based)浏览器测试框架,它对核心聊天回路、消息分支、并行多会话响应、模型切换、页面重载和侧边栏会话生命周期操作进行随机序列探索,而不是沿着固定脚本点击。

3.1 基础探索命令

npm run e2e:bombadil

底层由 e2e/playwright.config.bombadil.ts(testDir: 'bombadil'testMatch: 'harness.spec.ts')驱动 e2e/bombadil/harness.spec.ts,该 harness 会:

  • 把 e2e/bombadil/specification.ts 复制为运行时副本,并把登录占位符__BOMBADIL_E2E_USER_EMAIL__/__BOMBADIL_E2E_USER_PASSWORD__替换为实际 e2e 用户凭据;
  • spawnnode_modules/.bin/bombadil二进制,执行browser test --headless --output-path e2e/.generated/bombadil-output --instrument-javascript inline --exit-on-violation --time-limit 90s
  • 对新运行前,若e2e/.generated/bombadil-output已存在,先归档到e2e/.generated/bombadil-history/(带时间戳)。

调长探索时间:设置BOMBADIL_TIME_LIMIT(harness 支持90s5m2h这类数字+ s/m/h/d格式),本地或定时任务可放心用更长的值。

3.2 失败复现与归档闭环

失败会留下可复现 trace:

BOMBADIL_REPRODUCE=e2e/.generated/bombadil-output npm run e2e:bombadil:run

复现时 harness 会向 bombadil 传入--reproduce <path>而不是--time-limit,并把 Playwright 超时放宽到 30 分钟。按设计,复现出一个真实违反(invariant violation)时测试应当失败;但如果流式时序变化导致行为发散,复现结果可能偏离,Bombadil 会明确报告这一点。

3.3 CI 集成:非阻塞探索 + 工件

CI 在Bombadil Property Explorationworkflow 中做 5 分钟宽泛探索(非阻塞)。属性失败时:

  1. 下载bombadil-reproduction-*工件到e2e/.generated/bombadil-output/,本地执行上面的复现命令;
  2. 配套的bombadil-diagnostics-*工件包含 CI 日志、Playwright HTML 报告与测试结果;
  3. Bombadil 失败只产生 workflow 警告,不阻塞合并

3.4 JavaScript 插桩范围

默认只对inlineJS 做插桩,因为对 LibreChat 完整 Vite bundle 插桩会在有状态长运行中超过 Bombadil 的 driver 超时(harness.spec.ts 中的注释明确说明了这一点)。需要做更短周期的覆盖率引导实验时,可以设置:

BOMBADIL_INSTRUMENT_JAVASCRIPT=files,inline npm run e2e:bombadil

3.5 五个可独立运行的生命周期属性

分支重载、fork 提交、模型/会话、HITL 暂停/恢复、运行中 steering 的生命周期属性可以单独跑:

npm run e2e:bombadil:branch-reload npm run e2e:bombadil:fork-lifecycle npm run e2e:bombadil:model-lifecycle npm run e2e:bombadil:hitl npm run e2e:bombadil:steering

package.json 中每条命令都通过BOMBADIL_SPECIFICATION指定对应的 specification 文件(如hitl-lifecycle.specification.ts),并内置时间上限(30s/30s/30s/45s/75s 分别对应 branch-reload/fork/model/hitl/steering)。这些聚焦命令是诊断性属性:复现出产品不变量违反时以非零码退出。对应的 trace 输出目录按 specification 区分(如e2e/.generated/bombadil-output-hitl),复现命令也要匹配目录与:run脚本:

BOMBADIL_REPRODUCE=e2e/.generated/bombadil-output-hitl npm run e2e:bombadil:hitl:run

各属性的语义(摘自 e2e/README.md):

  • HITL:驱动一次真实的ask_user_question检查点走 answer/resume 控制器——问题暂停时重载页面、只回答一次、再重载已完成会话;
  • Steering:在一次慢速 MCP 支撑的运行中提交 in-flight steering,断言它恰好从 composer 锚点移动到响应中的工具边界一次,并重载已应用状态;
  • Model lifecycle:作为"应通过的对照(passing control)";
  • Branch reload 与 fork:保留其最小失败 trace 作为回归锚点。

由于 harness 使用的是免凭据 mock-LLM 画像,探索过程永远不会发出计费的 Provider 请求。

四、录制测试:把探索性浏览器会话变成草稿 spec

4.1 一键录制(Mock 画像)

npm run e2e:record

对照 e2e/setup/record.js 的源码,这条命令的实际行为是:

  1. npm run e2e:prepare构建应用;
  2. E2E_BASE_URL(npm 脚本固定为http://localhost:3333,避免与 3080 上的常规开发服务器冲突)未就绪,spawn e2e/setup/start-server.js 启动带进程内假 LLM 的测试服务器;
  3. writeStorageState()驱动 headless Chromium 完成注册(失败则回退登录),把认证态写入e2e/storageState.json
  4. --target=playwright-test --test-id-attribute=data-testid --load-storage e2e/storageState.json打开 Playwright codegen,起始页/c/new

原始录制写入e2e/recordings/,该目录被 git 忽略。

4.2 本地真实配置画像

要对真实的本地 LibreChat 配置(而非 mock 画像)录制:

npm run e2e:record:local

4.3 record.js 的完整参数

node e2e/setup/record.js --url=http://localhost:3080/c/new node e2e/setup/record.js --profile=local --no-output node e2e/setup/record.js --auth-only node e2e/setup/record.js --output=e2e/recordings/settings-draft.spec.ts

结合源码中的parseArgs()printHelp(),完整参数语义为:

参数默认值说明
--profile mock\|localmockmock 画像会生成运行时配置、清洗凭据并注入假模型钩子;local 直接使用本地环境
--url <url><baseURL>/c/newcodegen 打开的起始 URL
--output <path>e2e/recordings/recording-<时间戳>.spec.ts原始录制输出路径
--storage <path>e2e/storageState.json认证存储态路径
--no-output只在 codegen 面板展示生成代码,不落盘
--auth-only启动服务器、写入存储态后直接退出(不打开 codegen)

五、LLM 辅助循环:从录制草稿到可提交的测试

仓库给"让 LLM 用 Computer Use 操作 headed Playwright 浏览器来录制"的完整工作流定了 7 步标准:

  1. 启动npm run e2e:record
  2. 让 LLM 用 Computer Use 操作该 headed 浏览器;
  3. 捕获完工作流后停止 codegen;
  4. e2e/recordings/中有价值的部分搬进e2e/specs/mock/下的已提交 spec;
  5. 用 role、label、文本或data-testid定位器替换脆弱的生成选择器(codegen 本身就以--test-id-attribute=data-testid启动,优先产出 testid 定位器);
  6. 添加证明行为成立的断言,而不仅是断言被点击的路径;
  7. npm run e2e:mock -- <spec name>运行完成的 spec 验证。

关键原则:生成的录制是草稿,不是最终测试。提交版本应尽可能复用 e2e/specs/mock/helpers.ts 中的共享辅助函数,等待网络或可见 UI 状态而不是固定 sleep,并保持测试数据确定性——这与 mock 画像"每个 spec 使用全新注册用户 + 单 worker"的隔离设计是一致的:确定性数据配合e2e/recordings/之外的受控输入(fake-model 的标记协议),才能被 CI 稳定复现。

六、关键文件地图与延伸阅读

关注点文件
本文主体文档e2e/README.md
Mock 画像主配置e2e/playwright.config.mock.ts
Redis 传输专项配置e2e/playwright.config.redis.ts
零凭据配置模板e2e/config/librechat.e2e.yaml
流存储环境变量分发e2e/setup/env.ts
进程内假 LLM(标记协议)e2e/setup/fake-model.js
测试服务器启动(fail-closed Redis 检查)e2e/setup/start-server.js
录制脚本e2e/setup/record.js
Bombadil harnesse2e/bombadil/harness.spec.ts
Mock spec 目录(约 60 个场景)e2e/specs/mock/
npm 脚本入口package.json

适用前提与限制小结:本地运行需先构建前端(e2e:prepare),MongoDB 默认连mongodb://127.0.0.1:27017/LibreChat-e2e(可用MONGO_URI覆盖,或依赖E2E_USE_MEMORY_MONGO自动内存模式);Redis 泳道要求 6379 端口有可用 Redis;模型 fixture 录制模式(E2E_MODEL_FIXTURES=record)是唯一会接触真实 Provider 的路径,且被 playwright.config.mock.ts 中的多重防护严格限制在指定 spec 与命名白名单内,普通开发者日常只需面对零凭据的 mock 泳道即可。

【免费下载链接】LibreChatEnhanced ChatGPT Clone: Features Agents, MCP, Skills, DeepSeek, Anthropic, AWS, OpenAI, Responses API, Azure, Groq, o1, GPT-5, Mistral, OpenRouter, Vertex AI, Gemini, Artifacts, AI model switching, message search, Code Interpreter, langchain, DALL-E-3, OpenAPI Actions, Functions, Secure Multi-User Auth, Presets, open-source for self-hosting. Active项目地址: https://gitcode.com/GitHub_Trending/li/LibreChat

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询