AionUi aionrs(Aion CLI)E2E 测试用例全解:从 P0 基线路径到 P2 边界验证的设计与实践
2026/9/19 18:14:02 网站建设 项目流程

AionUi aionrs(Aion CLI)E2E 测试用例全解:从 P0 基线路径到 P2 边界验证的设计与实践

【免费下载链接】AionUi免费、本地、开源的 24/7 全天候 Cowork 应用,以及适用于 Gemini CLI、Claude Code、Codex、OpenCode、Qwen Code、Goose CLI、Auggie 等的 OpenClaw | 🌟 喜欢就点star吧项目地址: https://gitcode.com/iOfficeAI/AionUi

导读:本文基于 AionUi 开源仓库中的 aionrs E2E 测试用例设计文档(tests/e2e/docs/chat-aionrs/test-cases.zh.md),系统讲解针对 aionrs(Aion CLI)对话功能设计的 15 个端到端测试用例,涵盖用例编号规则、全局前置条件、五维测试矩阵(关联文件夹 / 上传文件 / 模型 / 权限 / 对话中操作)、SQL 级 DB 断言模板与清理约定。读完本文,你将掌握如何为基于本地 CLI binary 的 AI Agent 对话功能编写可跳过、可断言、可清理的高质量 E2E 用例,并理解 AionUi 中 guid 页 → 对话页的完整链路实现。


1. 背景:为什么需要一套独立的 aionrs E2E 用例

AionUi 是一个本地优先的开源 AI 应用,支持接入 Gemini CLI、Claude Code、Codex、Qwen Code、Goose CLI 等本地 CLI binary。其中aionrs(Aion CLI)是一种以binary + IPC方式驱动的 agent 后端:用户在前端(guid 页)选择 agent、配置模型与权限,随后在对话页与运行在本地进程中的 binary 交互。

这类后端的 E2E 测试与普通 API 对话测试有本质差异:

  • 依赖本地 binary 可用性:binary 不存在时整套测试必须优雅跳过,而不是失败;
  • 依赖用户真实配置的 provider:模型列表来自用户配置文件,测试不能 hardcode 模型 ID;
  • 涉及真实文件系统与进程生命周期:关联文件夹、上传文件、停止进程、清理 DB 与临时目录都是用例的一部分;
  • 权限模式影响交互行为default/auto_edit/yolo三档权限直接决定是否出现工具确认弹窗。

为此,设计文档以Gate 2 初稿的形式产出了一套编号为 TC-A-01 ~ TC-A-15 的完整用例矩阵,并在仓库 tests/e2e/features/conversations/aionrs/ 目录下落地为 6 个 spec 文件。

2. 用例结构:编号规则、前置条件与五维矩阵

2.1 用例编号规则(P0 / P1 / P2)

优先级用例范围定位
P0(必测)TC-A-01 ~ TC-A-05基线路径,最小可用功能
P1(常规)TC-A-06 ~ TC-A-12维度组合,常用场景
P2(边界)TC-A-13 ~ TC-A-15异常处理,边界验证

P0 保证"能跑通",P1 覆盖"常用变体",P2 守护"异常不崩"。从源码结构看,这一分层与 spec 文件的划分一一对应:basic-flow.e2e.ts承载 TC-A-01~03,model-selection.e2e.ts承载 TC-A-04,permission-modes.e2e.ts承载 TC-A-05/06,mid-conversation-switch.e2e.ts承载 TC-A-07~09,combo-scenarios.e2e.ts承载 TC-A-10~12,edge-cases.e2e.ts承载 TC-A-13~15。

2.2 全局前置条件

所有 aionrs 测试用例共享三项前置条件,缺一不可:

  1. aionrs binary 可用:通过ipcBridge.fs.findAionrsBinary.invoke()验证,否则 skip 全部测试;
  2. 至少 1 个可用的非 Google Auth provider
    • 调用ipcBridge.mode.getModelConfig.invoke()获取用户配置的 provider 列表;
    • 过滤掉platform包含gemini-with-google-auth的 provider(AionCore 不支持 Google Auth);
    • 验证至少 1 个 provider 包含apiKey且有可用model
    • 若无可用 provider:skip 全部测试,原因标记为"No non-Google-Auth provider with apiKey configured"
  3. 测试数据准备:临时工作目录/tmp/e2e-aionrs-<timestamp>/

第二点在源码中有明确印证:useAionrsModelSelection.ts 第 36-40 行对 provider 列表执行同样的过滤逻辑:allProviders.filter((p) => !p.platform?.toLowerCase().includes('gemini-with-google-auth'))。测试前置条件与产品代码保持同一套过滤规则,保证"测试看到的模型列表"与"产品实际可选的模型列表"一致。

模型获取 helper(由 engineer 实现,位于 tests/e2e/helpers/chatAionrs.ts):

export async function getAionrsTestModels(page: Page): Promise<{ modelA: TProviderWithModel; // 第一个可用模型(默认模型) modelB: TProviderWithModel | null; // 第二个可用模型(若存在) }>;

该 helper 还负责把原始 provider 数据规范化为测试友好的结构(如apiKey/api_key双字段归一、model/models数组归一、useModel默认取第一个模型),确保测试代码不依赖具体配置格式。

2.3 五维测试维度

维度可选值说明
关联文件夹无 / 单 / 多atPath数组(源码:AionrsSendBox.tsx)
上传文件无 / 单 / 多uploadFile数组(源码:useSendBoxFiles.ts
模型默认 / 自选从用户配置的 provider 列表选择(ipcBridge.mode.getModelConfig.invoke(),过滤 Google Auth)
权限default / auto_edit / yolo来源:aionrs runtime capabilities
对话中操作切换模型 / 切换权限 / 无对话页AionrsModelSelector/AgentModeSelector

从实现看,权限选项并非硬编码:AionrsSendBox 通过useAionrsMessageonConfigChanged回调接收 runtime capabilities 中的modes数组,动态生成选项(modeOptionsFromCapabilities),同时保留default/auto_edit/yolo兜底列表。这意味着测试文档中"权限来源:aionrs runtime capabilities"的描述与运行时行为一致。

2.4 清理约定与截图要求

命名模式:所有测试对话命名为E2E-aionrs-<timestamp>-<scenario>,便于统一清理与检索。

清理顺序(每个用例afterEach执行,防止用例间数据污染):

  1. 停止 binary 进程:ipcBridge.conversation.stopAgent.invoke(conversationId)
  2. 删除 DB 记录:DELETE FROM conversations WHERE name LIKE 'E2E-aionrs-%'(级联删除 messages);
  3. 删除临时目录:fs.rm('/tmp/e2e-aionrs-*', { recursive: true })
  4. 清理 sessionStorage:sessionStorage.removeItem('aionrs_initial_message_*')+sessionStorage.removeItem('aionrs_initial_processed_*')

其中 sessionStorage 清理对应 guid 页 → 对话页的"初始消息接力"机制:AionrsSendBox 在 AionrsSendBox.tsx 中读取aionrs_initial_message_${conversation_id},发送成功后写入aionrs_initial_processed_${conversation_id}标记,避免重复发送。测试清理这两项是保证"下一条用例能重新从 guid 页带消息跳转"的前提。

截图要求:每个用例最少 3 张——

  1. guid 页选择 agent 后(显示输入框 + 配置项);
  2. 对话页首条消息发送后(显示用户消息 + AI 回复流式中);
  3. 对话完成后(显示最终消息列表 + DB 断言通过)。

3. P0 基线用例(TC-A-01 ~ TC-A-05)

3.1 TC-A-01:最小可用路径

验证无附件 + 默认模型 + default 权限的最小对话流程,是整个套件的"试金石"。

维度组合:关联文件夹=无,上传文件=无,模型=默认(modelA),权限=default,对话中操作=无。

操作步骤

  1. 打开应用,导航至 guid 页(/#/guid);
  2. 选择 aionrs agent(点击[data-agent-backend="aionrs"]);
  3. 确认权限选择器默认值为defaultAgentModeSelector默认值);
  4. 输入测试消息:"Hello, aionrs! Please list files in current directory."
  5. 点击发送按钮;
  6. 等待跳转至对话页(URL 匹配/conversation/aionrs/*);
  7. 等待 AI 回复流式完成(轮询 DBmessages.status='finish',超时 60s)。

DB 断言点(对应文档附录 B 的查询模板):

-- 1. 验证 conversation 创建 SELECT id, name, type, model, status, json_extract(extra, '$.sessionMode') as mode FROM conversations WHERE name LIKE 'E2E-aionrs-%' AND id = ?; -- 期望: type='aionrs', mode='default', status='finished' -- 2. 验证用户消息 SELECT id, type, position, content, status FROM messages WHERE conversation_id = ? AND position = 'right'; -- 期望: type='text', position='right', json_extract(content, '$.content') 包含 "Hello, aionrs!" -- 3. 验证 AI 回复 SELECT id, type, position, status, created_at FROM messages WHERE conversation_id = ? AND position = 'left' AND type = 'text'; -- 期望: 至少 1 条, status='finish', created_at > 用户消息 created_at -- 4. 验证消息顺序 SELECT COUNT(*) FROM messages WHERE conversation_id = ?; -- 期望: ≥ 2(用户 + AI)

清理义务:conversation 名E2E-aionrs-<timestamp>-minimal-path;temp dir/tmp/e2e-aionrs-<timestamp>-tc-a-01/(workspace);sessionStorage 键aionrs_initial_message_${conversationId}aionrs_initial_processed_${conversationId}。截图数 3。

对应实现见 basic-flow.e2e.ts 中的TC-A-01: should complete minimal conversation with no attachments

3.2 TC-A-02:关联单个文件夹

验证关联文件夹后,消息内容包含文件夹引用,即attachedDirs正确写入用户消息。

前置准备

mkdir -p /tmp/e2e-aionrs-<timestamp>/test-folder/ echo "sample content" > /tmp/e2e-aionrs-<timestamp>/test-folder/sample.txt

关键步骤:从文件树选择test-folder/(触发emitter.emit('aionrs.selected.file', [{ path, name, isFile: false }])),确认 guid 页显示文件夹 Tag(data-testid="folder-tag-0"),发送消息"What files are in the attached folder?"

DB 断言点

-- 1. 验证用户消息包含文件夹引用 SELECT json_extract(content, '$.attachedDirs') as dirs FROM messages WHERE conversation_id = ? AND position = 'right'; -- 期望: dirs 是 JSON 数组, 包含 '{"path": ".../test-folder", "name": "test-folder", "isFile": false}' -- 2. 验证消息内容 SELECT json_extract(content, '$.content') as text FROM messages WHERE conversation_id = ? AND position = 'right'; -- 期望: text 包含 "What files are in the attached folder?"

实现佐证:文件夹 Tag 的渲染与 testid 生成位于 AionrsSendBox.tsx,其中folderIndex = atPath.filter((v) => typeof v !== 'string' && !v.isFile).indexOf(item)计算文件夹序号,data-testid={\aionrs-folder-tag-${folderIndex}`};文件预览卡片同理使用aionrs-file-tag-${index}。文档中提到的data-testid="folder-tag-0"` 是测试对实现 testid 的引用,实际以源码为准。

3.3 TC-A-03:上传单个文件

验证上传文件后,binary 接收files参数

前置准备

echo "Test file content for aionrs E2E" > /tmp/e2e-test-file.txt

关键步骤:WebUI 端使用<input type="file">选择文件;Desktop 端调用ipcBridge.dialog.showOpen()选择文件。确认文件预览卡片显示(data-testid="file-card-0")后发送"What is the content of the attached file?"

DB 断言点

-- 1. 验证用户消息包含文件引用 SELECT json_extract(content, '$.attachedFiles') as files FROM messages WHERE conversation_id = ? AND position = 'right'; -- 期望: files 是 JSON 数组, 包含 '/tmp/e2e-test-file.txt' -- 2. 验证 AI 回复提到文件内容 SELECT json_extract(content, '$.content') as text FROM messages WHERE conversation_id = ? AND position = 'left' AND type = 'text'; -- 期望: text 包含 "Test file content" 或文件名 "e2e-test-file.txt"

实现佐证:发送消息时文件通过collectChatFileRefs(uploadFile, atPath)收集为ChatFileRef[]并随ipcBridge.conversation.sendMessage.invoke({ input, conversation_id, files, sessions })传递(AionrsSendBox.tsx),由后端在发送边缘将每个 ChatFileRef 解析为绝对路径并注入[[AION_FILES]]标记。因此测试断言attachedFiles包含绝对路径/tmp/e2e-test-file.txt是符合设计意图的。

3.4 TC-A-04:使用第二个模型

验证在 guid 页选择非默认模型后,DB 正确记录模型 ID

前置条件getAionrsTestModels(page)返回{ modelA, modelB };若modelB === null,skip 此用例(原因:"Only 1 model available, skipping guid page model selection test")。

关键步骤:在 guid 页打开模型选择器(GuidModelSelector,仅当isGeminiMode=true可见),选择modelB不 hardcode 具体模型 ID),发送"What model are you using?"

DB 断言点

SELECT model, json_extract(extra, '$.model.useModel') as extra_model FROM conversations WHERE id = ?; -- 期望: extra_model = modelB.useModel SELECT status FROM conversations WHERE id = ?; -- 期望: status='finished' SELECT COUNT(*) FROM messages WHERE conversation_id = ? AND position = 'left'; -- 期望: ≥ 1

实现佐证:guid 页模型选择器的可见性由isGeminiMode控制,即PROVIDER_BASED_AGENTS.has(agentSelection.selectedAssistantBackend)(GuidPage.tsx)。备注:若 guid 页模型选择器未启用(isGeminiMode为 false),此用例改为在对话页切换模型(见 TC-A-07)。

3.5 TC-A-05:使用 yolo 权限

验证yolo 模式下工具调用自动批准(无确认弹窗)

关键步骤:打开权限选择器(AgentModeSelectordata-testid="agent-mode-selector-aionrs"),选择yolo(label: "YOLO"),发送"Please create a file named test.txt with content 'E2E test'."验证无确认弹窗出现,等待工具执行完成(轮询 DBmessages.type='tool_group'status='Success')。

DB 断言点

-- 1. 验证权限模式持久化 SELECT json_extract(extra, '$.sessionMode') as mode FROM conversations WHERE id = ?; -- 期望: mode='yolo' -- 2. 验证工具调用记录 SELECT type, json_extract(content, '$[0].status') as tool_status FROM messages WHERE conversation_id = ? AND type = 'tool_group'; -- 期望: 至少 1 条, tool_status IN ('Success', 'Executing', 'Error') -- 注意: yolo 模式不应出现 'Confirming' 状态 -- 3. 验证无确认弹窗(前端逻辑验证) -- E2E 层:page.waitForSelector('.confirmation-dialog', { timeout: 2000 }) 应超时(证明无弹窗)

4. P1 常规组合用例(TC-A-06 ~ TC-A-12)

4.1 TC-A-06:使用 auto_edit 权限

验证auto_edit 模式下 edit/info 工具自动批准,exec 工具仍需确认——这是对权限语义最精细的验证。

操作步骤

  1. 选择auto_edit(label: "Auto-Accept Edits");
  2. 发送"Please read the file ./README.md and summarize it."(触发 info 工具),等待执行完成,无确认弹窗
  3. 发送第二条消息"Now run command 'ls -la'."(触发 exec 工具),验证出现确认弹窗ConversationChatConfirm显示);
  4. 点击 "Yes, Allow Once" 批准,等待命令执行完成。

DB 断言点

SELECT json_extract(content, '$[0].name') as tool_name, json_extract(content, '$[0].status') as tool_status FROM messages WHERE conversation_id = ? AND type = 'tool_group'; -- 期望: -- - info 类工具: status 直接从 Executing → Success(跳过 Confirming) -- - exec 类工具: status 经历 Confirming → Executing → Success(需用户确认)

截图数:4(比基线多 1 张确认弹窗截图)。

4.2 TC-A-07:对话中切换模型

验证对话中切换模型后,DBconversations.extra.model更新为新模型 ID

操作步骤:按 TC-A-01 创建对话(modelA)→ 等待首条回复完成 → 点击对话页模型选择器(AionrsModelSelectordata-testid="aionrs-model-selector")→ 选择modelB→ 轮询 DBconversations.extra.model更新 → 发送第二条消息"What model are you using now?"

DB 断言点

SELECT json_extract(extra, '$.model.useModel') as current_model FROM conversations WHERE id = ?; -- 期望: current_model = modelB.useModel SELECT COUNT(*) FROM messages WHERE conversation_id = ?; -- 期望: ≥ 4(用户消息1 + AI回复1 + 用户消息2 + AI回复2)

实现佐证:AionrsModelSelector.tsx 使用${providerId}::${modelName}复合 ID 将扁平模型列表映射回 provider+model,选择后调用handleSelectModel(provider, modelName);模型切换状态经useAionrsModelSelectionhandleSelectModel回调(onSelectModel返回 true 才更新current_model)持久化。备注:根据设计文档中"议题 1"的决策,此用例只验证 DB 字段更新,不验证 binary 内部 sessionId 变化。

4.3 TC-A-08 / TC-A-09:对话中切换权限

这两个用例验证权限切换后工具确认行为立即变化,是"权限档位动态生效"的证明。

TC-A-08(default → auto_edit):先以 default 权限发送 edit 类消息 →验证出现确认弹窗→ 取消("No")→ 切换为auto_edit→ 重新发送相同消息 →验证无确认弹窗

TC-A-09(auto_edit → yolo):先以 auto_edit 发送"Please run command 'pwd'."(exec 工具)→验证出现确认弹窗→ 取消 → 切换yolo→ 重新发送 →验证无确认弹窗(yolo 自动批准所有工具)。

DB 断言点(以 TC-A-08 为例)

-- 1. 验证权限切换后 DB 更新 SELECT json_extract(extra, '$.sessionMode') as mode FROM conversations WHERE id = ?; -- 期望: mode='auto_edit' -- 2. 验证第二次工具调用无 Confirming 状态(取最新一条) SELECT json_extract(content, '$[0].status') as tool_status, created_at FROM messages WHERE conversation_id = ? AND type = 'tool_group' ORDER BY created_at DESC LIMIT 1; -- 期望: tool_status = 'Executing' 或 'Success'(跳过 Confirming) -- 3. 验证第一次工具调用被取消(取最早一条) SELECT json_extract(content, '$[0].status') as tool_status, created_at FROM messages WHERE conversation_id = ? AND type = 'tool_group' ORDER BY created_at ASC LIMIT 1; -- 期望: tool_status = 'Canceled'

截图数:TC-A-08 为 5 张(2 张确认弹窗:第一次出现 + 第二次未出现),TC-A-09 为 4 张。

4.4 TC-A-10 / TC-A-11 / TC-A-12:多维度组合场景

这三个用例验证维度交叉时的附件完整传递

TC-A-10(关联文件夹 + 上传文件 + 非默认模型 + auto_edit)

mkdir -p /tmp/e2e-aionrs-<timestamp>/folder-a/ echo "content A" > /tmp/e2e-aionrs-<timestamp>/folder-a/file-a.txt echo "content B" > /tmp/e2e-test-file-b.txt

发送"Compare the content of the attached folder and file.",断言dirs包含folder-afiles包含e2e-test-file-b.txtextra.model.useModel为第二个模型 ID、sessionMode='auto_edit'

TC-A-11(上传多个文件):创建/tmp/e2e-file-1.txt/tmp/e2e-file-2.txt/tmp/e2e-file-3.txt三个文件批量上传,断言attachedFiles数组长度 = 3,AI 回复提及 "3" 或 "three"。

TC-A-12(关联多个文件夹):创建folder-x/folder-y/并各含一个文件,依次从文件树选择,断言dirs数组长度 = 2、包含folder-xfolder-y,AI 回复提及x.txty.txt

对应实现见 combo-scenarios.e2e.ts,其中 TC-A-10/12 在只有 1 个模型时同样以test.skip优雅降级('Need at least 2 models for this test')。

5. P2 边界用例(TC-A-13 ~ TC-A-15)

5.1 TC-A-13:Binary 不可达时跳过测试

验证E2E 测试前的 binary 检查机制生效。通过设置process.env.AION_CLI_PATH = '/dev/null'模拟 binary 不可用,运行测试后断言:测试框架输出test.skip()标记;控制台输出 skip 原因"aionrs binary not found, skipping E2E tests";CI 报告显示 skipped(非 failed)。

实现参考(对应 spec 中的beforeAll钩子):

// tests/e2e/setup/aionrs.setup.ts export async function checkAionrsBinary(): Promise<boolean> { try { const binary = await ipcBridge.fs.findAionrsBinary.invoke(); return binary !== null; } catch { return false; } } // tests/e2e/specs/chat-aionrs/*.spec.ts test.beforeAll(async () => { const hasBinary = await checkAionrsBinary(); if (!hasBinary) { test.skip('aionrs binary not found, skipping E2E tests'); } });

实际实现中,edge-cases.e2e.ts 与各 spec 文件在beforeAll中除 binary 检查外,还会校验是否存在 aionrs 兼容的 provider,否则test.skip(true, 'No aionrs-compatible provider found, skipping E2E tests')——把"依赖外部环境"的用例从"失败"降级为"跳过",是本地 binary 型 E2E 的通用最佳实践。

5.2 TC-A-14:超大文件上传限制

验证前端文件大小限制机制。创建 100MB 文件:

dd if=/dev/zero of=/tmp/e2e-large-file.bin bs=1M count=100

尝试上传后断言:前端显示错误提示(Toast / Message 组件);文件预览卡片不显示;发送按钮可用(但消息体不包含该文件);DB 无记录(消息未发送)。

备注:若前端未实现大小限制(需确认FileService.processDroppedFiles()逻辑),此用例改为验证 binary 层错误处理——这种"实现优先、备选方案兜底"的写法避免了用例因实现偏差而僵死。

5.3 TC-A-15:关联不存在的文件夹

验证文件系统异常处理。通过手动触发选择事件模拟不存在的路径:

emitter.emit('aionrs.selected.file', [ { path: '/tmp/e2e-nonexistent-folder/', name: 'e2e-nonexistent-folder', isFile: false }, ]);

DB 断言点

-- 1. 验证用户消息记录文件夹引用(即使路径不存在) SELECT json_extract(content, '$.attachedDirs') as dirs FROM messages WHERE conversation_id = ? AND position = 'right'; -- 期望: dirs 包含 '/tmp/e2e-nonexistent-folder/' -- 2. 验证 AI 回复提示错误 SELECT json_extract(content, '$.content') as text FROM messages WHERE conversation_id = ? AND position = 'left' AND type = 'text'; -- 期望: text 包含 "not found" 或 "does not exist" 或类似错误提示 -- 3. 验证对话状态 SELECT status FROM conversations WHERE id = ?; -- 期望: status='finished'(非 'error',因为是用户输入错误而非系统错误)

第三点是整份文档中最值得注意的断言设计:用户输入错误不应把对话标记为 error,而应正常结束(finished)——这区分了"用户输入导致的业务异常"与"系统故障",是语义化断言的高阶用法。

6. 未覆盖场景:明确"不测什么"同样是设计

根据设计文档中"议题 3"的决策,以下场景本轮 E2E明确不覆盖,并记录理由:

  1. 工具确认中途切换权限(弹窗确认中切换 yolo 的行为未定义,E2E 不应固化不确定行为);
  2. 流式输出中途切换模型(当前 turn 是否中断/继续/使用新模型未定义);
  3. 跨对话/跨进程权限持久化("always allow" 重启后是否记住,本轮只测同一对话内切换生效);
  4. 并发对话场景(暂缓至后续 Gate,需 Playwright 多标签页 + 进程监控的复杂编排)。

这条"负面清单"的价值在于:它划定了当前测试的信任边界,避免测试断言了未定义的行为而变成"测试驱动实现"的隐性约束。

7. 测试数据矩阵与实现优先级

7.1 用例汇总矩阵

用例 ID关联文件夹上传文件模型权限对话中操作优先级截图数
TC-A-01默认defaultP03
TC-A-02默认defaultP03
TC-A-03默认defaultP03
TC-A-04第二个defaultP03
TC-A-05默认yoloP03
TC-A-06默认auto_editP14
TC-A-07默认→第二个default切换模型P14
TC-A-08默认default→auto_edit切换权限P15
TC-A-09默认auto_edit→yolo切换权限P14
TC-A-10第二个auto_editP14
TC-A-11多(3个)默认defaultP13
TC-A-12多(2个)默认defaultP13
TC-A-13N/AN/AN/AN/AN/AP21
TC-A-14超大默认defaultP22
TC-A-15不存在默认defaultP23

统计:P0 5 个(基线路径)、P1 7 个(常规组合 + 对话中操作)、P2 3 个(边界验证),总计 15 个用例,总截图数 50 张。

7.2 分阶段落地建议

  • Phase 1(P0 必测):TC-A-01(最小路径,优先实现验证端到端基础流程)→ TC-A-02/03(附件传递)→ TC-A-04(模型选择)→ TC-A-05(权限档位);
  • Phase 2(P1 常规覆盖):TC-A-06(完整权限档位覆盖)→ TC-A-07/08/09(对话中动态切换)→ TC-A-10/11/12(维度交叉);
  • Phase 3(P2 边界收尾):TC-A-13(CI 跳过机制)→ TC-A-14/15(健壮性验证)。

8. 下一步流程(Gate 2 → Gate 3)

设计文档明确了后续交付路径:chat-aionrs-engineerreview 用例设计并评估工作量 →team-lead批准后进入 Gate 3(实现)→ engineer 实现完成后,designer 产出implementation-mapping.zh.md(TC ID → 文件:行号:函数名 映射)。这一"设计-评审-实现-映射"的闭环保证了测试用例与源码实现可双向追溯。

附录 A:关键源码参考

文件关键位置说明
GuidPage.tsxisGeminiModeguid 页模型选择器可见性
AionrsSendBox.tsxatPath状态关联文件夹数组
AionrsSendBox.tsxsendMessage.invoke发送消息(传递files参数)
AionrsSendBox.tsx初始消息接力guid 页消息经 sessionStorage 注入对话页
useAionrsModelSelection.ts过滤 Google Auth测试与产品共用同一过滤规则
AionrsModelSelector.tsx复合 ID 映射对话页模型切换
chatAionrs.tsprovider 归一化E2E 测试模型获取 helper
basic-flow.e2e.tsTC-A-01~03P0 基线实现
combo-scenarios.e2e.tsTC-A-10~12组合场景实现
edge-cases.e2e.tsTC-A-13~15边界场景实现

附录 B:DB 断言查询模板

以下为整套用例共用的 SQL 模板,覆盖对话、消息、工具调用、思考四类断言,以及统一的 E2E 数据清理:

-- 查询对话基本信息 SELECT id, name, type, model, status, json_extract(extra, '$.sessionMode') as mode, json_extract(extra, '$.model.useModel') as extra_model, json_extract(extra, '$.lastTokenUsage.totalTokens') as tokens FROM conversations WHERE name LIKE 'E2E-aionrs-%'; -- 查询消息列表 SELECT id, msg_id, type, position, status, json_extract(content, '$.content') as text, json_extract(content, '$.attachedFiles') as files, json_extract(content, '$.attachedDirs') as dirs, created_at FROM messages WHERE conversation_id = ? ORDER BY created_at ASC; -- 查询工具调用 SELECT json_extract(content, '$[0].name') as tool_name, json_extract(content, '$[0].status') as tool_status, json_extract(content, '$[0].callId') as call_id, created_at FROM messages WHERE conversation_id = ? AND type = 'tool_group' ORDER BY created_at ASC; -- 查询思考消息 SELECT json_extract(content, '$.content') as thinking_text, json_extract(content, '$.duration') as duration_ms, json_extract(content, '$.status') as thinking_status FROM messages WHERE conversation_id = ? AND type = 'thinking'; -- 清理所有 E2E 数据 DELETE FROM conversations WHERE name LIKE 'E2E-aionrs-%';

结语

这套 15 用例的 aionrs E2E 设计给出了一条可复用的范式:用维度矩阵穷举输入组合,用 SQL 断言锁定持久化语义,用 skip 机制容忍环境依赖,用清理约定保证可重复运行,用负面清单划定信任边界。对于任何"本地 binary + 用户配置 + 文件系统交互"型 AI 应用的测试设计,它都是一份值得对照的模板;而其设计文档(test-cases.zh.md)与 tests/e2e/features/conversations/aionrs/ 下的落地实现,则展示了"设计先行、实现映射"的完整工程闭环。

【免费下载链接】AionUi免费、本地、开源的 24/7 全天候 Cowork 应用,以及适用于 Gemini CLI、Claude Code、Codex、OpenCode、Qwen Code、Goose CLI、Auggie 等的 OpenClaw | 🌟 喜欢就点star吧项目地址: https://gitcode.com/iOfficeAI/AionUi

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

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

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

立即咨询