Files
PlantAI-rag-new/docs/TEST_CASES.md
T

1569 lines
196 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TEST_CASES.md —— 需求测试用例与追溯矩阵
> 版本 1.0 | 作者 T(测试 agent)| 用例唯一来源:`PRD.md`(81 FR);请求/响应依据:`API.md`;分层与轮次纪律:`TEST_PLAN.md`;上游事实:`DISCOVERY.md`
> 本波(M0)交付:用例清单 + 双向追溯矩阵 + 执行说明 + E2E 骨架(2 条冒烟)。**全量执行从 M2 集成后开始,按 TEST_PLAN §5 轮次纪律。**
> 覆盖判据:每个 FR 至少 1 条 TC,且每条 TC 至少映射 1 个 FR(双向完整 = 主门禁 100%)。
---
## 1. 用例清单
### 1.1 编号与通用约定
- 编号:`TC-<模块>-<序号>`;E2E 主线场景:`TC-E2E-<主线号>-<视口>`(视口 M=Mobile 390×844 / T=Tablet 768×1024 / D=Desktop 1440×900)。
- 测试层:L1 后端单元(pytest -m unit,A 组自测)|L2 后端接口(pytest -m api,respx mock 上游,T 主写)|L2s 上游 smoke(`bash tests/smoke_upstreams.sh`)|L3 前端单元(vitest)|L4 前端组件(vitest + @vue/test-utils)|L5 端到端(Playwright,三档视口)|L6 验收(PM 人工)。
- 优先级:P0 = 主流程/数据正确性/安全;P1 = 重要功能与降级;P2 = 视觉细节/辅助路径。
- 可断言性要求:预期列均为可观察结果(元素存在/计数/请求体字段/HTTP 状态/存储值),无「检查是否正确」类断言。
- 「依赖充值」标注:上游 QA 当前 LLM 402 降级(DISCOVERY.md §6.1),凡断言涉及**自然语言答案内容**的用例均标注「依赖充值」——充值前只能验证结构(answer 字段存在、非空或为 fallback 证据列表、text 块已渲染),充值后验证完整断言。**检索/证据/图谱/来源类断言不受 402 影响。**
- 时序说明:流水线用例中的「pipeline 块状态依次 running→done」属 UI 状态推断,若无专门组件埋点,用例从渲染的相位卡/pipeline 卡状态文本断言;帧时序由 mock `sse_frames.json` 保证(与 TEST_CASES 无关的 fixture 细节以 PM 的 mock 为准)。
### 1.2 SHELL 应用外壳(FR-SHELL-001~007)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-SHELL-001 | FR-SHELL-001 | 桌面三栏网格精确尺寸 | Desktop 1440×900;AppShell 已挂载 | 1. 打开应用;2. 计算 `.app-shell` 的 grid-template-columns 与 rows 实际值(getComputedStyle);3. 计算 `.session-panel`/`.chat-panel`/`.bench-panel` 宽度 | columns = `260px minmax(0,1fr) 380px`;rows = `48px minmax(0,1fr) 28px`;三栏实际宽度 260/800/380(1440 下);`body` computed `overflow:hidden` | L5-D | P0 |
| TC-SHELL-002 | FR-SHELL-001 | 缩放下无横向滚动条 | Desktop 初始 1440×900 | 1. 将视口改为 1280×900、再 1440×900;2. 检查 `document.documentElement.scrollWidth` 与 `clientWidth` | 两档下 scrollWidth ≤ clientWidth;`body` 不出现横向滚动条 | L5-D | P1 |
| TC-SHELL-003 | FR-SHELL-002 | 顶栏结构:Logo/标题/徽章/主题按钮 | 已有一个活动会话;浅色主题 | 1. 打开应用;2. 断言 `.top-bar` 高 48px;3. 检查左 Logo 圆点与「海古纪 PlantAI」文字(gradient text);4. 检查中部会话标题与状态徽章;5. 检查右侧主题切换按钮 | `.top-bar` offsetHeight=48;logo 文字存在且带 `background-clip:text` 渐变;中部标题=当前会话 title;主题按钮可点 | L5-D | P1 |
| TC-SHELL-004 | FR-SHELL-002 | 顶栏无会话时显示「就绪」 | 数据库无任何会话 | 打开应用 | 顶栏中部徽章文本=「就绪」(labels.js 对应键) | L4 | P2 |
| TC-SHELL-005 | FR-SHELL-002 | 顶栏长标题省略 | 存在 title 为 60+ 字符的会话 | 1. 打开该会话;2. 检查顶栏标题元素 computed style | 标题 text-overflow=ellipsis;不换行(white-space:nowrap);单行渲染 | L5-D | P2 |
| TC-SHELL-006 | FR-SHELL-003 | 状态栏静态结构 | AppShell 已挂载;`/api/health`、`/api/qa/info` 正常 | 1. 检查 `.status-bar` 高 28px;2. 检查左 4 个 `.agent-dot-item`;3. 检查右侧版本/会话数/健康标记 | 高=28px;agent 点数量=4;右侧文本含 `PlantAI RAG v0.1` 与 QA 版本号(来自 `/api/qa/info` 的 `version`,如 `1.1.73-assertion-anchored`) | L5-D | P1 |
| TC-SHELL-007 | FR-SHELL-003 | 问答进行中状态栏四点联动 | 会话空闲;mock normal(SSE 回放) | 1. 发起提问;2. 在 SSE 进行中读取四个 agent 点的状态类 | 相位推进到 X 时第 X 个点激活(如 planning 时第 1 点 pulse);progress 全部结束后四点定格(成功态) | L5-D | P1 |
| TC-SHELL-008 | FR-SHELL-004 | 左栏折叠为 64px 图标轨 | Desktop 1440×900;左栏展开 | 1. 点击左栏折叠按钮;2. 检查 `.session-panel` 宽度与图标按钮(3 个 34×34);3. 刷新页面;4. 再次检查 | 折叠后宽度=64px;图标按钮=3 个;过渡 300ms;刷新后仍折叠 | L5-D | P1 |
| TC-SHELL-009 | FR-SHELL-004 | 左栏折叠状态持久化 | 同上 | 1. 折叠;2. 检查 `localStorage['pa-side-collapsed']` | localStorage 值为折叠标记;展开后标记被清除/反转 | L5-D | P2 |
| TC-SHELL-010 | FR-SHELL-005 | 右栏折叠保留手柄条 | Desktop 1440×900;右栏展开 | 1. 点击右栏折叠;2. 检查手柄条尺寸与可见性;3. 点击手柄展开;4. 检查 `localStorage['pa-bench-collapsed']` | 折叠后 `.bench-panel` 隐藏但手柄条 28px 可见可点;点击后恢复展开;刷新后保持折叠态 | L5-D | P1 |
| TC-SHELL-011 | FR-SHELL-006 | Aurora 背景不遮挡交互 | 任意视口;AppShell 已挂载 | 1. 检查 aurora 层 computed style;2. 点击顶栏主题按钮、会话列表项、作曲器输入框(逐个执行且均生效) | aurora 层 `position:fixed`、`z-index:0`、`pointer-events:none`;上述交互全部可操作 | L5-D | P1 |
| TC-SHELL-012 | FR-SHELL-006 | 浅色主题 aurora 衰减 | 已切浅色 | 检查 aurora 层或根元素的 `--pa-aurora-opacity` | computed 值=`.08`(UI_SPEC §1.2 令牌值) | L4 | P2 |
| TC-SHELL-013 | FR-SHELL-007 | 首屏初始化顺序与并行请求 | 深色主题已存 localStorage;无会话 | 1. 打开应用;2. 网络面板记录启动期请求 | `documentElement.dataset.theme` 在应用挂载前已写入(断言:无白色闪屏——深色下首帧背景即深色;实现断言:main.js 在 createApp 前写 dataset);启动期存在 GET `/api/sessions`、`/api/health`、`/api/qa/info` 三个请求且并行(无串行依赖) | L5-D + L3 | P0 |
| TC-SHELL-014 | FR-SHELL-007 | 首屏接口失败不阻塞渲染 | mock 对 `/api/health` 返回 500(或 BFF 停止) | 打开应用 | 页面仍渲染 AppShell 与欢迎空态;健康标记显示降级/离线态;无未捕获异常 | L5-D(mock error 场景) | P1 |
| TC-SHELL-015 | FR-SHELL-007 | 无会话显示欢迎空态 | 数据库无会话 | 打开应用 | 对话区显示欢迎空态(渐变菱形 + 标题 + 3 张建议卡) | L5-D | P1 |
### 1.3 THEME 主题与无障碍(FR-THEME-001~006)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-THEME-001 | FR-THEME-001 | 深色默认主题 | 首次打开(无 pa-theme 存储) | 1. 打开应用;2. 检查 `documentElement.dataset.theme` 与 `--pa-canvas` computed 值 | theme='dark';canvas=#0A0A10(rgb(10,10,16)) | L5-D | P0 |
| TC-THEME-002 | FR-THEME-001 | 浅色主题逐组件走查 | 已切浅色 | 逐个检查顶栏、会话项、气泡、作曲器、bench 面板的计算样式 | 无失色:各元素背景/文字均来自浅色令牌(canvas=#F6F8FC,surface-1=#FFFFFF);无深色令牌残留(如 #0A0A10 不再出现于背景) | L5-D(或 L6 人工走查) | P0 |
| TC-THEME-003 | FR-THEME-002 | 主题切换即时生效 | 默认深色 | 1. 点击顶栏主题按钮;2. 立即检查 `documentElement.dataset.theme` 与 localStorage;3. 刷新后复查 | dataset.theme 即时='light';`localStorage['pa-theme']='light'`;刷新后仍为 light;再切回同理 | L5-D | P0 |
| TC-THEME-004 | FR-THEME-002 | 主题图标旋转动画 | 同上 | 切换主题时检查图标 transform | 图标日/月互换且 rotate 180°(transition 400ms) | L5-D | P2 |
| TC-THEME-005 | FR-THEME-003 | 浅色 glow 衰减 | 已切浅色 | 检查根元素 `--pa-glow-opacity` computed 值 | 值=.35(深色下=1) | L4 | P2 |
| TC-THEME-006 | FR-THEME-004 | 动效降级(reduced motion) | 系统「减少动态效果」开启;Playwright 以 `reducedMotion:'reduce'` 启动 context | 1. 打开应用;2. 检查 aurora/状态点/按钮的 animation 计算样式;3. 发起一次问答 | `@media (prefers-reduced-motion: reduce)` 生效:所有元素 animation-duration=0 或 animation 为 none;running 状态以静态符号(实心点 + 文字徽章)可辨认,无 pulse/shimmer/spin 运动 | L5-D(reducedMotion context) | P1 |
| TC-THEME-007 | FR-THEME-005 | 焦点环样式 | 任意视口 | Tab 键聚焦顶栏主题按钮与作曲器 textarea | `:focus-visible` 输出 2px `rgba(94,106,210,.5)` 焦点环(outline-offset 1px) | L5-D | P1 |
| TC-THEME-008 | FR-THEME-005 | 纯键盘完成主流程 | 空数据库;mock normal | 只用 Tab/Enter/Esc 完成:新建会话 → 聚焦输入 → 输入问题 → ⌘/Ctrl+Enter 发送 → Tab 切换工作台 tab → Esc 关闭面板 | 每一步可达且生效;Tab 顺序符合视觉顺序(顶栏 → 会话列表 → 对话 → 作曲器 → 工作台) | L5-D(键盘驱动) | P0 |
| TC-THEME-009 | FR-THEME-006 | 对比度达标(深色) | 深色主题 | 抽检 `.app-shell` 内 3 处文本(正文 ink、muted、subtle)的计算颜色与 canvas 背景,按 WCAG 公式计算对比度 | ink/canvas ≥15:1;ink-muted/canvas ≥4.5:1;ink-subtle 仅用于非关键信息 | L5-D + L3(工具函数断言,可脚本化) | P1 |
| TC-THEME-010 | FR-THEME-006 | 对比度达标(浅色) | 浅色主题 | 同 TC-THEME-009 步骤,浅色令牌 | ink(#16182A)/canvas(#F6F8FC) ≈ 计算值 ≥ 深色同等标准;ink-muted/canvas ≥4.5:1 | L5-D | P1 |
### 1.4 SESSION 会话管理(FR-SESSION-001~009)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-SESSION-001 | FR-SESSION-001 | 列表按 updated_at 倒序 | 数据库 ≥3 个会话,updated_at 互异(fixtures 保证) | 1. GET `/api/sessions`;2. 前端渲染列表;3. 依次读取条目标题 | 条目顺序 = updated_at 从新到旧 | L2(fixture 会话数据)+ L4 | P0 |
| TC-SESSION-002 | FR-SESSION-001 | 分组「今天/昨天/更早」 | ≥3 个会话,时间分别落在今天/昨天/2 天前 | 渲染列表 | 三个组标签(11px/500/字距0.6px)按序出现,组内条目归属正确;组内按时间倒序 | L4(clock mock) | P1 |
| TC-SESSION-003 | FR-SESSION-001 | 空列表引导文案 | 数据库无会话 | 渲染列表 | 显示引导文案(「暂无会话」类 labels 文案);不渲染列表条目 | L4 | P2 |
| TC-SESSION-004 | FR-SESSION-002 | 状态点四态区分 | 4 个会话分别 idle/running/done/error | 渲染列表 | 形状可区分:idle=空心、running=空心+脉冲动画、done=实心 success 色、error=实心 error 色;running 有 animation,其余无 | L4 | P1 |
| TC-SESSION-005 | FR-SESSION-003 | 新建会话 | 任意初始状态 | 1. 点击「新建会话」按钮;2. 观察网络请求与界面 | 发出 POST `/api/sessions`;列表新增一条「新会话」;切换为活动会话;对话区显示欢迎空态;**不产生空消息**(GET 详情 messages 为空数组) | L5-D + L2 | P0 |
| TC-SESSION-006 | FR-SESSION-003 | 新建连点不重复 | 同上 | 快速连点新建按钮 2 次 | 产生 2 个独立会话(列表+2,两条 POST);均切到最后创建的一个 | L5-D | P1 |
| TC-SESSION-007 | FR-SESSION-004 | 选择会话加载历史 | 会话含 text/table/sources/graph 块消息 | 点击该会话条目 | 发出 GET `/api/sessions/{id}`;加载中显示骨架屏;完成后消息按块类型渲染:markdown 文本、表格(md-table 样式)、来源、图谱块均出现 | L5-D(mock 会话详情含全块) | P0 |
| TC-SESSION-008 | FR-SESSION-004 | 切换会话中断进行中流 | 会话 A 流式进行中;会话 B 存在 | 点击会话 B | 会话 A 的 SSE 连接 abort(Network 面板连接关闭);会话 A 状态置 error;切回会话 A 后其消息标注「已中断」 | L5-D(mock slow/正常流) | P0 |
| TC-SESSION-009 | FR-SESSION-005 | 搜索过滤(中文/英文/大小写) | ≥3 个会话,标题含中英文混排 | 1. 输入中文关键词;2. 输入英文小写;3. 输入英文大写;4. 输入无匹配词;5. 清空 | 匹配为 title 大小写不敏感子串;无匹配显示「无匹配会话」;清空恢复全量;过滤期间无网络请求 | L5-D + L4 | P1 |
| TC-SESSION-010 | FR-SESSION-006 | 重命名提交 | 活动会话 | 1. 双击标题进入编辑;2. 输入新名;3. 回车 | PATCH `/api/sessions/{id}` 请求体 `{title:新名}`;列表与顶栏标题同步更新 | L5-D + L2 | P1 |
| TC-SESSION-011 | FR-SESSION-006 | 重命名取消与空标题 | 同上 | 1. 编辑中按 Esc;2. 再次编辑并清空标题后回车 | Esc 放弃改动;空标题提交按钮禁用或提交被拒,不发出 PATCH 空 title | L5-D | P2 |
| TC-SESSION-012 | FR-SESSION-007 | 删除需二次确认 | 2 个会话 | 1. 右键/菜单点删除;2. 出现确认弹层时点取消 | 未删除(列表不变、无 DELETE 请求) | L5-D | P1 |
| TC-SESSION-013 | FR-SESSION-007 | 删除当前会话切换 | 2 个会话;选中其中一个 | 删除并确认 | DELETE `/api/sessions/{id}` 204;当前会话切换到剩余最新一个;刷新列表后已删会话不再出现 | L5-D + L2 | P0 |
| TC-SESSION-014 | FR-SESSION-007 | 删除最后一个会话显示空态 | 仅 1 个会话 | 删除并确认 | 列表空;对话区显示欢迎空态 | L5-D | P1 |
| TC-SESSION-015 | FR-SESSION-007 | 级联删除消息 | 会话含 2 条消息;BFF 真实 | 删除会话后 GET `/api/sessions/{id}` | 返回 404(NOT_FOUND 信封);SQLite 中该会话消息行一并删除(L2 断言数据库) | L2 | P0 |
| TC-SESSION-016 | FR-SESSION-008 | 首问自动标题 | 新建会话 | 1. 提问(问题 40+ 字符);2. 检查 PATCH 请求与列表标题 | PATCH 请求体 title = 问题前 30 字符 + 省略号;列表标题同步变化 | L5-D + L2 | P0 |
| TC-SESSION-017 | FR-SESSION-008 | 手动改名后不覆盖 | 会话 meta.title_manual=true(改过名) | 1. 再次提问;2. 检查是否发出 title PATCH | 不发出改 title 的 PATCH;标题保持手动值 | L2(会话固定数据)+ L4 | P1 |
| TC-SESSION-018 | FR-SESSION-009 | 活动态高亮 | ≥2 个会话 | 1. 选中会话 A;2. 检查其 computed style;3. 悬停另一项 B 对比 | A 有 2px 渐变左竖条 + g-to 8% 底色 + 内描边;与悬停态(B)可区分 | L5-D | P2 |
### 1.5 CHAT 对话与问答(FR-CHAT-001~015)
#### 1.5.1 基础渲染
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-001 | FR-CHAT-001 | 欢迎空态元素与建议卡 | 无消息 | 打开应用 | 显示 46px 渐变菱形(✧)+ 渐变标题「海古纪 PlantAI 知识工作台」+ 副标题 + 3 张建议卡 | L5-D | P1 |
| TC-CHAT-002 | FR-CHAT-001 | 建议卡点击即提问 | 无消息;mock normal | 点击第 1 张建议卡 | 卡片文本进入作曲器并直接发送;出现用户气泡(内容=卡片文本)与助手骨架;发出 POST `/api/qa/chat/stream` | L5-D | P0 |
| TC-CHAT-003 | FR-CHAT-002 | 用户气泡样式与长文本换行 | 任意 | 发送 300 字无空格长文本 | 气泡右对齐,宽度 ≤ 父容器 70%;文本换行且不溢出(scrollWidth ≤ 气泡宽度) | L5-D | P2 |
| TC-CHAT-004 | FR-CHAT-003 | 助手消息头部与悬停竖线 | 已有助手消息 | 1. 检查头部(24px 渐变头像 ✦ + 「PlantAI 智能体」+ 时间);2. 悬停消息左缘 | 头部三要素齐全;左缘 2px 竖线 hover 时出现渐变 | L5-D | P2 |
| TC-CHAT-005 | FR-CHAT-003 | 多块混排顺序 | 消息 blocks 为 [pipeline,text,table,sources,graph](mock 会话详情) | 渲染该消息 | 各块按 blocks 数组顺序渲染;无块丢失 | L5-D | P1 |
| TC-CHAT-006 | FR-CHAT-004 | Markdown 表格样式 | 消息含表格块(mock 含 md-table 内容的 text 块) | 渲染 | 表格带 md-table 类:thead 2px 渐变下边框;数据格 mono 字体(表头为「说明」的列保持比例字体) | L5-D | P1 |
| TC-CHAT-007 | FR-CHAT-004 | 脚本注入被消毒 | 向问答返回的 answer 注入 `<script>window.__pwned=1</script>` 与 `<img src=x onerror=...>`(mock fixture 或 BFF 层构造) | 渲染该答案 | `window.__pwned` 为 undefined;DOM 中不存在 script 标签;onerror 未执行;内容经 DOMPurify 后 v-html | L5-D(注入 fixture)+ L3(sanitize 单测) | P0 |
| TC-CHAT-008 | FR-CHAT-014 | 流式自动滚动到底 | mock normal;消息区可滚动 | 发起提问 | 流式更新期间滚动条持续贴近底部(scrollTop+clientHeight ≥ scrollHeight−10) | L5-D | P1 |
| TC-CHAT-009 | FR-CHAT-014 | 上滚暂停自动滚动 | 流式进行中 | 向上滚动 ≥100px | 不再自动贴底;出现「回到最新」按钮 | L5-D | P1 |
| TC-CHAT-010 | FR-CHAT-014 | 「回到最新」恢复滚动 | 上滚暂停状态 | 点击「回到最新」按钮 | 滚动回底部;恢复自动滚动;按钮消失 | L5-D | P1 |
| TC-CHAT-011 | FR-CHAT-015 | 内联引用 chip 跳转高亮 | 答案含引用标记(citation 编号)与对应来源 | 点击引用 chip | bench 切换到「文献来源」tab 并滚动定位到对应条目;该条目高亮 2s 后消失;chip 编号与列表条目序号一致 | L5-D | P1 |
#### 1.5.2 作曲器
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-012 | FR-CHAT-005 | 输入框高度自适应 | 桌面 | 1. 输入 1 行文本测基线(min-height 46px);2. 输入 10 行文本 | 基线 ≥46px;随内容增高,最大 160px 后内部滚动(scrollHeight > clientHeight) | L5-D | P2 |
| TC-CHAT-013 | FR-CHAT-006 | 三模式切换 | 桌面;mock normal | 依次点击 问答/方案/检索 pill | 激活 pill 渐变底+白字+青光;非激活态可区分;切换即生效 | L5-D | P0 |
| TC-CHAT-014 | FR-CHAT-006 | 问答模式请求体 | mock 正常;问答模式 | 提问并抓取 POST `/api/qa/chat/stream` 请求体 | body.use_llm=true;question 为输入文本;无 native_chain 字段(或为 modes.js 定义默认) | L5-D + L3(modes.js 参数集断言) | P0 |
| TC-CHAT-015 | FR-CHAT-006 | 方案模式请求体 | 方案模式 | 同上 | body.use_llm=true;native_chain_enabled=true;native_chain_max_hops=3;native_chain_top_k=5;端点仍为 `/api/qa/chat/stream` | L5-D + L3 | P0 |
| TC-CHAT-016 | FR-CHAT-006 | 检索模式请求与响应 | 检索模式 | 1. 提问;2. 观察端点为 `/api/qa/search`;3. 等待完成;4. 检查消息块 | body.use_llm=false;响应 answer 为空;消息只含 sources(+pipeline)块,**无 text 答案块** | L5-D + L2 | P0 |
| TC-CHAT-017 | FR-CHAT-007 | 快捷键发送 | 桌面 | 输入文字后按 ⌘/Ctrl+Enter | 发送;出现用户气泡 | L5-D | P0 |
| TC-CHAT-018 | FR-CHAT-007 | Enter 换行 | 桌面 | 输入文字后按 Enter(非组合键) | 不发送;textarea 内换行(行数+1) | L5-D | P1 |
| TC-CHAT-019 | FR-CHAT-007 | 中英文输入法快捷键 | IME 输入法激活(模拟 composition 事件) | composition 期间按 Enter | 不触发发送(组合输入确认才触发) | L3(composition 事件模拟) | P1 |
| TC-CHAT-020 | FR-CHAT-007 | 空输入与忙碌禁用 | 流式进行中 | 1. 空输入点发送;2. 流式中点发送 | 按钮 disabled(opacity .45);无新请求;底部提示文案显示快捷键说明 | L5-D | P1 |
| TC-CHAT-021 | FR-CHAT-011 | 停止流式 | mock slow(长流) | 1. 提问;2. 流式中点击「停止」 | 发送按钮已变为「停止」;点击后 SSE 连接关闭(Network 断言);消息置 error 并标注「已停止」;已收到的块保留 | L5-D | P0 |
| TC-CHAT-022 | FR-CHAT-011 | 停止后无悬挂请求 | BFF 真实 + 上游 QA | 流式中停止;随后检查 BFF 日志 | 前端 abort 后 BFF 取消上游请求(BFF 侧无悬挂 upstream 连接;日志有取消记录) | L2(respx 断言 abort)+ L5 | P1 |
#### 1.5.3 流式主流程(FR-CHAT-008)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-023 | FR-CHAT-008 | 主流程-用户消息立即落库 | mock normal;新会话 | 发送问题 | 用户气泡立即出现(不等后端);发出 POST `/api/sessions/{id}/messages`,body={role:user,text};落库成功 | L5-D + L2 | P0 |
| TC-CHAT-024 | FR-CHAT-008 | 主流程-会话置 running 与骨架 | 同上 | 发送后观察 | 会话状态置 running(左栏状态点脉冲动画);底栏 4 agent 点复位;出现助手骨架消息(status=streaming)含 pipeline 块,五相位全 waiting | L5-D | P0 |
| TC-CHAT-025 | FR-CHAT-008 | 主流程-progress 相位推进与阶段卡 | mock normal(sse_frames 12 帧) | 提问后观察 | 每帧 progress:pipeline 对应相位 running、此前相位 done;工作台「检索过程」新增阶段卡,数量=progress 帧数(11 个 stage 帧);阶段卡 label 为中文(如「已识别实体」) | L5-D | P0 |
| TC-CHAT-026 | FR-CHAT-008 | 主流程-complete 生成三块 | mock normal;提问完成 | 等待 complete | 消息含 text 块(揭示动画结束为最终文本)、sources 块、graph 块;pipeline 五相位全部 done;消息状态 done;会话状态 done | L5-D | P0 |
| TC-CHAT-027 | FR-CHAT-008 | 主流程-答案内容(依赖充值) | mock normal(mock 答案为固定文本);真实上游需充值 | 断言答案文本 | mock 下:答案文本与 mock fixture 一致(可断言内容);真实上游:answer 为自然语言答案(**依赖充值**,当前 402 下为 fallback 证据列表) | L5-D / L6 | P1 |
| TC-CHAT-028 | FR-CHAT-008 | 主流程-检查点持久化节奏 | BFF 真实;流 ≥3s | 提问并抓取 PATCH 请求 | 流式中每约 3s 发出 PATCH `/api/sessions/{id}/messages/{mid}`(块检查点);终态再发一次终态 PATCH(done/error) | L2 + L5 | P0 |
| TC-CHAT-029 | FR-CHAT-008 | 主流程-长任务持续反馈(240s) | mock slow(长流,或上游真实 ~92s) | 提问并计时观察 | 240s 内任一时刻页面均有视觉反馈(相位卡 shimmer/已耗时计数);无静止超过 5s 的状态(5s 间隔采样断言有动画元素或文本变化) | L5-D(slow 场景) | P0 |
| TC-CHAT-030 | FR-CHAT-008 | 网络中断重试按钮 | 流式中断网(playwright context.setOffline(true)) | 1. 流式中断网;2. 观察消息状态;3. 恢复网络;4. 观察是否自动重连;5. 点「重试」 | 消息置 error,文案「连接中断」;出现「重试」按钮;**不自动重连**(恢复网络后无新请求,需手动点击);点重试后重新发起同问题请求 | L5-D(offline 模拟) | P0 |
| TC-CHAT-031 | FR-CHAT-008 | 刷新恢复中断会话 | 流式进行中刷新页面 | 刷新后检查该会话 | 显示最后检查点内容;标注「已中断」;会话状态 error;不自动重试 | L5-D | P0 |
| TC-CHAT-032 | FR-CHAT-008 | 同一会话并发提问防护 | 流式进行中 | 观察发送按钮 | 按钮 disabled;无法发送第二个问题 | L5-D | P1 |
| TC-CHAT-033 | FR-CHAT-008 | 同会话提问可引用上文(默认开;设置中关闭后恢复独立) | 同一会话已完成一次提问 | 第二次提问并抓取请求体 | 第二次请求只含当前 question,无历史消息拼接(max_rounds:1 语义);UI 有「每次提问独立检索」提示文案 | L2 + L5 | P1 |
#### 1.5.4 流水线卡与揭示动画(FR-CHAT-009 / FR-CHAT-010)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-034 | FR-CHAT-009 | 五相位视觉与颜色 | 流式中与完成后分别观察 pipeline 卡 | 检查五个 p-step 的颜色令牌与状态字形 | 相位色:规划#C0A8DD、检索#9FBBE0、证据#9FC9A2、生成#DFA88F、完成#C08532;状态字形 ✓done/●running/◌waiting;running 相位带 11px 旋转 spinner;卡头「⚙ 检索流水线」+ 整体状态徽章(语义色) | L5-D | P0 |
| TC-CHAT-035 | FR-CHAT-009 | 相位与语义色不混用 | 流式中出现错误(mock error 场景) | 检查 pipeline 卡 | 相位点颜色只随相位走(五相位色);整体成败徽章只用语义色(success/error)——两者不互换 | L5-D | P1 |
| TC-CHAT-036 | FR-CHAT-010 | 揭示动画与跳过 | mock normal;答案长度已知 | 1. 观察 complete 后答案揭示;2. 点击「跳过」 | 揭示速度 30ms/字符,尾部 8×15px 青色闪烁光标 + 3px shimmer 进度线;点「跳过」后立即显示全文,reveal 元素移除 | L5-D | P1 |
| TC-CHAT-037 | FR-CHAT-010 | 长答案 8s 上限 | mock 构造 >2000 字符答案 | 测量揭示总时长 | 速度自动加快,总时长 ≤8s | L5-D | P2 |
#### 1.5.5 错误与重试(FR-CHAT-012)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-038 | FR-CHAT-012 | 引用校验失败重试 | BFF 对 invalid_llm_citation 已自动重试一次仍失败(L2 构造) | 观察响应与界面 | 前端展示「引用校验失败,请重试」(INVALID_CITATION 信封 message)并提供重试按钮 | L2(respx 断言 BFF 重试一次)+ L5 | P0 |
| TC-CHAT-039 | FR-CHAT-012 | 其他错误展示 message | mock scenario=error | 提问 | 消息置 error;展示 error.message 文案(上游错误中文文案);提供重试按钮;已收到块保留 | L5-D(error 场景) | P0 |
| TC-CHAT-040 | FR-CHAT-012 | 重试同位置替换 | 错误后 | 点击重试 | 用相同问题与模式重新发起;**不新增用户消息**(消息列表长度不变,同一条助手消息位置更新) | L5-D | P0 |
| TC-CHAT-041 | FR-CHAT-012 | SSE error/timeout 事件 | mock 构造 event:error 与 event:timeout 帧 | 提问 | error 帧→展示 error.message;timeout 帧→文案「检索超时」;两者均置消息 error 并保留已收到块 | L5-D(定制 mock 流) | P1 |
#### 1.5.6 持久化与恢复(FR-CHAT-013)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-CHAT-042 | FR-CHAT-013 | 块联合完整落库 | BFF 真实;完成一次问答 | 检查 SQLite 该消息行 | blocks 含 text/table/sources/graph/pipeline 等全部完成块;**无 stream 块**(瞬态已转 text);raw 字段保存完整归一化响应 | L2 | P0 |
| TC-CHAT-043 | FR-CHAT-013 | 刷新后恢复全部块 | 完成一次含表格/来源/图谱的问答 | 刷新页面并打开该会话 | GET `/api/sessions/{id}` 后全部块正确重渲染(表格、来源、图谱可见);无数据丢失 | L5-D | P0 |
### 1.6 RETRIEVAL 检索过程(FR-RETRIEVAL-001~006)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-RETRIEVAL-001 | FR-RETRIEVAL-001 | 阶段卡与 progress 帧一一对应 | mock normal;完成一次问答 | 统计工作台 Tab1 卡片数与 Network 中 progress 帧数 | 卡片数 = progress 帧数(sse_frames 11 个 stage 帧 → 11 张卡);每卡含相位色图标 + 阶段中文名 + 状态点 + 耗时 mono | L5-D | P0 |
| TC-RETRIEVAL-002 | FR-RETRIEVAL-001 | 阶段卡展开体参数块 | 已有一张阶段卡 | 展开卡头 | 展开体显示 details 参数块(mono)+ 摘要行(如 entities 列表) | L5-D | P2 |
| TC-RETRIEVAL-003 | FR-RETRIEVAL-002 | 相位筛选 | 一次问答后存在 4 个相位卡片 | 依次点击 全部/规划/检索/证据/生成 chip | 激活 chip 实心 #5E6AD2 底 + 白字;筛选后仅显示对应相位卡片(计数=对应相位帧数) | L5-D | P1 |
| TC-RETRIEVAL-004 | FR-RETRIEVAL-003 | 展开折叠与默认态 | 流式中(running 卡)与完成后各观察一次 | 1. 流式中看卡默认态;2. 完成后看默认态;3. 点击头部 | 运行中的卡默认展开;完成后自动折叠;点击切换展开/折叠;chevron 旋转 90°;展开体 fade-slide 200ms;各卡状态互相独立 | L5-D | P1 |
| TC-RETRIEVAL-005 | FR-RETRIEVAL-004 | 运行中效果 | 流式中 | 检查 running 卡 | 头部 shimmer 扫光(1.8s 循环)+ 状态点脉冲;完成后动效停止(animation none/移除) | L5-D | P2 |
| TC-RETRIEVAL-006 | FR-RETRIEVAL-005 | 检索计划展示与无 plan 不显示 | mock normal(fixture 含 retrieval_plan)与无 plan 的响应各一次 | 检查列表顶部 | 含 retrieval_plan 时顶部只读信息块展示 plan;无 plan 时该区域**不渲染**(无空框);另展示 `/api/qa/info` 的 12 段 pipeline 静态说明 | L5-D | P1 |
| TC-RETRIEVAL-007 | FR-RETRIEVAL-006 | 空态 | 未提问 | 打开工作台 Tab1 | 显示「发起提问后,这里会实时展示检索过程」;无假卡片 | L5-D | P2 |
### 1.7 SOURCE 文献来源(FR-SOURCE-001~006)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-SOURCE-001 | FR-SOURCE-001 | 来源列表条目数与元素 | mock normal 完成问答(source_count=4) | 打开工作台 Tab2 | 条目数 = 4(与响应 source_count 一致);每条:序号 + 标题(超长省略)+ mono 元信息行(PMID:xxx / DOI:xxx / 分数)+ 证据片段(默认 2 行截断) | L5-D | P0 |
| TC-SOURCE-002 | FR-SOURCE-001 | 证据片段展开 | 有一条来源 | 点击片段 | 展开显示完整 snippet;再点收起 | L5-D | P2 |
| TC-SOURCE-003 | FR-SOURCE-002 | 字段缺失不渲染占位 | mock 构造 source 缺 pmid/pmcid/doi/section 的组合 | 渲染列表 | 缺失字段位置不显示占位符;页面文本中不含 `undefined`、`null` 字样 | L5-D | P0 |
| TC-SOURCE-004 | FR-SOURCE-003 | 外链优先级 | 4 个 source:a 有 url;b 无 url 有 doi;c 无 url/doi 有 pmid;d 无 url/doi/pmid 有 pmcid;e 全无 | 检查各条目链接 | a 链=url;b=`https://doi.org/{doi}`;c=PubMed PMID 链接;d=PMC 链接;e 无链接图标;点击新标签打开且带 `rel="noopener"` | L5-D | P1 |
| TC-SOURCE-005 | FR-SOURCE-004 | 证据链分组与展开 | 响应 chains 含 ≥2 个 chain_id | 打开证据链区 | 按 chain_id 分组显示;组徽章显示跳数;展开后逐跳列表 `源实体 —[关系]→ 目标实体`,每跳附 paper_id/PMID;顺序与 hops 数组一致 | L5-D | P1 |
| TC-SOURCE-006 | FR-SOURCE-005 | 会话级聚合 | 同一会话完成 2 次问答(相同 paper 出现多次) | 切到「本会话全部」 | 发出 GET `/api/sessions/{id}/sources`;按 paper_id 去重;每条 count = 该 paper 累计出现次数;去重后条数正确 | L5-D + L2 | P1 |
| TC-SOURCE-007 | FR-SOURCE-006 | 空态 | mock scenario=empty 完成问答(source_count=0) | 打开工作台 Tab2 | 显示「本次检索未命中文献」;无空列表框(无 .ft-item 元素) | L5-D(empty 场景) | P1 |
### 1.8 EXTRACT 提取任务(FR-EXTRACT-001~006)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-EXTRACT-001 | FR-EXTRACT-001 | 任务列表与派生百分比 | mock 任务列表(含 queued/running/completed/failed 各一) | 打开工作台 Tab3 | 发出 GET `/api/extraction/jobs`;列表与响应一致;百分比派生正确:queued=5、running(35/75 按 stage)、completed=100、failed 无进度条且显示错误态;100% 为纯 success 色且无 sweep 扫光 | L5-D + L2(BFF 派生断言) | P0 |
| TC-EXTRACT-002 | FR-EXTRACT-002 | 任务详情 | 已有一个任务 | 点击展开 | GET `/api/extraction/jobs/{id}`;显示 status、message(中文进度)、stats 统计字段(stage/species/figure_table 计数) | L5-D | P1 |
| TC-EXTRACT-003 | FR-EXTRACT-002 | 未完成任务 plan 不显示 | 一个 running 任务 | 展开详情 | plan 为 null 时**不显示 plan 区块**且无报错 | L5-D | P1 |
| TC-EXTRACT-004 | FR-EXTRACT-003 | 运行日志 | mock 正常 | 打开运行日志 | GET `/api/extraction/run-log`;mono 等宽展示;长日志在最大高度内滚动(scrollHeight > clientHeight 时出现内部滚动);自动贴底 | L5-D | P2 |
| TC-EXTRACT-005 | FR-EXTRACT-004 | 上传 PDF 成功 | 构造 ≤50MB PDF;mock 上传成功 | 附件按钮 → 选 PDF → 上传 | POST `/api/extraction/upload`(multipart,Content-Type 含 multipart/form-data);显示上传进度;成功返回 job_id 并刷新列表(出现新任务) | L5-D | P1 |
| TC-EXTRACT-006 | FR-EXTRACT-004 | 非 PDF 被拒 | 一个 .txt 文件 | 尝试上传 | 被拒绝(前端拦截或 422);不发出上传请求(前端拦截时)或返回 VALIDATION 信封 | L5-D + L2 | P1 |
| TC-EXTRACT-007 | FR-EXTRACT-004 | 超 50MB 被拒 | 一个 >50MB PDF | 尝试上传 | 被拒绝;提示超出大小限制;不发出上传请求 | L5-D | P2 |
| TC-EXTRACT-008 | FR-EXTRACT-004 | 上游失败错误文案 | mock 返回 502(MinerU 不可用) | 上传 | 展示上游 message 的明确错误文案(非堆栈);任务列表/详情为失败态 | L5-D | P1 |
| TC-EXTRACT-009 | FR-EXTRACT-005 | 轮询节奏 | 列表含一个 running 任务 | 观察 12s 内网络请求 | 每 5s 轮询一次 GET `/api/extraction/jobs`;全部终态后轮询停止(再观察 12s 无新请求) | L5-D | P1 |
| TC-EXTRACT-010 | FR-EXTRACT-005 | 切 tab 暂停轮询 | running 任务存在;切换到其他 tab | 观察网络 | 离开 Tab3 期间无 jobs 轮询请求;切回恢复 | L5-D | P2 |
| TC-EXTRACT-011 | FR-EXTRACT-006 | 离线降级 | mock 对 extraction 返回 503(degraded) | 打开 Tab3 | 显示离线提示与重试按钮;其他 tab(检索/来源/图谱)不受影响可正常使用 | L5-D(degraded 场景) | P1 |
### 1.9 KG 知识图谱(FR-KG-001~008)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-KG-001 | FR-KG-001 | 答案图谱渲染(SVG 力导向) | mock normal 完成问答(graph 块 6 节点 4 边) | 打开工作台 Tab4 | 渲染手写 SVG 力导向图:节点圆点+标签;边为渐变线(#5E6AD2→#00D4FF)带关系名;节点与答案引用实体一致(与 graph 块节点 label 一致) | L5-D | P0 |
| TC-KG-002 | FR-KG-001 | 节点 >50 降级列表 | mock 构造 graph 块 >50 节点 | 打开 Tab4 | 自动降级为列表视图并提示;不渲染 SVG 画布 | L5-D | P1 |
| TC-KG-003 | FR-KG-002 | 节点着色与图例 | graph 块含 ≥2 种实体 type | 检查节点颜色与图例 | 按 type 着色(品牌+辅助紫+五相位色板);底部图例存在且与节点颜色一一对应;同 type 在会话内颜色稳定(两次问答同一 type 颜色相同) | L5-D | P2 |
| TC-KG-004 | FR-KG-003 | 节点详情面板 | graph 块有节点;Neo4j 不可用(mock 无 kg 或 503) | 点击一个节点 | 侧滑详情面板显示实体属性(消息内已有属性);**Neo4j 不可用时仍显示**(不报错、不空白) | L5-D | P1 |
| TC-KG-005 | FR-KG-003 | Neo4j 可用时拉全量属性 | Neo4j 可用(真实上游或 mock) | 点击节点 | 面板内额外数据来自 GET `/api/kg/entities/{name}`(发出该请求并渲染返回 properties) | L5-D | P2 |
| TC-KG-006 | FR-KG-004 | 实体搜索(精确/前缀) | mock normal | 1. 输入「OsSPL」;2. 回车 | GET `/api/kg/entities?q=OsSPL`;结果显示(精确或前缀匹配项);响应 <1s(断言用时) | L5-D + L2 | P0 |
| TC-KG-007 | FR-KG-004 | 实体搜索选中渲染邻域 | 上一步结果 | 点击第一个结果 | 渲染该实体邻域(调 neighborhood 接口或 mock 数据);画布更新为该实体为中心 | L5-D | P1 |
| TC-KG-008 | FR-KG-005 | 邻域深度切换 | mock normal | 1. 深度选 1(默认)观察请求;2. 深度选 2 观察 | 请求 depth 参数分别为 1/2;渲染节点数随之变化;深度 2 时显示「较慢」提示文案(两跳实测约 13s) | L5-D + L2 | P1 |
| TC-KG-009 | FR-KG-005 | 节点上限 200 截断 | mock 构造 >200 节点邻域 | 深度 2 展开 | 渲染节点数 ≤200;每跳按 paper_count/support_count 降序截断(L2 断言 BFF 截断逻辑);超限有提示不卡死 | L2 + L5 | P1 |
| TC-KG-010 | FR-KG-006 | 缩放平移(桌面) | 画布有图 | 滚轮缩放;拖拽平移;双击 | 缩放范围 0.3×–3×;平移生效;双击复位到初始视图 | L5-D | P1 |
| TC-KG-011 | FR-KG-006 | 触摸缩放平移(移动端) | Mobile 视口;画布有图 | 双指捏合;单指拖拽 | 双指缩放与单指拖拽均可用且流畅(缩放比例改变;拖拽后画布位移) | L5-M(touch 模拟) | P1 |
| TC-KG-012 | FR-KG-007 | Neo4j 不可用降级 | mock kg 接口返回 503(或 BFF 断开 Neo4j) | 打开 Tab4 | 搜索框与邻域功能禁用并提示离线;**答案图谱照常渲染**;tab 不白屏 | L5-D | P1 |
| TC-KG-013 | FR-KG-008 | 空态 | 本次回答无 graph 数据(mock empty) | 打开 Tab4 | 提示「本次检索未产生图谱关系」+ 引导使用实体搜索;不显示空画布 | L5-D(empty 场景) | P2 |
### 1.10 RESP 响应式(FR-RESP-001~013)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-RESP-001 | FR-RESP-001 | Desktop ≥1280 完整三栏 | Desktop 1440×900 | 检查布局 | 三栏 260/1fr/380 可见(同 TC-SHELL-001) | L5-D | P0 |
| TC-RESP-002 | FR-RESP-002 | Laptop 1024–1279 左栏自动折叠 | 视口 1200×900 | 检查布局 | 三栏保留;左栏宽=64px(自动折叠,无需点击);右栏=340px | L5-D(1200×900) | P1 |
| TC-RESP-003 | FR-RESP-003 | Tablet 左抽屉 | Tablet 768×1024 | 1. 检查布局(对话单栏铺满);2. 点顶栏汉堡 | 左栏默认隐藏;点汉堡后左抽屉 260px 滑入 + scrim 遮罩;顶栏有汉堡按钮;右栏为右抽屉(顶栏工作台按钮带来源数角标);点 scrim 或 Esc 关闭;动效 ease-out 300ms | L5-T | P0 |
| TC-RESP-004 | FR-RESP-004 | Mobile 单栏与工作台覆盖层 | Mobile 390×844 | 1. 检查布局;2. 点顶栏工作台按钮 | 顶栏=汉堡+标题+工作台按钮;对话铺满;作曲器吸底;工作台打开为**全屏覆盖层+顶部 tab 条**;底部状态栏隐藏(不可见);四个 agent 点合并为顶栏一枚聚合状态点;点 scrim 或 Esc 关闭 | L5-M | P0 |
| TC-RESP-005 | FR-RESP-005 | viewport 与安全区 | Mobile(iPhone 视口) | 检查 meta 与 computed 值 | `<meta viewport>` 含 `viewport-fit=cover`;作曲器 padding-bottom = env(safe-area-inset-bottom);顶栏 padding-top = env(safe-area-inset-top)(computed 值>0) | L5-M | P1 |
| TC-RESP-006 | FR-RESP-006 | iOS 输入放大规避 | Mobile 视口(<768px) | 检查 textarea computed font-size | font-size=16px;**未使用** maximum-scale=1(meta 内容断言) | L5-M | P0 |
| TC-RESP-007 | FR-RESP-007 | 悬停态触摸等价 | Mobile 视口;有来源条目与助手消息 | 检查来源外链图标、助手消息左缘线、会话条目样式 | 外链图标常驻可见;助手消息左缘线常驻;会话条目无 hover 底色依赖(点击反馈存在);`@media (hover:hover)` 包裹 hover 样式(L3 样式断言) | L5-M | P1 |
| TC-RESP-008 | FR-RESP-008 | 触控目标 44px | Mobile 视口 | 检查会话条目、bench tab、模式 pill、图标按钮高度 | min-height ≥44px(computed) | L5-M | P1 |
| TC-RESP-009 | FR-RESP-009 | 100dvh 视口高度 | Mobile 视口 | 检查应用根容器高度 | 使用 100dvh(computed 解析为实际视口高度);存在 100vh 回退声明(L3 样式断言) | L5-M | P2 |
| TC-RESP-010 | FR-RESP-010 | 虚拟键盘适配 | Mobile 视口;visualViewport 可模拟 | 聚焦 textarea(模拟键盘弹出压缩 visualViewport) | 消息区高度压缩并保持贴底;作曲器始终可见(boundingBox 在视口内) | L5-M | P1 |
| TC-RESP-011 | FR-RESP-011 | 表格横向滚动 | Mobile 视口;消息含宽表格 | 检查 md-table 容器 | 表格外层有横向滚动容器;容器 scrollWidth > clientWidth 时可横滑查看完整内容;字体字号未被压缩(computed font-size ≥ 桌面值) | L5-M | P1 |
| TC-RESP-012 | FR-RESP-012 | 移动端性能降级 | Mobile 视口 | 检查 aurora 与图谱上限 | aurora 模糊半径降低或 `--pa-aurora-opacity:0`;图谱节点数上限=30(构造 >30 节点 graph 块时渲染 ≤30 或降级列表) | L5-M | P2 |
| TC-RESP-013 | FR-RESP-013 | 手势(可选 N/A) | Mobile 视口 | 左缘右滑 | 若实现:右滑开会话抽屉、右滑关工作台覆盖层可用;**未实现不算缺陷,本条 N/A 记录** | L5-M(标记 N/A) | P2 |
### 1.11 HEALTH 健康与降级(FR-HEALTH-001~005)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-HEALTH-001 | FR-HEALTH-001 | 健康轮询 30s | 打开应用 | 观察 65s 内 GET `/api/health` 请求 | 挂载后立即一次;此后每 30s 一次(65s 内共 3 次) | L5-D | P1 |
| TC-HEALTH-002 | FR-HEALTH-001 | 轮询失败不弹窗 | mock `/api/health` 持续 500 | 打开应用 | 无错误弹窗/未捕获异常;状态栏健康标记显示降级态 | L5-D | P1 |
| TC-HEALTH-003 | FR-HEALTH-001 | 上游恢复 30s 内解禁 | mock 先 503 后恢复正常(场景切换) | 1. 观察禁用态;2. 切回正常场景;3. ≤30s 内观察 | 上游恢复后 ≤30s(一个轮询周期内)对应功能自动解禁,无需手动刷新 | L5-D | P1 |
| TC-HEALTH-004 | FR-HEALTH-002 | QA 不可用降级 | mock scenario=degraded(/api/qa/* 503) | 打开应用 | 作曲器禁用并显示「知识问答服务当前不可用」;历史会话仍可浏览(点击会话可看历史消息);无错误弹窗 | L5-D(degraded 场景) | P0 |
| TC-HEALTH-005 | FR-HEALTH-002 | QA 降级信封语义 | mock degraded | 检查响应结构 | HTTP 503 + `{"ok":false,"error":{"code":"UPSTREAM_DOWN","message":"…","degraded":true}}`;前端按 degraded 处理(横幅/离线态)而非错误弹窗 | L2 + L5 | P0 |
| TC-HEALTH-006 | FR-HEALTH-003 | Neo4j 不可用降级 | mock kg 503 | 打开 Tab4 | 搜索/邻域禁用并提示离线;答案图谱照常渲染(同 TC-KG-012) | L5-D | P1 |
| TC-HEALTH-007 | FR-HEALTH-004 | 抽取不可用降级 | mock extraction 503 | 打开 Tab3 | 仅 Tab3 降级(离线提示+重试按钮);其他 tab 正常(同 TC-EXTRACT-011) | L5-D | P1 |
| TC-HEALTH-008 | FR-HEALTH-005 | 网络中断提示与不自动重连 | 流式中断网(同 TC-CHAT-030) | 1. 断网;2. 恢复网络观察 | 提示「连接中断」+ 重试按钮;不自动重连;无重复 LLM 调用(Network 无自动新请求) | L5-D | P0 |
### 1.12 非功能要求(PRD §14)对照用例
| 编号 | 对应要求 | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-NFR-001 | 首屏可交互 | 桌面;mock normal | 打开应用并计时(performance.timing / Playwright 计时) | 桌面 <2s 可交互(首屏渲染+会话列表加载完成);手机 <3s | L5-D / L5-M | P1 |
| TC-NFR-002 | 长任务反馈 | mock slow(长流) | 提问并采样 | 240s 内无静止 >5s 状态(同 TC-CHAT-029) | L5-D | P0 |
| TC-NFR-003 | Neo4j 凭据不下发 | 打开应用并抓取全部网络响应与 JS bundle 文本 | 浏览器侧任何响应/源码中不含 Neo4j 密码(<neo4j-password-in-.env> 等)与 bolt:// URI | L5-D + L3(bundle 扫描) | P0 |
| TC-NFR-004 | 零外网请求 | 打开应用并抓取全部网络请求 | 所有请求 host 均为 127.0.0.1(或部署域);无 fonts.googleapis.com / CDN 域名请求 | L5-D | P1 |
| TC-NFR-005 | 浏览器兼容基线 | Chrome 110+/Firefox 110+/Safari 16+ | Playwright 三浏览器各跑冒烟 2 条 | 冒烟通过(页面加载 + AppShell 存在) | L5(chromium 常驻;firefox/webkit 每轮按需) | P1 |
### 1.13 E2E 主线场景(TEST_PLAN §6 九条主线 × 三档视口)
编号规则 `TC-E2E-<主线号>-<视口>`,M=Mobile(390×844)|T=Tablet(768×1024)|D=Desktop(1440×900)。每条为一条用例,步骤与预期为该视口下的完整流程断言。全量用例在后续轮次落为 spec 文件;本波仅实现 TC-E2E-SMOKE-01/02(§1.14)。
| 编号 | 主线 | 视口 | 步骤 | 预期结果 | 优先级 |
|---|---|---|---|---|---|
| TC-E2E-01-M | 1 主流程 | M | 新建会话 → 问答模式提问 → 观察流水线五相位推进 → 等待答案揭示(含表格)→ 来源 tab 有数据 → 图谱 tab 渲染 → 刷新后历史恢复 | 五相位按序推进(waiting→running→done);答案揭示并含 md-table;Tab2 条目数=source_count;Tab4 SVG 图渲染;刷新后该会话消息完整恢复 | P0 |
| TC-E2E-01-T | 1 主流程 | T | 同 TC-E2E-01-M(左栏经抽屉进入会话) | 同 TC-E2E-01-M;另断言左/右抽屉开合正常 | P0 |
| TC-E2E-01-D | 1 主流程 | D | 同 TC-E2E-01-M | 同 TC-E2E-01-M | P0 |
| TC-E2E-02-M | 2 检索模式 | M | 检索模式提问 → 等待完成 → 检查消息块 | 无 text 答案块;仅来源数据;请求体 use_llm=false 且端点 `/api/qa/search` | P0 |
| TC-E2E-02-T | 2 检索模式 | T | 同 TC-E2E-02-M | 同 TC-E2E-02-M | P0 |
| TC-E2E-02-D | 2 检索模式 | D | 同 TC-E2E-02-M | 同 TC-E2E-02-M | P0 |
| TC-E2E-03-M | 3 错误与重试 | M | scenario=error 下提问 → 观察错误;scenario=degraded 下观察作曲器 | error:错误文案展示+重试按钮可用(点击后重新发起);degraded:作曲器禁用+「知识问答服务当前不可用」提示 | P0 |
| TC-E2E-03-T | 3 错误与重试 | T | 同 TC-E2E-03-M | 同 TC-E2E-03-M | P0 |
| TC-E2E-03-D | 3 错误与重试 | D | 同 TC-E2E-03-M | 同 TC-E2E-03-M | P0 |
| TC-E2E-04-M | 4 会话管理 | M | 新建/切换/重命名/删除/搜索过滤/观察分组 | 每步按 SESSION 用例断言:新建+1、切换加载历史、重命名同步顶栏、删除需确认且列表-1、搜索实时过滤、分组标签正确 | P0 |
| TC-E2E-04-T | 4 会话管理 | T | 同 TC-E2E-04-M | 同 TC-E2E-04-M | P0 |
| TC-E2E-04-D | 4 会话管理 | D | 同 TC-E2E-04-M | 同 TC-E2E-04-M | P0 |
| TC-E2E-05-M | 5 中断 | M | 流式中途切会话 → 切回原会话 | 原会话置 error 且标注「已中断」;已收到块保留;无悬挂流 | P0 |
| TC-E2E-05-T | 5 中断 | T | 同 TC-E2E-05-M | 同 TC-E2E-05-M | P0 |
| TC-E2E-05-D | 5 中断 | D | 同 TC-E2E-05-M | 同 TC-E2E-05-M | P0 |
| TC-E2E-06-M | 6 主题 | M | 深浅切换 → 刷新 | 切换即时生效(dataset.theme 与 localStorage);刷新后保持 | P0 |
| TC-E2E-06-T | 6 主题 | T | 同 TC-E2E-06-M | 同 TC-E2E-06-M | P0 |
| TC-E2E-06-D | 6 主题 | D | 同 TC-E2E-06-M | 同 TC-E2E-06-M | P0 |
| TC-E2E-07-M | 7 图谱 | M | 实体搜索 → 选中渲染邻域 → 节点详情 → 双指缩放 + 单指拖拽 | 搜索结果渲染;邻域画布更新;详情面板打开;触摸缩放/拖拽生效 | P1 |
| TC-E2E-07-T | 7 图谱 | T | 同 TC-E2E-07-M(触摸为单指拖拽+双指捏合) | 同 TC-E2E-07-M | P1 |
| TC-E2E-07-D | 7 图谱 | D | 实体搜索 → 邻域 → 详情 → 滚轮缩放/拖拽平移/双击复位 | 同 TC-E2E-07-M(桌面交互) | P1 |
| TC-E2E-08-M | 8 抽取 | M | 任务列表 → 详情展开 → 运行日志;mock 下上传 PDF | 列表渲染+百分比正确;详情字段齐全;日志滚动;上传成功返回 job_id 并刷新列表 | P1 |
| TC-E2E-08-T | 8 抽取 | T | 同 TC-E2E-08-M | 同 TC-E2E-08-M | P1 |
| TC-E2E-08-D | 8 抽取 | D | 同 TC-E2E-08-M | 同 TC-E2E-08-M | P1 |
| TC-E2E-09-M | 9 响应式专项 | M | 布局断言(FR-RESP-004 全项)+ 移动端专项:安全区、16px 输入、44px 触控、表格横滚、键盘适配 | 顶栏=汉堡+标题+工作台按钮;作曲器吸底;工作台全屏覆盖层+tab 条;底栏隐藏;聚合状态点存在;safe-area padding 生效;textarea 16px;触控目标 ≥44px;宽表格横滚;聚焦时作曲器可见 | P0 |
| TC-E2E-09-T | 9 响应式专项 | T | 布局断言(FR-RESP-003 全项:抽屉/scrim/角标) | 单栏铺满;左右抽屉开合+scrim+Esc 关闭;汉堡与工作台按钮带来源数角标 | P0 |
| TC-E2E-09-D | 9 响应式专项 | D | 布局断言(FR-RESP-001/002:1280 边界与 1200 折叠) | 1440 完整三栏;1200 左栏自动折叠 64px 右栏 340px | P0 |
### 1.14 E2E 冒烟骨架用例(本波已实现)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-E2E-SMOKE-01 | FR-SHELL-007(页面加载) | 页面加载冒烟 | dev server 5180 可用;三档视口各跑一次 | 打开 `/` | title 含「海古纪 PlantAI」;`#app` 可见且内容非空 | L5-M/T/D | P0 |
| TC-E2E-SMOKE-02 | FR-SHELL-001/003/FR-RESP-004(壳层;移动端底栏隐藏断言) | AppShell 存在冒烟 | 同上 | 打开 `/` | 存在 `.app-shell` 时:shell/top-bar 可见且无占位符;status-bar 在 ≥768px 视口可见、移动端隐藏(FR-RESP-004);M0 占位期(无 .app-shell)回退:`.app-shell-placeholder` 可见 | L5-M/T/D | P0 |
---
## 2. 追溯矩阵
### 2.1 统计总览
| 项 | 值 |
|---|---|
| FR 总数 | 81 |
| 已覆盖 FR | 81 |
| 未覆盖清单 | (空) |
| TC 总数 | 179 |
| 孤儿 TC(无 FR 映射) | 0 |
| 主门禁(FR→TC 且 TC→FR 双向完整) | 81/81 = 100% |
### 2.2 FR→TC 矩阵(每个 FR 列出其全部 TC)
| FR | 用例 |
|---|---|
| FR-SHELL-001 | TC-SHELL-001, TC-SHELL-002, TC-E2E-SMOKE-02, TC-E2E-09-D |
| FR-SHELL-002 | TC-SHELL-003, TC-SHELL-004, TC-SHELL-005 |
| FR-SHELL-003 | TC-SHELL-006, TC-SHELL-007, TC-E2E-SMOKE-02 |
| FR-SHELL-004 | TC-SHELL-008, TC-SHELL-009 |
| FR-SHELL-005 | TC-SHELL-010 |
| FR-SHELL-006 | TC-SHELL-011, TC-SHELL-012 |
| FR-SHELL-007 | TC-SHELL-013, TC-SHELL-014, TC-SHELL-015, TC-E2E-SMOKE-01 |
| FR-THEME-001 | TC-THEME-001, TC-THEME-002 |
| FR-THEME-002 | TC-THEME-003, TC-THEME-004, TC-E2E-06-M, TC-E2E-06-T, TC-E2E-06-D |
| FR-THEME-003 | TC-THEME-005 |
| FR-THEME-004 | TC-THEME-006 |
| FR-THEME-005 | TC-THEME-007, TC-THEME-008 |
| FR-THEME-006 | TC-THEME-009, TC-THEME-010 |
| FR-SESSION-001 | TC-SESSION-001, TC-SESSION-002, TC-SESSION-003, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-002 | TC-SESSION-004 |
| FR-SESSION-003 | TC-SESSION-005, TC-SESSION-006, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-004 | TC-SESSION-007, TC-SESSION-008, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-005 | TC-SESSION-009, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-006 | TC-SESSION-010, TC-SESSION-011, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-007 | TC-SESSION-012, TC-SESSION-013, TC-SESSION-014, TC-SESSION-015, TC-E2E-04-M, TC-E2E-04-T, TC-E2E-04-D |
| FR-SESSION-008 | TC-SESSION-016, TC-SESSION-017 |
| FR-SESSION-009 | TC-SESSION-018 |
| FR-CHAT-001 | TC-CHAT-001, TC-CHAT-002 |
| FR-CHAT-002 | TC-CHAT-003 |
| FR-CHAT-003 | TC-CHAT-004, TC-CHAT-005 |
| FR-CHAT-004 | TC-CHAT-006, TC-CHAT-007 |
| FR-CHAT-005 | TC-CHAT-012 |
| FR-CHAT-006 | TC-CHAT-013, TC-CHAT-014, TC-CHAT-015, TC-CHAT-016, TC-E2E-02-M, TC-E2E-02-T, TC-E2E-02-D |
| FR-CHAT-007 | TC-CHAT-017, TC-CHAT-018, TC-CHAT-019, TC-CHAT-020 |
| FR-CHAT-008 | TC-CHAT-023, TC-CHAT-024, TC-CHAT-025, TC-CHAT-026, TC-CHAT-027, TC-CHAT-028, TC-CHAT-029, TC-CHAT-030, TC-CHAT-031, TC-CHAT-032, TC-CHAT-033, TC-E2E-01-M, TC-E2E-01-T, TC-E2E-01-D, TC-E2E-05-M, TC-E2E-05-T, TC-E2E-05-D |
| FR-CHAT-009 | TC-CHAT-034, TC-CHAT-035 |
| FR-CHAT-010 | TC-CHAT-036, TC-CHAT-037 |
| FR-CHAT-011 | TC-CHAT-021, TC-CHAT-022, TC-E2E-05-M, TC-E2E-05-T, TC-E2E-05-D |
| FR-CHAT-012 | TC-CHAT-038, TC-CHAT-039, TC-CHAT-040, TC-CHAT-041, TC-E2E-03-M, TC-E2E-03-T, TC-E2E-03-D |
| FR-CHAT-013 | TC-CHAT-042, TC-CHAT-043, TC-E2E-01-M, TC-E2E-01-T, TC-E2E-01-D |
| FR-CHAT-014 | TC-CHAT-008, TC-CHAT-009, TC-CHAT-010 |
| FR-CHAT-015 | TC-CHAT-011 |
| FR-RETRIEVAL-001 | TC-RETRIEVAL-001, TC-RETRIEVAL-002 |
| FR-RETRIEVAL-002 | TC-RETRIEVAL-003 |
| FR-RETRIEVAL-003 | TC-RETRIEVAL-004 |
| FR-RETRIEVAL-004 | TC-RETRIEVAL-005 |
| FR-RETRIEVAL-005 | TC-RETRIEVAL-006 |
| FR-RETRIEVAL-006 | TC-RETRIEVAL-007 |
| FR-SOURCE-001 | TC-SOURCE-001, TC-SOURCE-002 |
| FR-SOURCE-002 | TC-SOURCE-003 |
| FR-SOURCE-003 | TC-SOURCE-004 |
| FR-SOURCE-004 | TC-SOURCE-005 |
| FR-SOURCE-005 | TC-SOURCE-006 |
| FR-SOURCE-006 | TC-SOURCE-007 |
| FR-EXTRACT-001 | TC-EXTRACT-001, TC-E2E-08-M, TC-E2E-08-T, TC-E2E-08-D |
| FR-EXTRACT-002 | TC-EXTRACT-002, TC-EXTRACT-003, TC-E2E-08-M, TC-E2E-08-T, TC-E2E-08-D |
| FR-EXTRACT-003 | TC-EXTRACT-004, TC-E2E-08-M, TC-E2E-08-T, TC-E2E-08-D |
| FR-EXTRACT-004 | TC-EXTRACT-005, TC-EXTRACT-006, TC-EXTRACT-007, TC-EXTRACT-008, TC-E2E-08-M, TC-E2E-08-T, TC-E2E-08-D |
| FR-EXTRACT-005 | TC-EXTRACT-009, TC-EXTRACT-010 |
| FR-EXTRACT-006 | TC-EXTRACT-011 |
| FR-KG-001 | TC-KG-001, TC-KG-002 |
| FR-KG-002 | TC-KG-003 |
| FR-KG-003 | TC-KG-004, TC-KG-005 |
| FR-KG-004 | TC-KG-006, TC-KG-007, TC-E2E-07-M, TC-E2E-07-T, TC-E2E-07-D |
| FR-KG-005 | TC-KG-008, TC-KG-009, TC-E2E-07-M, TC-E2E-07-T, TC-E2E-07-D |
| FR-KG-006 | TC-KG-010, TC-KG-011, TC-E2E-07-M, TC-E2E-07-T, TC-E2E-07-D |
| FR-KG-007 | TC-KG-012 |
| FR-KG-008 | TC-KG-013 |
| FR-RESP-001 | TC-RESP-001, TC-E2E-09-D |
| FR-RESP-002 | TC-RESP-002, TC-E2E-09-D |
| FR-RESP-003 | TC-RESP-003, TC-E2E-09-T |
| FR-RESP-004 | TC-RESP-004, TC-E2E-09-M, TC-E2E-SMOKE-02 |
| FR-RESP-005 | TC-RESP-005, TC-E2E-09-M |
| FR-RESP-006 | TC-RESP-006, TC-E2E-09-M |
| FR-RESP-007 | TC-RESP-007, TC-E2E-09-M |
| FR-RESP-008 | TC-RESP-008, TC-E2E-09-M |
| FR-RESP-009 | TC-RESP-009, TC-E2E-09-M |
| FR-RESP-010 | TC-RESP-010, TC-E2E-09-M |
| FR-RESP-011 | TC-RESP-011, TC-E2E-09-M |
| FR-RESP-012 | TC-RESP-012, TC-E2E-09-M |
| FR-RESP-013 | TC-RESP-013(N/A 可选) |
| FR-HEALTH-001 | TC-HEALTH-001, TC-HEALTH-002, TC-HEALTH-003 |
| FR-HEALTH-002 | TC-HEALTH-004, TC-HEALTH-005, TC-E2E-03-M, TC-E2E-03-T, TC-E2E-03-D |
| FR-HEALTH-003 | TC-HEALTH-006, TC-KG-012 |
| FR-HEALTH-004 | TC-HEALTH-007, TC-EXTRACT-011 |
| FR-HEALTH-005 | TC-HEALTH-008, TC-CHAT-030 |
> 非功能要求(PRD §14,非 FR 编号)由 TC-NFR-001~005 覆盖:首屏性能(TC-NFR-001)、长任务反馈(TC-NFR-002)、凭据安全(TC-NFR-003)、零外网(TC-NFR-004)、浏览器兼容(TC-NFR-005)。
### 2.3 TC→FR 矩阵(每条 TC 列出其全部 FR,证明无孤儿)
| TC | FR |
|---|---|
| TC-SHELL-001 | FR-SHELL-001 |
| TC-SHELL-002 | FR-SHELL-001 |
| TC-SHELL-003 | FR-SHELL-002 |
| TC-SHELL-004 | FR-SHELL-002 |
| TC-SHELL-005 | FR-SHELL-002 |
| TC-SHELL-006 | FR-SHELL-003 |
| TC-SHELL-007 | FR-SHELL-003 |
| TC-SHELL-008 | FR-SHELL-004 |
| TC-SHELL-009 | FR-SHELL-004 |
| TC-SHELL-010 | FR-SHELL-005 |
| TC-SHELL-011 | FR-SHELL-006 |
| TC-SHELL-012 | FR-SHELL-006 |
| TC-SHELL-013 | FR-SHELL-007 |
| TC-SHELL-014 | FR-SHELL-007 |
| TC-SHELL-015 | FR-SHELL-007 |
| TC-THEME-001 | FR-THEME-001 |
| TC-THEME-002 | FR-THEME-001 |
| TC-THEME-003 | FR-THEME-002 |
| TC-THEME-004 | FR-THEME-002 |
| TC-THEME-005 | FR-THEME-003 |
| TC-THEME-006 | FR-THEME-004 |
| TC-THEME-007 | FR-THEME-005 |
| TC-THEME-008 | FR-THEME-005 |
| TC-THEME-009 | FR-THEME-006 |
| TC-THEME-010 | FR-THEME-006 |
| TC-SESSION-001 | FR-SESSION-001 |
| TC-SESSION-002 | FR-SESSION-001 |
| TC-SESSION-003 | FR-SESSION-001 |
| TC-SESSION-004 | FR-SESSION-002 |
| TC-SESSION-005 | FR-SESSION-003 |
| TC-SESSION-006 | FR-SESSION-003 |
| TC-SESSION-007 | FR-SESSION-004 |
| TC-SESSION-008 | FR-SESSION-004 |
| TC-SESSION-009 | FR-SESSION-005 |
| TC-SESSION-010 | FR-SESSION-006 |
| TC-SESSION-011 | FR-SESSION-006 |
| TC-SESSION-012 | FR-SESSION-007 |
| TC-SESSION-013 | FR-SESSION-007 |
| TC-SESSION-014 | FR-SESSION-007 |
| TC-SESSION-015 | FR-SESSION-007 |
| TC-SESSION-016 | FR-SESSION-008 |
| TC-SESSION-017 | FR-SESSION-008 |
| TC-SESSION-018 | FR-SESSION-009 |
| TC-CHAT-001 | FR-CHAT-001 |
| TC-CHAT-002 | FR-CHAT-001 |
| TC-CHAT-003 | FR-CHAT-002 |
| TC-CHAT-004 | FR-CHAT-003 |
| TC-CHAT-005 | FR-CHAT-003 |
| TC-CHAT-006 | FR-CHAT-004 |
| TC-CHAT-007 | FR-CHAT-004 |
| TC-CHAT-008 | FR-CHAT-014 |
| TC-CHAT-009 | FR-CHAT-014 |
| TC-CHAT-010 | FR-CHAT-014 |
| TC-CHAT-011 | FR-CHAT-015 |
| TC-CHAT-012 | FR-CHAT-005 |
| TC-CHAT-013 | FR-CHAT-006 |
| TC-CHAT-014 | FR-CHAT-006 |
| TC-CHAT-015 | FR-CHAT-006 |
| TC-CHAT-016 | FR-CHAT-006 |
| TC-CHAT-017 | FR-CHAT-007 |
| TC-CHAT-018 | FR-CHAT-007 |
| TC-CHAT-019 | FR-CHAT-007 |
| TC-CHAT-020 | FR-CHAT-007 |
| TC-CHAT-021 | FR-CHAT-011 |
| TC-CHAT-022 | FR-CHAT-011 |
| TC-CHAT-023 | FR-CHAT-008 |
| TC-CHAT-024 | FR-CHAT-008 |
| TC-CHAT-025 | FR-CHAT-008 |
| TC-CHAT-026 | FR-CHAT-008 |
| TC-CHAT-027 | FR-CHAT-008 |
| TC-CHAT-028 | FR-CHAT-008 |
| TC-CHAT-029 | FR-CHAT-008 |
| TC-CHAT-030 | FR-CHAT-008, FR-HEALTH-005 |
| TC-CHAT-031 | FR-CHAT-008 |
| TC-CHAT-032 | FR-CHAT-008 |
| TC-CHAT-033 | FR-CHAT-008 |
| TC-CHAT-034 | FR-CHAT-009 |
| TC-CHAT-035 | FR-CHAT-009 |
| TC-CHAT-036 | FR-CHAT-010 |
| TC-CHAT-037 | FR-CHAT-010 |
| TC-CHAT-038 | FR-CHAT-012 |
| TC-CHAT-039 | FR-CHAT-012 |
| TC-CHAT-040 | FR-CHAT-012 |
| TC-CHAT-041 | FR-CHAT-012 |
| TC-CHAT-042 | FR-CHAT-013 |
| TC-CHAT-043 | FR-CHAT-013 |
| TC-RETRIEVAL-001 | FR-RETRIEVAL-001 |
| TC-RETRIEVAL-002 | FR-RETRIEVAL-001 |
| TC-RETRIEVAL-003 | FR-RETRIEVAL-002 |
| TC-RETRIEVAL-004 | FR-RETRIEVAL-003 |
| TC-RETRIEVAL-005 | FR-RETRIEVAL-004 |
| TC-RETRIEVAL-006 | FR-RETRIEVAL-005 |
| TC-RETRIEVAL-007 | FR-RETRIEVAL-006 |
| TC-SOURCE-001 | FR-SOURCE-001 |
| TC-SOURCE-002 | FR-SOURCE-001 |
| TC-SOURCE-003 | FR-SOURCE-002 |
| TC-SOURCE-004 | FR-SOURCE-003 |
| TC-SOURCE-005 | FR-SOURCE-004 |
| TC-SOURCE-006 | FR-SOURCE-005 |
| TC-SOURCE-007 | FR-SOURCE-006 |
| TC-EXTRACT-001 | FR-EXTRACT-001 |
| TC-EXTRACT-002 | FR-EXTRACT-002 |
| TC-EXTRACT-003 | FR-EXTRACT-002 |
| TC-EXTRACT-004 | FR-EXTRACT-003 |
| TC-EXTRACT-005 | FR-EXTRACT-004 |
| TC-EXTRACT-006 | FR-EXTRACT-004 |
| TC-EXTRACT-007 | FR-EXTRACT-004 |
| TC-EXTRACT-008 | FR-EXTRACT-004 |
| TC-EXTRACT-009 | FR-EXTRACT-005 |
| TC-EXTRACT-010 | FR-EXTRACT-005 |
| TC-EXTRACT-011 | FR-EXTRACT-006, FR-HEALTH-004 |
| TC-KG-001 | FR-KG-001 |
| TC-KG-002 | FR-KG-001 |
| TC-KG-003 | FR-KG-002 |
| TC-KG-004 | FR-KG-003 |
| TC-KG-005 | FR-KG-003 |
| TC-KG-006 | FR-KG-004 |
| TC-KG-007 | FR-KG-004 |
| TC-KG-008 | FR-KG-005 |
| TC-KG-009 | FR-KG-005 |
| TC-KG-010 | FR-KG-006 |
| TC-KG-011 | FR-KG-006 |
| TC-KG-012 | FR-KG-007, FR-HEALTH-003 |
| TC-KG-013 | FR-KG-008 |
| TC-RESP-001 | FR-RESP-001 |
| TC-RESP-002 | FR-RESP-002 |
| TC-RESP-003 | FR-RESP-003 |
| TC-RESP-004 | FR-RESP-004 |
| TC-RESP-005 | FR-RESP-005 |
| TC-RESP-006 | FR-RESP-006 |
| TC-RESP-007 | FR-RESP-007 |
| TC-RESP-008 | FR-RESP-008 |
| TC-RESP-009 | FR-RESP-009 |
| TC-RESP-010 | FR-RESP-010 |
| TC-RESP-011 | FR-RESP-011 |
| TC-RESP-012 | FR-RESP-012 |
| TC-RESP-013 | FR-RESP-013(N/A 可选) |
| TC-HEALTH-001 | FR-HEALTH-001 |
| TC-HEALTH-002 | FR-HEALTH-001 |
| TC-HEALTH-003 | FR-HEALTH-001 |
| TC-HEALTH-004 | FR-HEALTH-002 |
| TC-HEALTH-005 | FR-HEALTH-002 |
| TC-HEALTH-006 | FR-HEALTH-003 |
| TC-HEALTH-007 | FR-HEALTH-004 |
| TC-HEALTH-008 | FR-HEALTH-005 |
| TC-NFR-001 | PRD §14 首屏可交互(非 FR) |
| TC-NFR-002 | PRD §14 长任务反馈(非 FR) |
| TC-NFR-003 | PRD §14 数据安全(非 FR) |
| TC-NFR-004 | PRD §14 离线容忍(非 FR) |
| TC-NFR-005 | PRD §14 浏览器支持(非 FR) |
| TC-E2E-01-M | FR-CHAT-008, FR-CHAT-013 |
| TC-E2E-01-T | FR-CHAT-008, FR-CHAT-013 |
| TC-E2E-01-D | FR-CHAT-008, FR-CHAT-013 |
| TC-E2E-02-M | FR-CHAT-006 |
| TC-E2E-02-T | FR-CHAT-006 |
| TC-E2E-02-D | FR-CHAT-006 |
| TC-E2E-03-M | FR-CHAT-012, FR-HEALTH-002 |
| TC-E2E-03-T | FR-CHAT-012, FR-HEALTH-002 |
| TC-E2E-03-D | FR-CHAT-012, FR-HEALTH-002 |
| TC-E2E-04-M | FR-SESSION-001, FR-SESSION-003, FR-SESSION-004, FR-SESSION-005, FR-SESSION-006, FR-SESSION-007 |
| TC-E2E-04-T | FR-SESSION-001, FR-SESSION-003, FR-SESSION-004, FR-SESSION-005, FR-SESSION-006, FR-SESSION-007 |
| TC-E2E-04-D | FR-SESSION-001, FR-SESSION-003, FR-SESSION-004, FR-SESSION-005, FR-SESSION-006, FR-SESSION-007 |
| TC-E2E-05-M | FR-CHAT-008, FR-CHAT-011 |
| TC-E2E-05-T | FR-CHAT-008, FR-CHAT-011 |
| TC-E2E-05-D | FR-CHAT-008, FR-CHAT-011 |
| TC-E2E-06-M | FR-THEME-002 |
| TC-E2E-06-T | FR-THEME-002 |
| TC-E2E-06-D | FR-THEME-002 |
| TC-E2E-07-M | FR-KG-004, FR-KG-005, FR-KG-006 |
| TC-E2E-07-T | FR-KG-004, FR-KG-005, FR-KG-006 |
| TC-E2E-07-D | FR-KG-004, FR-KG-005, FR-KG-006 |
| TC-E2E-08-M | FR-EXTRACT-001, FR-EXTRACT-002, FR-EXTRACT-003, FR-EXTRACT-004 |
| TC-E2E-08-T | FR-EXTRACT-001, FR-EXTRACT-002, FR-EXTRACT-003, FR-EXTRACT-004 |
| TC-E2E-08-D | FR-EXTRACT-001, FR-EXTRACT-002, FR-EXTRACT-003, FR-EXTRACT-004 |
| TC-E2E-09-M | FR-RESP-004, FR-RESP-005, FR-RESP-006, FR-RESP-007, FR-RESP-008, FR-RESP-009, FR-RESP-010, FR-RESP-011, FR-RESP-012 |
| TC-E2E-09-T | FR-RESP-003 |
| TC-E2E-09-D | FR-RESP-001, FR-RESP-002, FR-SHELL-001 |
| TC-E2E-SMOKE-01 | FR-SHELL-007 |
| TC-E2E-SMOKE-02 | FR-SHELL-001, FR-SHELL-003, FR-RESP-004 |
### 2.4 模块分布
| 模块 | TC 条数(含 E2E 拆分) |
|---|---|
| SHELL | 15 |
| THEME | 10 |
| SESSION | 18 |
| CHAT | 43 |
| RETRIEVAL | 7 |
| SOURCE | 7 |
| EXTRACT | 11 |
| KG | 13 |
| RESP | 13 |
| HEALTH | 8 |
| NFR(PRD §14) | 5 |
| E2E 主线/冒烟 | 29 |
| **合计** | **179** |
---
## 3. 执行说明
### 3.1 分层运行命令(TEST_PLAN §7)
```bash
# L1 后端单元(远端 plantai-bff conda 环境;A 组自测,T 复跑确认)
cd sdk && pytest tests -m unit -q
# L2 后端接口(respx mock 上游;用例见 L2 标注项)
cd sdk && pytest tests -m api -q
# L2s 上游 smoke(仅集成点 M2 与验收前手动各跑一次;远端本机执行)
bash tests/smoke_upstreams.sh
# L3+L4 前端(vitest;远端 ui/)
cd ui && npx vitest run
# L5 E2E(三档视口;dev server 由 playwright webServer 自动拉起或复用已启动的 5180)
cd ui && npx playwright test # playwright 未安装时:npx playwright@1.49.1 test
```
### 3.2 Mock 场景使用(ARCHITECTURE.md §6)
mock server:`python sdk/mock/mock_server.py`(127.0.0.1:8099),场景经查询参数或请求头 `X-Mock-Scenario` 切换。E2E 中由测试代码在请求头注入或 mock 路由拦截实现:
| scenario | 用途 | 使用用例示例 |
|---|---|---|
| `normal` | 主流程(SSE 回放 12 帧真实时序) | TC-CHAT-023~033、TC-E2E-01/02 |
| `empty` | 空结果(source_count=0、answer 为「未找到…」fallback) | TC-SOURCE-007、TC-KG-013、TC-CHAT-027(空态分支) |
| `slow` | 慢响应/长流(持续视觉反馈断言) | TC-CHAT-021、TC-CHAT-029、TC-NFR-002 |
| `error` | 上游故障(502 UPSTREAM_ERROR) | TC-CHAT-039、TC-E2E-03 |
| `degraded` | QA 不可用(503 UPSTREAM_DOWN) | TC-HEALTH-004/005、TC-EXTRACT-011、TC-KG-012、TC-E2E-03 |
注意:mock 的场景切换仅覆盖 QA 端点;extraction/kg 的 503 降级在 E2E 中用 Playwright route 拦截模拟。
### 3.3 真实上游注意事项(DISCOVERY.md)
1. **QA LLM 402 降级(最重要)**:上游 DeepSeek 余额不足,`degraded_execution=true`,answer 为 fallback 证据列表而非自然语言答案。**涉及自然语言答案内容的断言(TC-CHAT-027 等,标注「依赖充值」)在充值前执行时只验结构不断内容**:answer 字段存在、text 块渲染、fallback 文案可见即可。检索/证据/来源/图谱断言(sources、chains、graph 块)不受 402 影响,照常执行。
2. **耗时**:单次 search ≈92s、stream ≈37–38s(DISCOVERY.md §4/§6.8)。真实上游的 L5/L6 用例需把 expect 超时调到 ≥180s(search 模式)/≥120s(chat 模式);BFF 读超时 300s。
3. **上游只绑 127.0.0.1**:L2s 必须在远端本机跑;Mac 本地经 SSH 隧道跑(见脚本注释)。
4. **Neo4j 当选实例** direct-v1-full(bolt 18788 / HTTP 18575),schema canonical;`/api/kg/*` 依赖 BFF 的 Bolt 直连(上游 kg 路由已死,不探测)。
5. **抽取上游**:8000 正常;7900 为容器(jobs 空属正常,BFF 只在 8000 不可达时回落);新上传任务可能因 MinerU 路径缺失 failed——TC-EXTRACT-008 就是断言该错误文案路径。
### 3.4 L5 运行环境一次性准备(已验证)
- **Node 18(远端)**:`npx playwright@1.49.1 test` 首次运行自动下载 chromium 1148(≈150MB)。实测 CDN 可达(Mac 直连 2.9MB/s)。
- **`@playwright/test` 模块解析**:spec 文件位于 `tests/e2e/`,在 `ui/node_modules` 之外,Node 默认解析路径找不到 `@playwright/test`,会报 `ERR_MODULE_NOT_FOUND`。**已在 Mac 本地验证**(playwright 1.61.1 实测复现;1.49.1 CJS 变换同样回退到默认 ESM 解析,机制相同)。运行处须一次性执行(不污染任何 agent 归属文件——`node_modules` 不入库不同步):
```bash
# 远端,一次性
cd /home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new
ln -sfn ui/node_modules node_modules # 若目录已存在先确认其内容再覆盖
cd ui && npm install --save-dev @playwright/test@1.49.1 # 写入 package.json 需 PM 裁决,见 §5 未决问题 4
```
Mac 本地本次验证的等价做法(未改动 `ui/package.json`):安装到 `/tmp/pw-test-runner` 后 `ln -sfn /tmp/pw-test-runner/node_modules/@playwright/test ui/node_modules/@playwright/test`,再 `ln -sfn ui/node_modules <repo>/node_modules`,以 playwright 1.61.1(匹配本机已缓存 chromium-1228)跑通 6/6。
- **本地 Node 26 已知问题**:playwright 1.49.1 的 `module.register()` loader 在 Node 26 + 系统高负载下启动极慢/挂起;远端 Node 18 无此问题。本地验证用 playwright 1.61.1 替代。
- **本机验证结果(M0 冒烟)**:`6 passed`(mobile/tablet/desktop × 2 条冒烟)。冒烟断言对 B1 已交付的 AppShell 走真实分支(`.app-shell/.top-bar/.status-bar`,移动端 `.status-bar` 按 FR-RESP-004 断言隐藏),M0 占位期走占位回退分支。
---
## 4. E2E 骨架交付说明(本波)
| 文件 | 内容 |
|---|---|
| `ui/playwright.config.js` | 三项目 mobile(iPhone 14 390×844,触摸+UA)/tablet(iPad 768×1024)/desktop(1440×900);chromium;baseURL `http://127.0.0.1:5180`;webServer `npm run dev -- --strictPort`(已有 dev 复用);失败保留 trace/screenshot |
| `tests/e2e/smoke.spec.js` | 2 条冒烟(TC-E2E-SMOKE-01/02),三档视口各跑一次共 6 条结果。AppShell 断言带 M0 占位回退(B1 交付后自动走真实分支,无需改测试) |
| `tests/smoke_upstreams.sh` | L2s 冒烟:QA 7920 health/info、抽取 8000 health/jobs、7900 health、Neo4j(HTTP 18575 Cypher 只读查询)、mock 8099 health;PASS/FAIL 表 + 非零退出码;支持 `QA_URL/EXTRACT_URL/ALT_URL/MOCK_URL/NEO4J_HTTP/TIMEOUT` 环境变量覆盖 |
全量 L1–L5 执行从 M2 集成后开始(TEST_PLAN §5 轮次纪律);完整 E2E 用例(TC-E2E-01~09)按本文件在后续轮次落为 spec 文件。
## 5. 未决问题(提请 PM)
1. 若干 UI 类断言依赖 UI_SPEC 类名(如 `agent-dot-item`、`p-step`);若 B1 实现时类名有偏差,需按 UI_SPEC §5.3 对齐(T 不自行改用例契约)。
2. TC-EXTRACT-005/007(上传进度/超限)依赖 B2/B3 上传 UI 与 50MB 校验落点(前端或 BFF)——已按「前端拦截或 422」双路径写预期,无需改用例。
3. TC-KG 节点详情在 Neo4j 不可用时的属性来源为「消息内 graph 块已有属性」;graph 块节点若不含属性字段,该断言在实现时需以实际块结构微调步骤(预期语义不变)。
4. **L5 依赖安装需 PM 裁决**:`tests/e2e/` 的 spec 需要解析 `@playwright/test`,而它位于 `ui/node_modules` 之外。两个方案二选一:(a) 远端一次性 `npm install --save-dev @playwright/test@1.49.1`(写入 B1 归属的 `ui/package.json`,需 PM 批准);(b) 保持 `npx playwright@1.49.1` 并在远端建 `node_modules` 根符号链接 + `@playwright/test` 符号链接(不改 package.json,M2 前由 T/PM 在远端一次性执行)。本波按 (b) 在 Mac 本地验证通过(6/6 pass),建议远端集成点采用 (b)。
5. **task 验证命令差异**:任务书给的验证命令 `npx playwright test`(无版本)在本机无已安装 playwright 时会从 npm 拉最新版;远端 Node 18 + `npx playwright@1.49.1` 仍会拉 1.49.1 的 chromium 1148(≈150MB,CDN 实测可达)。已在本文件 §3.4 记录完整步骤。
## 6. 生信流程编排(FR-BIO-001~032)
> 本节由 T1 编制(阶段 0,2026-09-05)。需求唯一来源:PRD.md §16;组件规格:UI_SPEC.md §8;分层与门禁:TEST_PLAN.md §9-12;端点事实:实施计划 §六。意图分流词典唯一事实源:docs/team/cases_bioflow_intent.md(前后端同表双跑)。
> 编号 TC-BIO-<模块>-<序号>;E2E 视口后缀 M/T/D(390×844 / 768×1024 / 1440×900)。分层:L1 生信服务单元(pytest -m bioflow_unit)|L2 生信接口(pytest -m bioflow_api,mock LLM/vstore/docker)|L2s 生信冒烟(bash bioflow_kernel/tests/smoke_golden.sh,仅集成点手动)|L3 前端单元(vitest)|L4 前端组件(vitest + @vue/test-utils)|L5(Playwright 三档视口)。
> 可断言性:预期列均为可观察断言(HTTP 状态/请求体字段/存储值/元素存在/计算样式值/事件序列),无「检查是否正确」类断言。
> 模块缩写:INTENT 意图分流 | API 生信服务端点 | RUN runner 状态机 | KERN 内核执行与 manifest | SSE 事件流 | DB 三表迁移 | FLOW 上下游集成 | STORE 前端 store | PATH 路径卡 | FORM 参数表单卡 | FILE 文件引导卡 | PROG 进度卡 | ARCH 存档卡 | JOB 生信任务面板 | PANE 生信档案面板 | ACT UI 动作矩阵 | DEPLOY 三形态部署 | REG 回归 | GOLD 金标与发布 | E2E 端到端主线。
### 6.1 用例清单
#### 6.1.1 INTENT 意图分流(FR-BIO-001/FR-BIO-023/FR-BIO-026,词典唯一事实源 docs/team/cases_bioflow_intent.md)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-INTENT-001 | FR-BIO-001 | 命中「帮我跑水稻 SPL 家族鉴定」 | 无附件、无活动文档 | route("帮我跑水稻 SPL 家族鉴定") | 返回 bioflow(词典用例表第 1 条) | L3 | P0 |
| TC-BIO-INTENT-002 | FR-BIO-001 | 命中「跑一下拟南芥 MADS-box 家族分析」 | 无附件、无活动文档 | route("跑一下拟南芥 MADS-box 家族分析") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-003 | FR-BIO-001 | 命中「请帮我鉴定水稻 SPL 家族」 | 无附件 | route("请帮我鉴定水稻 SPL 家族") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-004 | FR-BIO-001 | 命中「识别玉米 bZIP 家族成员」 | 无附件 | route("识别玉米 bZIP 家族成员") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-005 | FR-BIO-001 | 命中「帮我研究一下水稻 SPL 基因家族」 | 无附件 | route("帮我研究一下水稻 SPL 基因家族") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-006 | FR-BIO-001 | 命中「分析小麦 WRKY 转录因子家族」 | 无附件 | route("分析小麦 WRKY 转录因子家族") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-007 | FR-BIO-001 | 命中「做个大豆 NAC 家族分析」 | 无附件 | route("做个大豆 NAC 家族分析") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-008 | FR-BIO-001 | 命中「跑 SPL 家族」 | 无附件 | route("跑 SPL 家族") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-009 | FR-BIO-001 | 命中「水稻 SPL 家族,帮我跑」 | 无附件 | route("水稻 SPL 家族,帮我跑") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-010 | FR-BIO-001 | 命中「基因家族鉴定:水稻 SPL」 | 无附件 | route("基因家族鉴定:水稻 SPL") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-011 | FR-BIO-001 | 漏判安全:知识问答 | 无附件 | route("什么是基因家族?") | 返回 qa | L3 | P0 |
| TC-BIO-INTENT-012 | FR-BIO-001 | 漏判安全:光有动词 | 无附件 | route("帮我跑一下") | 返回 qa | L3 | P0 |
| TC-BIO-INTENT-013 | FR-BIO-001 | 漏判安全:光有家族名 | 无附件 | route("SPL 家族") | 返回 qa | L3 | P0 |
| TC-BIO-INTENT-014 | FR-BIO-001 | 漏判安全:无动词无家族 | 无附件 | route("今天天气不错") | 返回 qa | L3 | P1 |
| TC-BIO-INTENT-015 | FR-BIO-001 | 漏判安全:问方法 | 无附件 | route("跑 SPL 家族鉴定需要准备什么输入?") | 返回 qa | L3 | P0 |
| TC-BIO-INTENT-016 | FR-BIO-001 | 漏判安全:非生信对象 | 无附件 | route("帮我跑一个数据分析") | 返回 qa | L3 | P1 |
| TC-BIO-INTENT-017 | FR-BIO-001 | 漏判安全:闲聊 | 无附件 | route("你好呀") | 返回 qa | L3 | P1 |
| TC-BIO-INTENT-018 | FR-BIO-001 | 漏判安全:空字符串 | 无附件 | route("") | 返回 qa | L3 | P1 |
| TC-BIO-INTENT-019 | FR-BIO-001 | 漏判安全:纯空白 | 无附件 | route(" ") | 返回 qa | L3 | P1 |
| TC-BIO-INTENT-020 | FR-BIO-001 | 漏判安全:乱码 | 无附件 | route("⚡☂☄ hmm") | 返回 qa(非 bioflow) | L3 | P2 |
| TC-BIO-INTENT-021 | FR-BIO-001 | 漏判安全:未在词典的家族名 | 无附件 | route("帮我跑香蕉 XYK 家族鉴定") | 返回 qa(XYK 不在家族词典) | L3 | P1 |
| TC-BIO-INTENT-022 | FR-BIO-001 | 边界:大小写家族名 | 无附件 | route("跑水稻 spl 家族鉴定") | 返回 bioflow(家族名大小写不敏感) | L3 | P1 |
| TC-BIO-INTENT-023 | FR-BIO-001 | 边界:英文整句 | 无附件 | route("Please run rice SPL family identification") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-024 | FR-BIO-001 | 边界:标点夹杂 | 无附件 | route("帮我跑(水稻 SPL 家族)鉴定!") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-025 | FR-BIO-001 | 边界:超长文本(>200 字) | 无附件 | route(200 字长文含「跑水稻 SPL 家族鉴定」在末尾) | 返回 bioflow | L3 | P2 |
| TC-BIO-INTENT-026 | FR-BIO-001 | 边界:家族名跨词干扰 | 无附件 | route("这个 SPL 会议帮我跑一下流程") | 返回 qa(SPL 后无家族/分析对象词) | L3 | P2 |
| TC-BIO-INTENT-027 | FR-BIO-001 | 附件存在不改判定 | has_attachments=true | route("帮我跑水稻 SPL 家族鉴定") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-028 | FR-BIO-001 | 活动文档存在不改判定 | has_active_artifact=true | route("帮我跑水稻 SPL 家族鉴定") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-029 | FR-BIO-001 | docgen 优先:写报告 | 无附件、无活动文档 | route("帮我生成一份水稻 SPL 家族分析报告") | 返回 docgen(既有 docgen 路由在 bioflow 之前判定) | L3 | P0 |
| TC-BIO-INTENT-030 | FR-BIO-001 | docgen 优先:撰写论文 | 无附件 | route("帮我写一篇水稻基因家族研究论文") | 返回 docgen | L3 | P1 |
| TC-BIO-INTENT-031 | FR-BIO-001 | export 优先 | has_active_artifact=true | route("导出成 PDF") | 返回 export | L3 | P1 |
| TC-BIO-INTENT-032 | FR-BIO-001 | edit 优先:文档打开时改文字 | has_active_artifact=true | route("把这句话改成红色") | 返回 edit | L3 | P1 |
| TC-BIO-INTENT-033 | FR-BIO-019 | 图表调整走 bioflow:文档打开时 | has_active_artifact=true | route("xxx 图表颜色换成红色") | 返回 bioflow(图表类词命中生信,不进 edit) | L3 | P0 |
| TC-BIO-INTENT-034 | FR-BIO-023 | 存档复用命中:标准句式 | 无附件 | route("用 XXX 存档任务的方法帮我跑水稻 SPL 家族鉴定") | 返回 bioflow 且解析出复用意图(方法名=XXX) | L3 | P0 |
| TC-BIO-INTENT-035 | FR-BIO-023 | 存档复用命中:根据句式 | 无附件 | route("根据 XXX 存档任务的方法帮我跑一下玉米 bZIP") | 返回 bioflow 且复用意图成立 | L3 | P1 |
| TC-BIO-INTENT-036 | FR-BIO-023 | 存档复用命中:参考句式 | 无附件 | route("参考 XXX 存档的方法再跑一个水稻 SPL") | 返回 bioflow 且复用意图成立 | L3 | P1 |
| TC-BIO-INTENT-037 | FR-BIO-023 | 存档复用命中:按句式中文括号 | 无附件 | route("用《XXX》存档任务的方法帮我跑小麦 WRKY 家族") | 返回 bioflow 且方法名=XXX | L3 | P1 |
| TC-BIO-INTENT-038 | FR-BIO-023 | 存档复用边界:只有复用词无任务词 | 无附件 | route("用 XXX 存档任务的方法") | 返回 qa(无「帮我跑 xxxx」目标) | L3 | P1 |
| TC-BIO-INTENT-039 | FR-BIO-023 | 存档复用边界:无家族对象 | 无附件 | route("用 XXX 存档任务的方法帮我跑 yyy") | 返回 qa(yyy 无家族名匹配,漏判安全) | L3 | P1 |
| TC-BIO-INTENT-040 | FR-BIO-001 | 标点与空白容错 | 无附件 | route("帮我跑 水稻 SPL 家族 鉴定") | 返回 bioflow | L3 | P2 |
| TC-BIO-INTENT-041 | FR-BIO-001 | 命中 RNA-seq | 无附件 | route("帮我跑水稻叶片 RNA-seq 差异表达分析") | 返回 bioflow | L3 | P0 |
| TC-BIO-INTENT-042 | FR-BIO-001 | 命中 WGS | 无附件 | route("帮我做水稻全基因组变异检测") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-043 | FR-BIO-001 | 命中 GWAS | 无附件 | route("帮我跑水稻产量性状 GWAS 关联分析") | 返回 bioflow | L3 | P1 |
| TC-BIO-INTENT-044 | FR-BIO-001 | 命中交互式补充:追问对象 | 会话上文为「帮我跑水稻 SPL 家族鉴定」已开任务 | route("换玉米,重跑") | 返回 bioflow 且目标对象=玉米 | L3 | P2 |
| TC-BIO-INTENT-045 | FR-BIO-026 | 流程咨询在生信流内 | 会话已有生信任务 | route("identify 需要什么输入") | 返回 bioflow 内 flow_qa 路径(不新建任务) | L3 | P1 |
| TC-BIO-INTENT-046 | FR-BIO-001 | 命中句不打乱 QA 流 | 无生信上下文 | 先 route("什么是 SPL 家族") 再 route("帮我跑水稻 SPL 家族鉴定") | 第 1 条=qa、第 2 条=bioflow,两者互不影响 | L3 | P2 |
| TC-BIO-INTENT-047 | FR-BIO-001 | 词典同表后端一致性 | 后端 bioflow_service 已部署 | 后端对词典用例表 40+ 条输入逐一分流 | 后端判定结果与词典期望逐条一致(同表双跑) | L2 | P0 |
#### 6.1.2 API 生信服务端点(实施计划 §六 20 端点;mock LLM/vstore/docker)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-API-001 | FR-BIO-001 | chat/stream 入口建立 SSE | mock LLM/vstore | POST /api/bioflow/chat/stream {"session_id":"s1","message":"帮我跑水稻 SPL 家族鉴定"} 流式读首个事件 | 响应 200;Content-Type=text/event-stream;首个事件类型=job_created(或 plan_ready),data 为 JSON | L2 | P0 |
| TC-BIO-API-002 | FR-BIO-002 | 候选路径随 plan_ready 下发 | mock LLM 返回 3 条候选路径 | 读流至 plan_ready 事件 | plan_ready.data.candidates 为数组,length 在 2~3;每条含 stages[](非空)与 purpose(非空字符串) | L2 | P0 |
| TC-BIO-API-003 | FR-BIO-003 | 伪造阶段被拒 | mock LLM 候选含未知阶段「fake_stage_xyz」 | 读流至第 1 个 plan/error 事件 | 事件 data 含 code=UNKNOWN_STAGE 且 fake_stage_xyz 被点名;该候选不进入候选集 | L2 | P0 |
| TC-BIO-API-004 | FR-BIO-003 | 前置阶段自动补全 | 候选链缺 identify 前置 | 读流至 plan_ready | 事件 data.candidates[*].stages 已含前置;data 或后续事件文本含「已自动补全」明示字段 auto_filled[]=前置阶段名 | L2 | P0 |
| TC-BIO-API-005 | FR-BIO-001 | 非生信消息不建任务 | mock LLM 分流 | POST 消息「什么是基因家族」读流 | 响应 200;事件含 message_done 且不含 job_created;data 不含 job_id | L2 | P0 |
| TC-BIO-API-006 | FR-BIO-001 | 空 message 422 | 无 | POST {"session_id":"s1","message":""} | 422;detail 含 message 字段错误 | L2 | P1 |
| TC-BIO-API-007 | FR-BIO-001 | 缺 message 字段 422 | 无 | POST {"session_id":"s1"} | 422;detail 含 message | L2 | P1 |
| TC-BIO-API-008 | FR-BIO-001 | 缺 session_id 422 | 无 | POST {"message":"帮我跑水稻 SPL 家族鉴定"} | 422;detail 含 session_id | L2 | P1 |
| TC-BIO-API-009 | FR-BIO-001 | LLM 超时降级 | mock LLM 延迟超过上限 | 读流至第 1 个事件 | 事件 data 含 code=PLAN_LLM_TIMEOUT 的降级提示;SSE 正常关闭 | L2 | P1 |
| TC-BIO-API-010 | FR-BIO-001 | vstore 不可用降级 | mock vstore 返回 500 | 读流至 plan_ready | plan_ready 正常返回(LLM 直接候选);data.source 标记=llm_only;无 5xx 中断 | L2 | P1 |
| TC-BIO-API-011 | FR-BIO-023 | 存档复用句式接口路径 | 归档「XXX」存在且含参数 | POST message「用 XXX 存档任务的方法帮我跑玉米 bZIP」读流至 job_created | job_created.data.reused_archive=XXX;bio_jobs 行参数=存档参数 | L2 | P0 |
| TC-BIO-API-012 | FR-BIO-026 | 流程咨询接口路径 | 任务已存在 | POST message「identify 需要什么输入」读流 | 事件含 message_done;data.citations[] 含来源文件+章节;不产生新 job_created | L2 | P0 |
| TC-BIO-API-013 | FR-BIO-014 | 断流时任务不回滚 | mock docker 慢 | 流中途关闭客户端 | 任务在 DB 仍 in-flight;重连 events 接口可回放 | L2 | P1 |
| TC-BIO-API-014 | FR-BIO-001 | 客户端断开清理 | 任务尚未创建 | 收到首个字节后立即断开 | 服务端无未捕获异常;资源释放(无连接泄漏,服务存活) | L2 | P2 |
| TC-BIO-API-015 | FR-BIO-001 | 超长消息拒绝 | 无 | POST message=100001 字符 | 422(max_length 超限)或 400;不触发 LLM 调用 | L2 | P1 |
| TC-BIO-API-016 | FR-BIO-031 | 并发 chat 上限 | 已有 3 个 in-flight 任务 | 再发起第 4 个任务型消息 | 第 4 个任务不立即执行;事件 data 含 queued=true 或状态=queued | L2 | P0 |
| TC-BIO-API-017 | FR-BIO-014 | 断线重连回放快照 | 任务含 3 阶段(1 done 1 running 1 waiting) | GET /api/bioflow/jobs/{id}/events 首帧 | 首帧 data 为任务快照:stages 数组=3、每阶段含 status;无 stage_* 事件丢失 | L2 | P0 |
| TC-BIO-API-018 | FR-BIO-001 | 事件包含 plan_ready 后必有确认点 | 候选路径选定 | 读事件序列 | 序列中出现 stage_await_confirm(或 plan_ready);事件顺序由 seq 严格递增 | L2 | P1 |
| TC-BIO-API-019 | FR-BIO-001 | chat/stream 400 请求体非 JSON | 无 | POST body="not-json" Content-Type: application/json | 400 或 422 | L2 | P2 |
| TC-BIO-API-020 | FR-BIO-001 | LLM 完全不可用 | mock LLM 连接拒绝 | 读流至第 1 个事件 | 事件 data 含 code=PLAN_UNAVAILABLE;SSE 关闭;无 job 落库 | L2 | P1 |
| TC-BIO-API-021 | FR-BIO-002 | catalog 返回 73 阶段 | 服务正常 | GET /api/bioflow/catalog | 200;data.stages 数组 length=73;每项含 name/description/params/inputs/outputs | L2 | P0 |
| TC-BIO-API-022 | FR-BIO-002 | catalog 基因家族链 18 阶段 | 无 | GET /api/bioflow/catalog?chain=gene_family | 200;返回 18 项;name 集合与 stage_image_map 的 gf 链一致 | L2 | P0 |
| TC-BIO-API-023 | FR-BIO-002 | catalog 参数 schema | 无 | GET /api/bioflow/catalog?stage=identify | 返回 identify 项;params[] 每项含 name/type/default/source/help;inputs 含 fasta/hmm 类 | L2 | P0 |
| TC-BIO-API-024 | FR-BIO-002 | catalog 未知阶段 404 | 无 | GET /api/bioflow/catalog?stage=nope | 404 信封 code=NOT_FOUND | L2 | P1 |
| TC-BIO-API-025 | FR-BIO-002 | catalog 镜像映射字段 | 无 | GET /api/bioflow/catalog?stage=identify | 该项 image 字段=bioflow-gf(与 stage_image_map.json 一致) | L2 | P1 |
| TC-BIO-API-026 | FR-BIO-002 | catalog 缓存无效时重载 | 修改 catalog 源后 | GET /api/bioflow/catalog | 返回新数据(无服务重启);ETag 或 Last-Modified 变化 | L2 | P2 |
| TC-BIO-API-027 | FR-BIO-004 | POST jobs 创建任务 | 候选链已选定 | POST /api/bioflow/jobs {"session_id":"s1","title":"SPL 鉴定","stages":["identify","align","phylogeny"],"params":{}} | 201;body 含 id/uuid、title、status=created、stages 数组 3 项(status=waiting) | L2 | P0 |
| TC-BIO-API-028 | FR-BIO-004 | POST jobs 缺 stages 422 | 无 | POST {"session_id":"s1","title":"t"} | 422;detail 含 stages | L2 | P1 |
| TC-BIO-API-029 | FR-BIO-023 | POST jobs 复用归档 | 归档 a1 含阶段链+参数 | POST {"session_id":"s1","archive_id":"a1"} | 201;body.stages=归档阶段链;params=归档参数;bio_archives 行 reused_count+1 | L2 | P0 |
| TC-BIO-API-030 | FR-BIO-004 | POST jobs 未知 stage 拒绝 | 无 | POST {"stages":["ghost_stage"]} | 422/400;detail 点名 ghost_stage 不在 catalog | L2 | P1 |
| TC-BIO-API-031 | FR-BIO-004 | POST jobs 缺 session_id 422 | 无 | POST {"title":"t","stages":["identify"]} | 422;detail 含 session_id | L2 | P1 |
| TC-BIO-API-032 | FR-BIO-024 | GET jobs 列表 | 库中 3 个任务 | GET /api/bioflow/jobs | 200;data.items length=3;按 created_at 倒序;每项含 id/title/status/progress | L2 | P0 |
| TC-BIO-API-033 | FR-BIO-024 | GET jobs 分页 | 25 个任务 | GET /api/bioflow/jobs?page=2&page_size=10 | 200;items length=10;total=25 | L2 | P1 |
| TC-BIO-API-034 | FR-BIO-024 | GET job 详情 | 任务含 3 阶段 | GET /api/bioflow/jobs/{id} | 200;body.stages length=3 且各含 stage/status/params;progress 为数字 0-100 | L2 | P0 |
| TC-BIO-API-035 | FR-BIO-024 | GET job 404 | 无 | GET /api/bioflow/jobs/not-exist | 404 信封 code=NOT_FOUND | L2 | P1 |
| TC-BIO-API-036 | FR-BIO-024 | 任务阶段子资源 | 任务 j1 | GET /api/bioflow/jobs/{j1}/stages | 200;数组与任务阶段一致,含每阶段开始/结束时间 | L2 | P1 |
| TC-BIO-API-037 | FR-BIO-024 | DELETE job | 任务 j1 | DELETE /api/bioflow/jobs/{j1} | 204;GET 后 404;bio_stages 级联删除 | L2 | P1 |
| TC-BIO-API-038 | FR-BIO-024 | DELETE 进行中任务 | 任务 running | DELETE /api/bioflow/jobs/{id} | 409 信封 code=JOB_RUNNING(拒绝) | L2 | P1 |
| TC-BIO-API-039 | FR-BIO-006 | POST files 上传 | 任务 j1 起始阶段 await_files | POST /api/bioflow/jobs/{j1}/files multipart file=test.fa | 200;body 含 file_id/name/size=测试文件字节数/path 以 /job/{j1}/input/ 开头 | L2 | P0 |
| TC-BIO-API-040 | FR-BIO-006 | 上传写入任务目录 | 同上 | 上传后读服务器文件系统 | 文件存在于任务 input 目录;内容字节与上传一致 | L2 | P0 |
| TC-BIO-API-041 | FR-BIO-006 | 大文件流式上传 | 456MB fixture | 上传并统计内存峰值 | 200;服务端内存峰值 < 200MB(流式不整读) | L2 | P0 |
| TC-BIO-API-042 | FR-BIO-007 | 路径登记合法 | 任务 j1 | POST /api/bioflow/jobs/{j1}/files {"server_path":"/home/xzq/5090/teamWorkspace/zh/bioflow-data/examples/SPL.fa"} | 200;body 含登记记录 path;GET files 列表可见;无文件复制(path 指向原位) | L2 | P0 |
| TC-BIO-API-043 | FR-BIO-007 | 路径登记不存在文件 | 无 | POST files {"server_path":"/nonexistent/x.fa"} | 400 信封 code=PATH_NOT_EXIST;无登记记录 | L2 | P0 |
| TC-BIO-API-044 | FR-BIO-007 | 路径登记目录而非文件 | 无 | POST files {"server_path":"/tmp"} | 400 信封 code=NOT_A_FILE | L2 | P1 |
| TC-BIO-API-045 | FR-BIO-007 | 路径登记非白名单根 | 无 | POST files {"server_path":"/etc/passwd"} | 403 信封 code=PATH_NOT_ALLOWED(限 BIOFLOW_DATA_ROOT/任务目录内) | L2 | P0 |
| TC-BIO-API-046 | FR-BIO-006 | 上传类型限制 | 任务 j1 | 上传 file.exe(扩展名不在白名单) | 422;detail 指明扩展名不允 | L2 | P1 |
| TC-BIO-API-047 | FR-BIO-006 | 上传大小上限 | 任务 j1 | 上传超过上限的 fixture | 413;detail 含 max_size 与实到字节数 | L2 | P1 |
| TC-BIO-API-048 | FR-BIO-006 | GET files 列表 | 任务 j1 已登记 2 文件 | GET /api/bioflow/jobs/{j1}/files | 200;items length=2;每项含 name/path/size/registered_at;含服务器路径登记项 source=server_path | L2 | P0 |
| TC-BIO-API-049 | FR-BIO-006 | 上传完成事件 | 任务 j1 await_files | 上传满足阶段输入 | 后续事件流出现 stage_started(该阶段不再 await_files);bio_stages 状态=waiting_confirm 或 running | L2 | P0 |
| TC-BIO-API-050 | FR-BIO-006 | 上传失败不登记 | mock 磁盘写失败 | 上传 | 500 信封;files 列表不含该文件 | L2 | P2 |
| TC-BIO-API-051 | FR-BIO-006 | 同文件重复上传 | 已上传 a.fa | 再次上传同名 a.fa | 200;新 file_id;input 目录 a.fa 被覆盖(或 409 按实现断言其一,二选一固定) | L2 | P1 |
| TC-BIO-API-052 | FR-BIO-006 | 多文件并发上传 | 任务 j1 | 并发 3 个 multipart 上传 | 3 个均 200;files 列表 length=3;无文件交错损坏(各 size 与源一致) | L2 | P1 |
| TC-BIO-API-053 | FR-BIO-006 | 中文文件名 | 任务 j1 | 上传「水稻基因组.fa」 | 200;files 列表 name=水稻基因组.fa 且 URL 编码取回正确 | L2 | P2 |
| TC-BIO-API-054 | FR-BIO-006 | 空文件上传 | 任务 j1 | 上传 0 字节文件 | 200 且 size=0(或 422 按实现断言其一,二选一固定) | L2 | P2 |
| TC-BIO-API-055 | FR-BIO-006 | GET files 单文件内容 | 已上传 a.fa | GET /api/bioflow/jobs/{j1}/files/{file_id}/content | 200;Content-Type 与文件一致;body 字节与源一致 | L2 | P1 |
| TC-BIO-API-056 | FR-BIO-008 | confirm 发起执行 | 阶段 identify 状态 waiting_confirm | POST /api/bioflow/jobs/{j1}/stages/identify/confirm {"params":{"cpu":8}} | 200;body.status=running;bio_stages 参数已存 cpu=8 | L2 | P0 |
| TC-BIO-API-057 | FR-BIO-009 | confirm 参数覆盖 | 默认参数 cpu=4 | POST confirm {"params":{"cpu":16}} | 后续 mock docker 命令含 --cpu 16(非 4);stage 执行用新值 | L2 | P0 |
| TC-BIO-API-058 | FR-BIO-008 | confirm 拒绝非 schema 参数 | 无 | POST confirm {"params":{"magic":"x"}} | 422;detail 含 magic 未知参数 | L2 | P1 |
| TC-BIO-API-059 | FR-BIO-009 | 重复 confirm 幂等 | 阶段已 running | 再次 POST confirm | 409 信封 code=STAGE_NOT_CONFIRMABLE | L2 | P1 |
| TC-BIO-API-060 | FR-BIO-009 | confirm 未知阶段 | 无 | POST /stages/nope/confirm | 404 信封 | L2 | P1 |
| TC-BIO-API-061 | FR-BIO-009 | confirm 非等待态 | 阶段 done | POST confirm | 409 信封 code=INVALID_STAGE_TRANSITION | L2 | P1 |
| TC-BIO-API-062 | FR-BIO-012 | rerun 失败阶段 | 阶段 failed | POST /api/bioflow/jobs/{j1}/stages/{st}/rerun | 200;状态=running 或 waiting_confirm(rerun_with_params);bio_stages 新增 attempt 记录 | L2 | P0 |
| TC-BIO-API-063 | FR-BIO-012 | rerun 带新参数 | 阶段 failed | POST rerun {"params":{"cpu":2}} | mock docker 命令含 --cpu 2;成功后状态=done | L2 | P0 |
| TC-BIO-API-064 | FR-BIO-012 | rerun 非 failed 409 | 阶段 done | POST rerun | 409 信封 code=STAGE_NOT_FAILED | L2 | P1 |
| TC-BIO-API-065 | FR-BIO-012 | skip 失败阶段 | 阶段 failed | POST /api/bioflow/jobs/{j1}/stages/{st}/skip | 200;状态=skipped;事件流出现 stage_skipped | L2 | P0 |
| TC-BIO-API-066 | FR-BIO-012 | skip 非 failed 409 | 阶段 running | POST skip | 409 信封 | L2 | P1 |
| TC-BIO-API-067 | FR-BIO-010 | pause 生效 | 任务 2/5 阶段 running | POST /api/bioflow/jobs/{j1}/pause | 200;状态=paused;事件 job_paused;当前阶段不启新 docker | L2 | P0 |
| TC-BIO-API-068 | FR-BIO-010 | pause 已完成任务 409 | 任务 done | POST pause | 409 信封 code=JOB_NOT_RUNNING | L2 | P1 |
| TC-BIO-API-069 | FR-BIO-010 | resume 继续 | 任务 paused | POST /api/bioflow/jobs/{j1}/resume | 200;状态=running;等待确认的阶段回到 waiting_confirm(不跳过确认) | L2 | P0 |
| TC-BIO-API-070 | FR-BIO-010 | resume 非 paused 409 | 任务 created | POST resume | 409 信封 | L2 | P1 |
| TC-BIO-API-071 | FR-BIO-011 | manifest+日志尾 | 阶段 identify done | GET /api/bioflow/jobs/{j1}/stages/identify/manifest | 200;body 含 manifest 对象与 log_tail 字符串;log_tail 行数≤80 | L2 | P0 |
| TC-BIO-API-072 | FR-BIO-011 | manifest 日志恰好 80 行边界 | 日志 80 行 fixture | GET manifest | log_tail 行数=80 且含第 1 行与第 80 行 | L2 | P1 |
| TC-BIO-API-073 | FR-BIO-011 | 日志超 80 行截尾 | 日志 200 行 fixture | GET manifest | log_tail 行数=80 且为最后 80 行(第 1 行=原第 121 行) | L2 | P1 |
| TC-BIO-API-074 | FR-BIO-011 | manifest 404 | 未执行阶段 | GET .../stages/nope/manifest | 404 信封 | L2 | P1 |
| TC-BIO-API-075 | FR-BIO-011 | manifest 判成败字段 | 阶段失败 fixture | GET manifest | body.manifest.status 存在且为 failed;log_tail 含报错行 | L2 | P0 |
| TC-BIO-API-076 | FR-BIO-011 | 日志尾含 ANSI 色码清洗 | 日志含 \x1b[31m | GET manifest | log_tail 不含原始转义序列(已清洗或原样两态断言其一) | L2 | P2 |
| TC-BIO-API-077 | FR-BIO-014 | events SSE 全事件序列 | mock 任务跑通 3 阶段 | GET /api/bioflow/jobs/{j1}/events 收集全部事件 | 事件序列=job_created→plan_ready→stage_started→stage_log(≥1)→stage_await_confirm→stage_done(×3 阶段)→job_done;seq 严格递增 | L2 | P0 |
| TC-BIO-API-078 | FR-BIO-014 | events 断线重连回放 | 任务 3 阶段(1 done 1 running 1 waiting) | GET events | 首帧快照后按事件序补齐历史:stage_done(第 1 阶段)必回放;不含重复 stage_done | L2 | P0 |
| TC-BIO-API-079 | FR-BIO-014 | events 单阶段过滤 | 任务多阶段 | GET /api/bioflow/jobs/{j1}/events?stage=identify | 仅 identify 的事件;不含其他阶段事件 | L2 | P1 |
| TC-BIO-API-080 | FR-BIO-014 | events 心跳保活 | 任务运行中无新事件 | 等待 2×心跳间隔 | 收到至少 1 条 :keepalive 注释行;连接未断 | L2 | P1 |
| TC-BIO-API-081 | FR-BIO-014 | events job_done 后关闭 | 任务 done | 读流至 job_done | 收到 job_done 后服务端正常关闭连接 | L2 | P1 |
| TC-BIO-API-082 | FR-BIO-014 | events 客户端断开清理 | 任务运行中 | 断开 events 连接 | 订阅者计数回落;服务无泄漏(再连正常) | L2 | P2 |
| TC-BIO-API-083 | FR-BIO-014 | events 事件 id 递增 | 任务运行中 | 读全部事件 | 每个事件 data.seq 比前一事件 +1,无重复 seq | L2 | P1 |
| TC-BIO-API-084 | FR-BIO-019 | revise 重跑绘图阶段 | 报告任务含绘图阶段 plot_heatmap | POST /api/bioflow/report/{job_id}/revise {"target":"图1 颜色","instruction":"红色","params":{"color":"red"}} | 200;body 含 rerun_stage=plot_heatmap;该阶段 attempt+1 且状态=running | L2 | P0 |
| TC-BIO-API-085 | FR-BIO-019 | revise 后新图回填 | 绘图阶段重跑完成 | 轮询 job 状态至 done;GET report | 报告 HTML 中对应图 fig://id 的 base64 内容变化(与 revise 前不同) | L2 | P0 |
| TC-BIO-API-086 | FR-BIO-019 | revise 纯文字指令走 docgen | 报告已登记 | POST revise {"instruction":"首段字号加大"}(无图表目标) | 不触发绘图阶段重跑;调用报告编辑链路(docgen);报告文字更新 | L2 | P1 |
| TC-BIO-API-087 | FR-BIO-020 | 存档 POST | 任务 done 含报告 | POST /api/bioflow/archives {"job_id":"j1","name":"SPL 水稻鉴定","description":"...","include_intermediate":true} | 201;body 含 id/name/disk_path/size_bytes>0;磁盘路径目录存在且含 report.html | L2 | P0 |
| TC-BIO-API-088 | FR-BIO-020 | 存档名称缺失 422 | 任务 done | POST {"job_id":"j1"} | 422;detail 含 name | L2 | P1 |
| TC-BIO-API-089 | FR-BIO-020 | 放弃存档不调接口 | 前端已出提示 | 点击放弃后观察网络 | 无 POST /api/bioflow/archives 请求 | L4 | P1 |
| TC-BIO-API-090 | FR-BIO-022 | GET archives 列表 | 3 个归档 | GET /api/bioflow/archives | 200;items length=3 按 created_at 倒序;每项含 name/description/size/disk_path | L2 | P0 |
| TC-BIO-API-091 | FR-BIO-022 | GET archive 详情 | 归档 a1 | GET /api/bioflow/archives/{a1} | 200;含 stages 链、params、report_artifact、文件清单 | L2 | P0 |
| TC-BIO-API-092 | FR-BIO-022 | DELETE archive | 归档 a1 | DELETE /api/bioflow/archives/{a1} | 204;磁盘目录删除;GET 后 404 | L2 | P1 |
| TC-BIO-API-093 | FR-BIO-022 | DELETE archive 404 | 无 | DELETE /api/bioflow/archives/nope | 404 信封 | L2 | P1 |
| TC-BIO-API-094 | FR-BIO-023 | archive run 复用发起 | 归档 a1 | POST /api/bioflow/archives/{a1}/run {"session_id":"s1","target":"玉米 bZIP"} | 201;新任务 job_id 返回;stages=归档链;params 预填归档值 | L2 | P0 |
| TC-BIO-API-095 | FR-BIO-023 | 名称精确匹配优先 | 归档「SPL」与「SPL2」 | POST archives/run {"name":"SPL"} | 命中 SPL(精确优先) | L2 | P1 |
| TC-BIO-API-096 | FR-BIO-023 | 名称模糊候选 | 归档「水稻SPL」 | POST archives/run {"name":"SPL 水稻"} | 返回候选列表(≥1)且不含无关归档 | L2 | P1 |
| TC-BIO-API-097 | FR-BIO-023 | 复用无匹配 404 | 无 | POST archives/run {"name":"不存在"} | 404 信封 code=ARCHIVE_NOT_FOUND | L2 | P1 |
| TC-BIO-API-098 | FR-BIO-020 | 重名归档 409 | 已有归档名「X」 | POST archives {"name":"X"} | 409 信封(或 201 自动去重两态断言其一) | L2 | P2 |
| TC-BIO-API-099 | FR-BIO-025 | health 探活 | 服务运行 | GET /api/bioflow/health | 200;body 含 status=ok 与 db 连通状态字段 | L2 | P0 |
| TC-BIO-API-100 | FR-BIO-028 | BFF 反代开关开启态 | BIOFLOW_ENABLED=true | GET http://BFF/api/bioflow/health | 200 且响应体=直连 8098 响应体 | L2 | P0 |
| TC-BIO-API-101 | FR-BIO-028 | BFF 反代开关关闭态 | BIOFLOW_ENABLED=false | GET http://BFF/api/bioflow/health | 404(路由未注册) | L2 | P0 |
| TC-BIO-API-102 | FR-BIO-028 | 反代 SSE 透传不缓冲 | BFF 反代开启;任务运行 | 经 BFF 连 events 测首字节延迟 | 首帧到达延迟与直连差 <500ms;流连续无缓冲合并 | L2 | P0 |
| TC-BIO-API-103 | FR-BIO-028 | BFF 停而生信服务直连可用 | BFF 停止(mock) | 直连 GET :8098/api/bioflow/health | 200;任务可继续(GET jobs 正常) | L2 | P0 |
| TC-BIO-API-104 | FR-BIO-015 | 报告登记端点 | 任务 done 报告在任务目录 | BFF 调用报告登记(字段 job_id/标题/md/图清单) | doc_artifacts 表出现新行;字段与 docgen 报告表对齐 | L2 | P0 |
| TC-BIO-API-105 | FR-BIO-006 | 反代上传超时单独调大 | BFF 反代开启 | 经 BFF 上传 456MB fixture | 200;无 502/504;服务端统计耗时正常 | L2 | P1 |
| TC-BIO-API-106 | FR-BIO-007 | 路径登记经 BFF 反代 | 反代开启 | 经 BFF POST files {"server_path": 合法} | 200 且直连与反代结果一致 | L2 | P2 |
| TC-BIO-API-107 | FR-BIO-004 | jobs 创建后进度字段 | 新任务 | GET job | progress=0;stages 全部 waiting | L2 | P1 |
| TC-BIO-API-108 | FR-BIO-011 | 日志尾非 running 阶段也可见 | 阶段 done | GET manifest | 200;log_tail 非空(保留最后执行日志) | L2 | P1 |
| TC-BIO-API-109 | FR-BIO-031 | 第 4 并发任务排队 | 3 任务 running(mock) | 创建第 4 任务并 confirm | 第 4 任务不立即出 stage_started;前 3 任一完成后方出现 | L2 | P0 |
| TC-BIO-API-110 | FR-BIO-031 | 并发信号量可配 | BIOFLOW_CONCURRENCY=1 重启 | 2 任务并发 | 始终只有 1 个 docker 在跑(mock 计数=1) | L2 | P1 |
| TC-BIO-API-111 | FR-BIO-031 | 重启续跑不重跑已完成 | 任务 3 阶段(1 done 1 running);重启服务 | 观察 | 重启后第 1 阶段保持 done(无新 attempt);第 2 阶段从断点续跑 | L2 | P0 |
| TC-BIO-API-112 | FR-BIO-024 | 任务列表过滤状态 | 库中 done/failed 各一 | GET /api/bioflow/jobs?status=failed | items 仅 failed 任务 | L2 | P1 |
| TC-BIO-API-113 | FR-BIO-024 | 任务列表按会话过滤 | 会话 s1 2 任务 | GET /api/bioflow/jobs?session_id=s1 | items length=2 | L2 | P1 |
| TC-BIO-API-114 | FR-BIO-002 | catalog 阶段用途文案 | 无 | GET catalog?stage=identify | description 非空中文文案(含输入输出描述) | L2 | P1 |
| TC-BIO-API-115 | FR-BIO-029 | 执行日志含资源参数 | 阶段 running(mock docker 记录命令) | 读 stage_log | 日志或 mock 记录含 --cpus 与 --memory 数值 | L2 | P0 |
| TC-BIO-API-116 | FR-BIO-029 | 镜像按阶段映射 | identify 阶段 | mock 记录 docker 命令 | 命令镜像=bioflow-gf(stage_image_map 映射) | L2 | P0 |
| TC-BIO-API-117 | FR-BIO-029 | 容器 --user 宿主机 uid | 阶段执行 | mock 记录命令 | 含 --user 且值=服务进程 uid | L2 | P0 |
| TC-BIO-API-118 | FR-BIO-029 | BIOFLOW_DATA 只读挂载 | 阶段执行 | mock 记录命令 | 含 -v {BIOFLOW_DATA_ROOT}:/bioflow-data:ro | L2 | P0 |
| TC-BIO-API-119 | FR-BIO-029 | 容器退出即清理 | 阶段完成 | mock 记录 | 含 --rm 标志 | L2 | P1 |
| TC-BIO-API-120 | FR-BIO-006 | 上传无任务 404 | 无 | POST /api/bioflow/jobs/nope/files | 404 信封 | L2 | P1 |
| TC-BIO-API-121 | FR-BIO-008 | confirm 空参数体 | 阶段 waiting_confirm | POST confirm {} | 200;按默认参数执行 | L2 | P1 |
| TC-BIO-API-122 | FR-BIO-010 | 暂停含排队任务 | 任务 queued | POST pause | 200;队列移除且状态=paused | L2 | P1 |
| TC-BIO-API-123 | FR-BIO-016 | 报告登记含图清单 | 报告含 2 图 | 登记 | doc_artifacts 行图清单字段含 2 个 fig id | L2 | P1 |
| TC-BIO-API-124 | FR-BIO-015 | 报告 HTML 单文件 | 任务 done | 读任务目录报告文件 | 单 .html 文件;图以 data:image/...;base64 内嵌(无外部图文件引用) | L2 | P0 |
| TC-BIO-API-125 | FR-BIO-015 | 报告含各阶段 manifest 事实 | 任务 done | 解析报告 HTML | 含 identify 阶段输出数量等 manifest 事实数据 | L2 | P1 |
| TC-BIO-API-126 | FR-BIO-014 | events 未知 job 404 | 无 | GET /api/bioflow/jobs/nope/events | 404 信封 | L2 | P1 |
| TC-BIO-API-127 | FR-BIO-011 | stage_log 事件日志尾推送 | 阶段 running | 读 events | stage_log 事件 data.log 字段非空且随执行追加 | L2 | P0 |
| TC-BIO-API-128 | FR-BIO-014 | 断线期间事件不丢 | 任务 running;断开 5s 重连 | 重连读事件 | 断开期间产生的 stage_log 全部回放 | L2 | P0 |
| TC-BIO-API-129 | FR-BIO-020 | 存档含中间文件开关 | 任务 done 含中间文件 | POST archives include_intermediate=true | 磁盘目录含中间产物;size 更大 | L2 | P1 |
| TC-BIO-API-130 | FR-BIO-020 | 存档不含中间文件 | 同上 | POST archives include_intermediate=false | 磁盘目录不含中间产物目录 | L2 | P1 |
| TC-BIO-API-131 | FR-BIO-021 | 存档状态回复字段 | 存档完成 | 读对话消息 | 消息含名称/位置/大小三要素字段 | L2 | P0 |
| TC-BIO-API-132 | FR-BIO-023 | run 后新任务入列表 | POST archives/run | GET jobs | 新任务出现在列表(title 含 target) | L2 | P1 |
| TC-BIO-API-133 | FR-BIO-025 | health 失败 503 | 服务 db 损坏(mock) | GET health | 503 或 200 带 db:error 字段(两态断言其一) | L2 | P1 |
| TC-BIO-API-134 | FR-BIO-028 | 生信服务独立进程 | 无 | 检查进程表 | 8098 进程独立于 BFF;BFF 重启后 8098 存活 | L2s | P0 |
| TC-BIO-API-135 | FR-BIO-028 | 独立 SQLite | 无 | 检查文件 | bioflow.db 存在于生信数据根;BFF 无同表 | L2s | P1 |
| TC-BIO-API-136 | FR-BIO-001 | chat 流错误信封 | mock LLM 500 | 读流 | SSE data 含 code/msg 错误信封结构 | L2 | P1 |
| TC-BIO-API-137 | FR-BIO-002 | plan_ready 用途字段非空 | mock LLM | 读 plan_ready | 每条 candidate.purpose 非空 | L2 | P1 |
| TC-BIO-API-138 | FR-BIO-004 | 确认创建任务后 SSE 建库 | 前端确认 | 读事件 | job_created 后 GET job 200 且状态=created | L2 | P0 |
| TC-BIO-API-139 | FR-BIO-031 | 任务失败不占并发 | 任务失败 | 创建新任务 confirm | 新任务立即执行(信号量已释放) | L2 | P1 |
| TC-BIO-API-140 | FR-BIO-012 | 改参数重跑走 confirm | 阶段 failed | POST rerun {"params":{...}} | 状态=waiting_confirm(表单再确认)或直接 running(两态断言其一) | L2 | P1 |
| TC-BIO-API-141 | FR-BIO-022 | 归档文件下载 | 归档 a1 | GET /api/bioflow/archives/{a1}/download | 200 zip/目录打包流;可解压 | L2 | P1 |
| TC-BIO-API-142 | FR-BIO-022 | 归档报告单独取 | 归档 a1 含报告 | GET /api/bioflow/archives/{a1}/report | 200;text/html 内容含 <html | L2 | P1 |
| TC-BIO-API-143 | FR-BIO-017 | 报告编辑落盘 | 报告已登记 | PATCH 报告文字 | 200;磁盘 HTML 内容更新 | L2 | P1 |
| TC-BIO-API-144 | FR-BIO-019 | revise 无绘图目标 422 | 报告任务 | POST revise {"instruction":"不明确"} | 422 或转 docgen(两态断言其一) | L2 | P2 |
| TC-BIO-API-145 | FR-BIO-002 | chat/stream 多候选单选 | 3 候选 | 用户选第 2 条(消息或 API 选) | 任务 stages=第 2 候选链 | L2 | P1 |
| TC-BIO-API-146 | FR-BIO-031 | 队列顺序 FIFO | 并发满 | 3 任务排队 | 完成 1 个后先入队者先执行 | L2 | P1 |
| TC-BIO-API-147 | FR-BIO-010 | 自动连续模式接口字段 | 任务开启 auto_continue | 读任务详情 | job.auto_continue=true;阶段间跳过 confirm | L2 | P0 |
| TC-BIO-API-148 | FR-BIO-010 | 自动连续暂停停在下一阶段前 | auto_continue 任务暂停 | 读任务 | 当前阶段等待且未 confirm;无跳过 | L2 | P1 |
| TC-BIO-API-149 | FR-BIO-004 | 创建任务重复 id 幂等 | POST jobs 两次相同 payload | 两次 | 产生 2 个不同 job id(或 409 二选一固定) | L2 | P2 |
| TC-BIO-API-150 | FR-BIO-009 | confirm 参数类型校验 | 无 | confirm {"params":{"cpu":"abc"}} | 422;detail 含 cpu 类型错误 | L2 | P1 |
### 6.1.3 RUN runner 状态机(L1 单元,mock docker 执行)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-RUN-001 | FR-BIO-031 | 全链成功推进 | 3 阶段任务 mock docker 全 0 退出 | run | 阶段状态依次 running→done;任务=done;事件序 stage_started/stage_done 成对 | L1 | P0 |
| TC-BIO-RUN-002 | FR-BIO-012 | 阶段失败转 failed | mock docker 退出码 1 | run | 状态=failed;事件 stage_failed;后续阶段不执行(任务停在 failed 阶段) | L1 | P0 |
| TC-BIO-RUN-003 | FR-BIO-012 | 失败后 rerun 成功 | 同上 | rerun | attempt=2;状态 done;继续后续阶段 | L1 | P0 |
| TC-BIO-RUN-004 | FR-BIO-012 | 失败后 skip | 阶段 failed | skip | 状态=skipped;事件 stage_skipped;后续阶段可执行 | L1 | P0 |
| TC-BIO-RUN-005 | FR-BIO-012 | 失败后改参数重跑 | 阶段 failed | rerun_with_params {"cpu":8} | 新执行命令含 cpu=8;成功 | L1 | P0 |
| TC-BIO-RUN-006 | FR-BIO-010 | 暂停在阶段边界 | 阶段 2 running 完成时 pause | 观察 | 阶段 2 done 后阶段 3 不启动;任务=paused;事件 job_paused | L1 | P0 |
| TC-BIO-RUN-007 | FR-BIO-010 | 暂停后恢复续跑 | 任务 paused | resume | 从下一阶段继续;不重跑已完成 | L1 | P0 |
| TC-BIO-RUN-008 | FR-BIO-031 | 重启续跑不重跑 | 任务 2/5 阶段 done;模拟重启加载 DB | 重启恢复 | 已 done 阶段 attempt 不变;从第 3 阶段续跑 | L1 | P0 |
| TC-BIO-RUN-009 | FR-BIO-031 | 重启恢复 in-flight | running 阶段无完成标记;重启 | 恢复 | 该阶段按 manifest 判成败:有 manifest 且成功→done;否则重跑 | L1 | P0 |
| TC-BIO-RUN-010 | FR-BIO-031 | 并发上限排队 | BIOFLOW_CONCURRENCY=3;4 任务 | run | 同时 running 的 docker ≤3;第 4 任务 queued | L1 | P0 |
| TC-BIO-RUN-011 | FR-BIO-031 | 并发槽释放 | 任务 1 完成 | 观察 | 队列头立即启动 | L1 | P1 |
| TC-BIO-RUN-012 | FR-BIO-029 | 阶段超时 | mock docker 不退出;timeout=1s | run | 阶段=failed(reason=timeout);容器被 kill;日志含超时记录 | L1 | P0 |
| TC-BIO-RUN-013 | FR-BIO-031 | 日志截断只留尾 | mock 输出 500 行 | run | bio_stages.log_tail 行数=80 且为末 80 行 | L1 | P0 |
| TC-BIO-RUN-014 | FR-BIO-029 | 退出码非 0 判失败 | mock 退出码 3 | run | 状态=failed;log_tail 含 stderr | L1 | P0 |
| TC-BIO-RUN-015 | FR-BIO-031 | 退出码 0 但 manifest 缺 | 无 manifest 产出 | run | 阶段=failed(reason=no_manifest) | L1 | P0 |
| TC-BIO-RUN-016 | FR-BIO-029 | manifest 失败标记判败 | manifest status=failed | run | 阶段=failed(不因退出码 0 误判成功) | L1 | P0 |
| TC-BIO-RUN-017 | FR-BIO-005 | 输入缺失等待文件 | 阶段 input 文件不存在 | run 至该阶段 | 状态=await_files;事件 stage_await_files;不启动 docker | L1 | P0 |
| TC-BIO-RUN-018 | FR-BIO-005 | 文件补齐自动推进 | await_files 后登记文件 | 触发 | 状态转 waiting_confirm(手动)或 running(自动连续);事件 stage_started | L1 | P0 |
| TC-BIO-RUN-019 | FR-BIO-008 | 阶段前等待确认 | 手动模式 | run 至阶段 | 状态=waiting_confirm;事件 stage_await_confirm;不执行 docker | L1 | P0 |
| TC-BIO-RUN-020 | FR-BIO-008 | 确认后执行 | waiting_confirm | confirm | docker 命令以表单参数构造;状态=running | L1 | P0 |
| TC-BIO-RUN-021 | FR-BIO-010 | 自动连续跳过确认 | auto_continue=true | run | 阶段间无 waiting_confirm;全程自动推进 | L1 | P0 |
| TC-BIO-RUN-022 | FR-BIO-010 | 自动连续可暂停 | auto_continue 任务 | pause | 停在当前阶段边界;恢复后仍自动连续 | L1 | P0 |
| TC-BIO-RUN-023 | FR-BIO-031 | 暂停恢复重入安全 | 任务 paused | resume 两次 | 第二次 resume 409/幂等无副作用 | L1 | P1 |
| TC-BIO-RUN-024 | FR-BIO-012 | 三选一状态校验 | 阶段 done | rerun/skip | 拒绝(状态机不越迁) | L1 | P1 |
| TC-BIO-RUN-025 | FR-BIO-031 | 并发信号量释放异常安全 | docker 执行抛异常 | 观察 | 信号量释放;任务转 failed;服务不挂 | L1 | P1 |
| TC-BIO-RUN-026 | FR-BIO-031 | 阶段间输入传递 | 上游 manifest 含 artifacts 路径 | run 下游 | 下游 docker 命令的 input 路径=上游 artifacts | L1 | P0 |
| TC-BIO-RUN-027 | FR-BIO-031 | 全部完成后归档提示事件 | 任务 done | 观察 | 事件 job_done 后紧跟 archive_suggest(或前端判 done 出提示,两态断言其一) | L1 | P1 |
| TC-BIO-RUN-028 | FR-BIO-024 | 多任务互不串扰 | 2 任务并发 | run | 各自状态/参数独立;无共享状态污染 | L1 | P1 |
| TC-BIO-RUN-029 | FR-BIO-024 | 任务进度数值 | 3 阶段任务完成 1 | 读进度 | progress=33(按完成阶段数/总阶段数) | L1 | P1 |
| TC-BIO-RUN-030 | FR-BIO-031 | 恢复时跳过已归档任务 | 已归档任务 in-flight 残留 | 重启 | 不重复执行(含 archive 状态检查) | L1 | P2 |
| TC-BIO-RUN-031 | FR-BIO-029 | docker 失败重试策略 | mock docker 偶发失败 | run | 按配置重试 N 次;最终 failed;attempt 数=N+1 | L1 | P1 |
| TC-BIO-RUN-032 | FR-BIO-005 | 多输入文件部分缺失 | 阶段需 2 文件缺 1 | run | await_files;事件 data 指明缺哪个文件 | L1 | P0 |
| TC-BIO-RUN-033 | FR-BIO-031 | 暂停时运行中阶段完成才停 | 阶段 running 且即将完成 | pause | 当前阶段完成→done 后任务才 paused(不杀容器) | L1 | P1 |
| TC-BIO-RUN-034 | FR-BIO-003 | 前置补全后链完整性 | 候选链缺前置 | 规划校验 | 补全后链包含前置;job.stages 完整 | L1 | P0 |
| TC-BIO-RUN-035 | FR-BIO-029 | 容器环境变量 BBA_* 注入 | 阶段执行 | mock 记录命令 | 含 -e BBA_*(至少 BBA_PFAM_DIR/BBA_RAG_MAPPING_FILE 其一) | L1 | P0 |
| TC-BIO-RUN-036 | FR-BIO-029 | 任务目录挂载 | 阶段执行 | mock 记录命令 | 含 -v {job_dir}/input:/job/input 与 -v {job_dir}/workspace:/job/workspace | L1 | P0 |
| TC-BIO-RUN-037 | FR-BIO-029 | 容器内命令形态 | 阶段执行 | mock 记录命令 | python -B -m cli.run_identify --input-dir /job/input --workspace /job/workspace(前缀两元素 python -B) | L1 | P0 |
| TC-BIO-RUN-038 | FR-BIO-031 | 阶段状态机非法迁移拒绝 | 任意状态 | 调用非法迁移 | 抛状态机错误/忽略(不写脏状态) | L1 | P1 |
| TC-BIO-RUN-039 | FR-BIO-031 | runner 无阶段空任务 | stages=[] | run | 直接 done;无 docker 调用 | L1 | P2 |
| TC-BIO-RUN-040 | FR-BIO-031 | 并发计数含 running 阶段 | 3 任务各 1 running | 观察 | 计数=3;新任务排队 | L1 | P1 |
| TC-BIO-RUN-041 | FR-BIO-031 | 阶段等待确认不占并发 | 任务 waiting_confirm | 观察 | 并发计数不含该任务 | L1 | P1 |
| TC-BIO-RUN-042 | FR-BIO-031 | 事件总线订阅多者广播 | 2 个 events 连接 | run 1 阶段 | 两连接收到相同事件序列 | L1 | P1 |
| TC-BIO-RUN-043 | FR-BIO-031 | 心跳期无事件不空转 | 任务 paused | 观察 CPU | 无 busy-loop(等待用事件/队列阻塞) | L1 | P2 |
| TC-BIO-RUN-044 | FR-BIO-024 | manifest 路径登记 | 阶段 done | 读 bio_stages | manifest_path 指向任务目录内真实文件 | L1 | P0 |
| TC-BIO-RUN-045 | FR-BIO-012 | 跳过事件携带阶段名 | skip | 读事件 | stage_skipped.data.stage=阶段名 | L1 | P1 |
| TC-BIO-RUN-046 | FR-BIO-031 | 长时间任务状态可查 | mock 慢执行 | 执行中 GET job | 状态=running;无阻塞(独立线程/协程) | L1 | P1 |
### 6.1.4 KERN 内核执行与 manifest(L1 单元 mock 命令拼装 + L2s 真实冒烟)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-KERN-001 | FR-BIO-029 | docker 命令拼装基元 | mock | 拼装 identify 阶段命令 | 数组元素依次:docker,run,--rm,--user,uid,-v×3,--cpus,--memory,-e×N,镜像,python,-B,-m,cli.run_identify,参数… | L1 | P0 |
| TC-BIO-KERN-002 | FR-BIO-029 | 挂载三目录 | mock | 拼装 | -v 含 input/workspace/BIOFLOW_DATA 三处;BIOFLOW_DATA 后带 :ro | L1 | P0 |
| TC-BIO-KERN-003 | FR-BIO-029 | --cpus 注入 | mock | 拼装 | 含 --cpus 且值来自阶段配置 | L1 | P0 |
| TC-BIO-KERN-004 | FR-BIO-029 | --memory 注入 | mock | 拼装 | 含 --memory 且格式如 64g | L1 | P0 |
| TC-BIO-KERN-005 | FR-BIO-029 | 环境变量拼装 | mock | 拼装 | 每项 env 输出为两个元素:-e 与 KEY=value | L1 | P0 |
| TC-BIO-KERN-006 | FR-BIO-029 | 容器命令转义安全 | 参数含空格 | 拼装 | 参数作为独立 argv 元素(subprocess list 传参,无 shell 注入) | L1 | P0 |
| TC-BIO-KERN-007 | FR-BIO-029 | 镜像映射查表 | mock | 查 align 阶段镜像 | 返回 bioflow-gf(stage_image_map.json) | L1 | P0 |
| TC-BIO-KERN-008 | FR-BIO-029 | 未知阶段镜像映射 | mock | 查未知阶段 | 返回 None 且执行前置拦截(不拼命令) | L1 | P1 |
| TC-BIO-KERN-009 | FR-BIO-029 | 超时 kill | mock docker 超时 | 观察 | 调用 kill/terminate;阶段 failed | L1 | P0 |
| TC-BIO-KERN-010 | FR-BIO-030 | 金标 24 成员 ID 全等 | bioflow-gf 镜像;金标输入 Ft.SPL | 镜像内跑 identify | 输出 ID 集合与 dev 预期 24 成员集合 diff 为空 | L2s | P0 |
| TC-BIO-KERN-011 | FR-BIO-030 | 金标 diff 命令空输出 | 同上 | 执行 diff 脚本 | stdout 为空;脚本退出码 0 | L2s | P0 |
| TC-BIO-KERN-012 | FR-BIO-032 | 18 入口 --help 冒烟 | 4 镜像齐 | 对 18 个 cli.run_* 逐条 python -B -m cli.run_x --help | 18/18 退出码 0;无 traceback | L2s | P0 |
| TC-BIO-KERN-013 | FR-BIO-032 | 镜像内 import 编译产物 | bioflow-gf 镜像 | python -c "import gfa_core.mas" | 成功(.so 加载无 ImportError) | L2s | P0 |
| TC-BIO-KERN-014 | FR-BIO-030 | manifest 解析成功路径 | 金标 manifest fixture | 解析 | 字段齐:status/artifacts/outputs/params/耗时 | L1 | P0 |
| TC-BIO-KERN-015 | FR-BIO-030 | manifest 缺失文件 | 无 manifest 文件 | 解析 | 返回错误(判失败 reason=no_manifest) | L1 | P0 |
| TC-BIO-KERN-016 | FR-BIO-030 | manifest 非法 JSON | 损坏内容 | 解析 | 返回解析错误;阶段 failed | L1 | P1 |
| TC-BIO-KERN-017 | FR-BIO-030 | manifest status 缺失 | JSON 无 status 键 | 解析 | 按退出码兜底判成败 | L1 | P1 |
| TC-BIO-KERN-018 | FR-BIO-030 | artifacts 路径提取 | manifest 含 artifacts | 解析 | 提取为下游输入(跨阶段输入定位) | L1 | P0 |
| TC-BIO-KERN-019 | FR-BIO-030 | 路径不存在时报错 | artifacts 指向缺失文件 | 解析 | 报错含具体路径(阶段失败) | L1 | P1 |
| TC-BIO-KERN-020 | FR-BIO-030 | 24 ID 去重与排序无关 | 金标输出乱序 | 比对 | 集合比对全等(顺序无关) | L2s | P1 |
| TC-BIO-KERN-021 | FR-BIO-032 | 4 镜像构建产物 | build_all.sh 完成 | 检查 | 4 镜像 tag 均存在(docker images 可见) | L2s | P0 |
| TC-BIO-KERN-022 | FR-BIO-032 | SHA256SUMS 产出 | 构建完成 | 检查 | 产物目录存在 SHA256SUMS 且含 4 条目 | L2s | P0 |
| TC-BIO-KERN-023 | FR-BIO-032 | 泄露门禁(明文凭据扫描) | 构建产物 | 扫描 .so/明文 | 无 ACCESS_KEY/SECRET 类凭据命中 | L2s | P0 |
| TC-BIO-KERN-024 | FR-BIO-029 | 数据不进镜像 | 构建产物 | 检查镜像层 | 镜像内无金标/用户数据文件 | L2s | P1 |
### 6.1.5 SSE 事件流与断线回放(L1 单元帧解析 + L2 序列)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-SSE-001 | FR-BIO-014 | 事件类型全集 | mock 全链 | 收集事件 | 出现类型 ∈ {job_created, plan_ready, stage_started, stage_log, stage_done, stage_failed, stage_skipped, stage_await_confirm, stage_await_files, job_done, job_paused, job_archived} 且无未知类型 | L1 | P0 |
| TC-BIO-SSE-002 | FR-BIO-014 | job_created 字段 | 创建任务 | 读事件 | data 含 job_id/title/stages | L1 | P0 |
| TC-BIO-SSE-003 | FR-BIO-014 | stage_started 字段 | 阶段启动 | 读事件 | data 含 stage/attempt/ts | L1 | P0 |
| TC-BIO-SSE-004 | FR-BIO-014 | stage_log 追加 | 阶段运行 | 读事件 | data.log 非空;多帧顺序=日志顺序 | L1 | P0 |
| TC-BIO-SSE-005 | FR-BIO-014 | stage_done 字段 | 阶段完成 | 读事件 | data 含 stage/exit_code=0/manifest_ref | L1 | P0 |
| TC-BIO-SSE-006 | FR-BIO-014 | stage_failed 字段 | 阶段失败 | 读事件 | data 含 stage/exit_code 非 0/reason | L1 | P0 |
| TC-BIO-SSE-007 | FR-BIO-014 | stage_skipped 字段 | 跳过 | 读事件 | data 含 stage | L1 | P0 |
| TC-BIO-SSE-008 | FR-BIO-014 | stage_await_confirm 字段 | 阶段待确认 | 读事件 | data 含 stage/form_defaults(参数默认值) | L1 | P0 |
| TC-BIO-SSE-009 | FR-BIO-014 | stage_await_files 字段 | 阶段待文件 | 读事件 | data 含 stage/required_files[](含缺失文件名) | L1 | P0 |
| TC-BIO-SSE-010 | FR-BIO-014 | job_done 收尾 | 任务完成 | 读事件 | data 含 job_id/耗时;为最后事件 | L1 | P0 |
| TC-BIO-SSE-011 | FR-BIO-014 | job_paused 字段 | 暂停 | 读事件 | data 含 job_id/当前阶段 | L1 | P0 |
| TC-BIO-SSE-012 | FR-BIO-014 | job_archived 字段 | 存档 | 读事件 | data 含 archive_id | L1 | P1 |
| TC-BIO-SSE-013 | FR-BIO-014 | seq 严格递增 | mock 帧序列 | 解析 seq | 后帧 seq=前帧 seq+1 | L1 | P0 |
| TC-BIO-SSE-014 | FR-BIO-014 | 帧解析空行容错 | 帧含多余空行 | 解析 | 正常解析不报错 | L1 | P1 |
| TC-BIO-SSE-015 | FR-BIO-014 | 多行 data 合并 | data 分行发送 | 解析 | 事件 data 按 \n 合并 | L1 | P1 |
| TC-BIO-SSE-016 | FR-BIO-014 | 心跳注释忽略 | 帧含 :keepalive | 解析 | 不产业务事件 | L1 | P1 |
| TC-BIO-SSE-017 | FR-BIO-014 | 坏帧不中断流 | 含未命名 data 帧 | 解析 | 跳过坏帧继续后续事件 | L1 | P1 |
| TC-BIO-SSE-018 | FR-BIO-014 | 前端 parser 兼容既有帧 | 既有 sse/parser.js 输出格式 | 解析 bioflow 帧 | 复用 parser 无改动可解析(红线零改动验证) | L3 | P0 |
| TC-BIO-SSE-019 | FR-BIO-014 | 事件序列全链顺序 | mock 3 阶段 | 收集序列 | 相对序:job_created<plan_ready<首 stage_started<末 stage_done<job_done | L2 | P0 |
| TC-BIO-SSE-020 | FR-BIO-014 | 失败序列 | mock 阶段 2 失败 | 收集 | 出现 stage_failed;无该阶段 stage_done;后续阶段无 stage_started | L2 | P0 |
| TC-BIO-SSE-021 | FR-BIO-014 | 跳过序列 | mock skip | 收集 | stage_skipped 出现在 stage_failed 之后 | L2 | P0 |
| TC-BIO-SSE-022 | FR-BIO-014 | 断线回放快照结构 | 任务 3 阶段中途 | 重连首帧 | 首帧 data.type=snapshot;data.job.status 与 DB 一致;data.stages 逐阶段含 status | L2 | P0 |
| TC-BIO-SSE-023 | FR-BIO-014 | 回放补齐事件序 | 断开 5s 期间 2 条 stage_log | 重连 | 快照后回放这 2 条;seq 连续 | L2 | P0 |
| TC-BIO-SSE-024 | FR-BIO-014 | 回放不重复已见事件 | 客户端带 last_seq 重连 | 重连 | 不重发 ≤last_seq 事件 | L2 | P0 |
| TC-BIO-SSE-025 | FR-BIO-014 | 前端重连机制 | 断网 30s | 观察前端 | 自动重连(重试/退避);进度卡整体刷新 | L3 | P0 |
| TC-BIO-SSE-026 | FR-BIO-014 | 前端回放刷新进度卡 | 快照 1 done 1 running 1 waiting | 应用快照 | 卡片三阶段状态与快照一致;日志尾区显示 | L3 | P0 |
| TC-BIO-SSE-027 | FR-BIO-014 | 重连失败提示 | 服务不可达 | 观察 | 进度卡显示断线态;有重连按钮/文案 | L3 | P1 |
| TC-BIO-SSE-028 | FR-BIO-014 | events 与 chat/stream 事件同源 | 同任务 | 对比两流 | 事件类型与 seq 一致 | L2 | P1 |
| TC-BIO-SSE-029 | FR-BIO-014 | 事件延迟心跳期间无重复 job_done | 任务 done | 读流 | job_done 仅 1 次 | L2 | P1 |
| TC-BIO-SSE-030 | FR-BIO-014 | 快照含日志尾 | 阶段 running 有日志 | 重连快照 | snapshot.stages[*].log_tail 非空 | L2 | P0 |
| TC-BIO-SSE-031 | FR-BIO-014 | Last-Event-ID 续传 | 断连时记录 id | 重连带 Last-Event-ID | 服务从该 id 后补发 | L2 | P1 |
| TC-BIO-SSE-032 | FR-BIO-014 | 前端事件更新器幂等 | 重复 stage_done 帧 | 应用两次 | 阶段状态仍 done;无异常 | L3 | P1 |
### 6.1.6 DB 三表迁移与持久化(L1)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-DB-001 | FR-BIO-028 | 三表创建 | 空库 | 初始化 | bio_jobs/bio_stages/bio_archives 三表存在;schema 含任务书字段 | L1 | P0 |
| TC-BIO-DB-002 | FR-BIO-028 | 迁移幂等 | 已初始化 | 重复跑迁移 | 无异常;schema_version 不变;表数不增 | L1 | P0 |
| TC-BIO-DB-003 | FR-BIO-028 | 版本升级迁移 | v1 库 fixture | 迁移至 v2 | 新列存在;旧数据保留 | L1 | P1 |
| TC-BIO-DB-004 | FR-BIO-028 | 阶段链 JSON 存取 | 任务 3 阶段 | 写入读回 | stages 数组完整还原 | L1 | P0 |
| TC-BIO-DB-005 | FR-BIO-028 | 参数 JSON 存取 | 参数嵌套 | 写入读回 | 参数对象完整还原(含嵌套) | L1 | P0 |
| TC-BIO-DB-006 | FR-BIO-024 | 任务级联删除阶段 | 任务含 5 阶段 | 删任务 | bio_stages 对应行=0 | L1 | P0 |
| TC-BIO-DB-007 | FR-BIO-022 | 归档外键任务 | 任务 j1 归档 | 删任务(若实现允许) | 归档保留或级联(两态断言其一,按实现固定) | L1 | P1 |
| TC-BIO-DB-008 | FR-BIO-028 | 时间戳字段 | 创建任务 | 读行 | created_at/updated_at 非空且 ISO 格式 | L1 | P1 |
| TC-BIO-DB-009 | FR-BIO-028 | 状态枚举约束 | 写入 | 写非法状态值 | 拒绝或枚举约束错误 | L1 | P1 |
| TC-BIO-DB-010 | FR-BIO-031 | 并发写安全 | 2 协程更新同任务 | 并发写 | 无死锁;最终状态一致 | L1 | P1 |
| TC-BIO-DB-011 | FR-BIO-024 | log_tail 持久化 | 阶段运行 | 更新 log_tail | 读回与内存一致 | L1 | P0 |
| TC-BIO-DB-012 | FR-BIO-021 | 归档大小与路径字段 | 存档 | 读 bio_archives 行 | size_bytes>0;disk_path 非空且目录存在 | L1 | P0 |
### 6.1.7 FLOW 上下游集成(接口级)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-FLOW-001 | FR-BIO-028 | BFF 反代开启注册 | BIOFLOW_ENABLED=true 启动 BFF | 检查路由表 | /api/bioflow/* 路由已注册(FastAPI routes 可见) | L2 | P0 |
| TC-BIO-FLOW-002 | FR-BIO-028 | BFF 反代关闭不注册 | BIOFLOW_ENABLED=false | 检查路由表 | 无 /api/bioflow/* 路由 | L2 | P0 |
| TC-BIO-FLOW-003 | FR-BIO-016 | 报告登记进 doc_artifacts | 生信任务 done | 登记 | doc_artifacts 新行;kind=bioflow_report 或等价字段 | L2 | P0 |
| TC-BIO-FLOW-004 | FR-BIO-016 | 报告登记字段对齐 | 登记 | 读行 | job_id/标题/md/图清单与 docgen 表字段对齐(缺字段报错) | L2 | P0 |
| TC-BIO-FLOW-005 | FR-BIO-015 | fig:// 图引用渲染 | 报告含 fig://fig1 | 渲染报告 | img src 变为 data:image/...base64;无 fig:// 残留 | L3 | P0 |
| TC-BIO-FLOW-006 | FR-BIO-015 | fig:// 未知 id 降级 | fig://nope | 渲染 | 图位置显示占位/跳过且不报错 | L3 | P1 |
| TC-BIO-FLOW-007 | FR-BIO-016 | DocPane 白底预览 | 报告登记 | 打开 DocPane | 容器 computed background=#FFFFFF(白底);图文正常 | L4 | P0 |
| TC-BIO-FLOW-008 | FR-BIO-019 | revise 触发预览刷新 | 图表调整后 | 观察 DocPane | 预览重新加载;新图可见 | L3 | P0 |
| TC-BIO-FLOW-009 | FR-BIO-026 | vstore flow_docs 检索 | flow_docs 集合已入库 | 检索「identify 需要什么输入」 | 返回块含源文件+章节;top1 相关 | L2 | P0 |
| TC-BIO-FLOW-010 | FR-BIO-023 | 存档复用端到端接口链 | 归档 a1 | POST archives/{a1}/run | 新任务→表单预填→confirm→执行,参数=归档值(全链) | L2 | P0 |
### 6.1.8 STORE 前端 store(L3 vitest)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-STORE-001 | FR-BIO-001 | sendBioflow 动作存在 | store 挂载 | 调用 sendBioflow(msg) | 消息进入 messages 数组且 blocks 含 bioflow 类块 | L3 | P0 |
| TC-BIO-STORE-002 | FR-BIO-001 | 分流未命中不触发生信 | mock 词典 | 发送「什么是基因家族」 | 走原 send() 路径;不产生 bioflow 请求 | L3 | P0 |
| TC-BIO-STORE-003 | FR-BIO-002 | 候选路径写入消息 | mock plan_ready | 应用事件 | 消息 blocks 含 path 块且 candidates.length 2~3 | L3 | P0 |
| TC-BIO-STORE-004 | FR-BIO-004 | 确认后创建任务状态 | mock job_created | 应用事件 | bioflowJob 状态写入 store(jobId 非空) | L3 | P0 |
| TC-BIO-STORE-005 | FR-BIO-011 | 阶段状态更新 | mock stage 事件序列 | 逐帧应用 | store 中阶段状态 waiting→running→done 逐帧一致 | L3 | P0 |
| TC-BIO-STORE-006 | FR-BIO-012 | 失败事件置 failed | mock stage_failed | 应用 | store 阶段 status=failed 且 error 文案存在 | L3 | P0 |
| TC-BIO-STORE-007 | FR-BIO-011 | 日志尾追加 | mock stage_log×3 | 应用 | store logTail 追加为整体,长度=三帧之和 | L3 | P0 |
| TC-BIO-STORE-008 | FR-BIO-014 | 快照整体替换 | mock snapshot | 应用 | store 阶段数组被快照整体替换(引用变化) | L3 | P0 |
| TC-BIO-STORE-009 | FR-BIO-014 | 断线重连触发 | SSE 断开(mock) | 等待 | store 触发 reconnect;成功后应用快照 | L3 | P0 |
| TC-BIO-STORE-010 | FR-BIO-006 | 上传进度状态 | mock XHR 进度 45% | 上传 | store uploadProgress=45 | L3 | P0 |
| TC-BIO-STORE-011 | FR-BIO-009 | 表单值提交 | mock | dispatch confirmStage(stage, params) | 请求体 params 与表单一致 | L3 | P0 |
| TC-BIO-STORE-012 | FR-BIO-010 | 自动连续开关状态 | mock | 切换 autoContinue | store.autoContinue=true 且随任务持久化字段下发 | L3 | P0 |
| TC-BIO-STORE-013 | FR-BIO-010 | 暂停/恢复动作 | mock | dispatch pauseJob/resumeJob | store 状态 paused/running;发出对应 POST | L3 | P0 |
| TC-BIO-STORE-014 | FR-BIO-012 | 三选一动作 | mock | dispatch rerunStage/skipStage/rerunWithParams | 分别发出 rerun/skip/rerun 请求;请求体正确 | L3 | P0 |
| TC-BIO-STORE-015 | FR-BIO-023 | 存档复用预填 | mock archive_loaded | 应用 | store.formDefaults=存档参数;来源标记=archive | L3 | P0 |
| TC-BIO-STORE-016 | FR-BIO-025 | 探活结果 | mock health 200/500 | 初始化 | 200→bioflowAvailable=true;500/超时→false | L3 | P0 |
| TC-BIO-STORE-017 | FR-BIO-021 | 存档状态回复写入 | mock archive_done | 应用 | 消息块含名称/位置/大小三字段 | L3 | P0 |
| TC-BIO-STORE-018 | FR-BIO-024 | 面板任务列表 | mock jobs | loadJobs | store.jobs 数组与接口一致(排序) | L3 | P0 |
| TC-BIO-STORE-019 | FR-BIO-022 | 档案列表 | mock archives | loadArchives | store.archives 数组与接口一致 | L3 | P0 |
| TC-BIO-STORE-020 | FR-BIO-014 | 事件乱序容错 | mock 乱序帧 | 应用 | 不崩溃;状态不回退(done 不再变 running) | L3 | P1 |
| TC-BIO-STORE-021 | FR-BIO-014 | 会话切换隔离 | 2 会话各 1 任务 | 切换 | store 当前任务随会话切换;互不污染 | L3 | P1 |
| TC-BIO-STORE-022 | FR-BIO-001 | 红线文件零改动校验 | 仓库 checkout 状态 | 对比 modes.js/labels.js/bench.js/qa.js/parser.js | 与分支基线一致(无 diff) | L3 | P0 |
### 6.1.9 PATH 路径选择卡(flow-path-card,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-PATH-001 | FR-BIO-002 | 引导 UI 显示:卡片标题 | mock 候选 2 条 | 挂载 | 标题文本=「🧬 分析路径选择」;卡体有 .flow-path-card 类 | L4 | P0 |
| TC-BIO-PATH-002 | FR-BIO-002 | 引导操作:候选行渲染 | 2-3 条候选 | 挂载 | 渲染 2-3 个候选行;每行含阶段序列文本(首阶段加粗)与用途文本 | L4 | P0 |
| TC-BIO-PATH-003 | FR-BIO-002 | 候选行阶段序列显示 | 候选 [identify,align,phylogeny] | 挂载 | 行文本含「identify → align → phylogeny」;首阶段字重 600 | L4 | P0 |
| TC-BIO-PATH-004 | FR-BIO-002 | 引导操作:点选候选行 | 未选中 | 点击第 2 行 | 该行获得选中态(border 1.5px --pa-g-from;背景=gradient 8% 混色) | L4 | P0 |
| TC-BIO-PATH-005 | FR-BIO-002 | 引导 UI 显示:选中态边框 | 已选中 | 检查 computed style | border-width=1.5px 且 border-color=var(--pa-g-from) | L4 | P0 |
| TC-BIO-PATH-006 | FR-BIO-002 | 确认按钮选中后可点 | 已选中 | 检查「确认此路径」按钮 | disabled=false;背景为 --pa-gradient;文字白色 12.5px/600 | L4 | P0 |
| TC-BIO-PATH-007 | FR-BIO-002 | 确认按钮无选中禁用 | 未选中 | 检查 | disabled=true;opacity=0.45 | L4 | P0 |
| TC-BIO-PATH-008 | FR-BIO-002 | 引导操作:确认发出选择 | 已选中候选 2 | 点击确认 | 触发 select 回调/请求,参数=候选 2 的 stages | L4 | P0 |
| TC-BIO-PATH-009 | FR-BIO-002 | 自然语言改选 | 候选 3 条 | 用户输入「换第二条」 | 回调携带选中索引 2(或经 LLM 解析) | L4 | P1 |
| TC-BIO-PATH-010 | FR-BIO-002 | 空候选不渲染 | candidates=[] | 挂载 | 卡体不渲染(或空态文案);不报错 | L4 | P1 |
| TC-BIO-PATH-011 | FR-BIO-002 | 单候选自动不强制 | candidates=1 | 挂载 | 渲染 1 行;确认仍可用 | L4 | P2 |
| TC-BIO-PATH-012 | FR-BIO-003 | 前置补全明示 | 候选含 auto_filled | 挂载 | 行内或提示区显示「已自动补全」标记与前置阶段名 | L4 | P0 |
| TC-BIO-PATH-013 | FR-BIO-004 | 确认卡逐阶段可读 | path 确认态 | 挂载确认视图 | 逐阶段显示名称/用途/预计耗时三要素 | L4 | P0 |
| TC-BIO-PATH-014 | FR-BIO-004 | 确认后任务创建请求 | 确认卡 | 点击确认 | 发出 POST /api/bioflow/jobs;body.stages=选中链 | L4 | P0 |
| TC-BIO-PATH-015 | FR-BIO-002 | 路径卡主题令牌 | 深/浅主题 | 检查 computed | 背景=surface-1;边框=hairline;圆角=r-lg | L4 | P1 |
| TC-BIO-PATH-016 | FR-BIO-002 | 移动端不溢出 | 390×844 | 挂载 | 卡片宽≤容器宽;无横向滚动 | L5-M | P1 |
| TC-BIO-PATH-017 | FR-BIO-004 | 阶段链超长显示 | 15 阶段候选 | 挂载 | 行内序列文本可换行/省略;行不撑破卡片 | L4 | P2 |
| TC-BIO-PATH-018 | FR-BIO-002 | 用途文本渲染 | candidate.purpose | 挂载 | 每行显示用途文本(非空) | L4 | P1 |
| TC-BIO-PATH-019 | FR-BIO-002 | 卡体尺寸 | 挂载 | 检查 computed | padding=14px 16px;margin=14px 0 | L4 | P2 |
| TC-BIO-PATH-020 | FR-BIO-002 | 行 hover 态 | 未选中 | hover 候选行 | 背景=surface-3(--pa-s3) | L4 | P1 |
| TC-BIO-PATH-021 | FR-BIO-002 | 键盘 Enter 确认 | 已选中;确认按钮聚焦 | 按 Enter | 触发确认回调(同点击) | L4 | P1 |
| TC-BIO-PATH-022 | FR-BIO-002 | 选中后再点同行走自然语言修改 | 已选中行 1 | 再次点击行 1 | 无选中态抖动;回调幂等(保持选中) | L4 | P2 |
### 6.1.10 FORM 参数表单卡(flow-form-card,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-FORM-001 | FR-BIO-008 | 引导 UI 显示:表单卡标题 | 阶段 identify 待确认 | 挂载 | 标题=「⚙ identify 步骤 · 可调整参数」;.flow-form-card 存在 | L4 | P0 |
| TC-BIO-FORM-002 | FR-BIO-008 | 引导 UI 显示:前置文案 | 同上 | 挂载 | 对话区显示「XXXX 步骤,可调整参数如下,可按需调整,调整完毕后继续」文案 | L4 | P0 |
| TC-BIO-FORM-003 | FR-BIO-008 | 引导操作:字段渲染 | 参数 schema 3 字段 | 挂载 | 渲染 3 个字段行:label 12px ink-muted、宽 96px;input 存在 | L4 | P0 |
| TC-BIO-FORM-004 | FR-BIO-008 | 默认值显示 | 默认 cpu=4 | 挂载 | input value=4 | L4 | P0 |
| TC-BIO-FORM-005 | FR-BIO-008 | 引导 UI 显示:来源标注 | 字段含 source | 挂载 | 每字段下方 11px ink-subtle 文案含「默认值来源:阶段契约文档」 | L4 | P0 |
| TC-BIO-FORM-006 | FR-BIO-008 | 来源标注多类型 | 来源=参数预填值 | 挂载 | 标注文案区分「契约文档」与「参数预填」两来源 | L4 | P1 |
| TC-BIO-FORM-007 | FR-BIO-009 | 引导操作:编辑参数 | input cpu | 输入 8 | v-model 值=8;无校验拦截 | L4 | P0 |
| TC-BIO-FORM-008 | FR-BIO-009 | 继续按钮执行 | 已改 cpu=8 | 点击「继续」 | 发出 confirm 请求 body.params.cpu=8 | L4 | P0 |
| TC-BIO-FORM-009 | FR-BIO-009 | 继续按钮样式 | 挂载 | 检查 | 「继续」--pa-gradient 白字 12.5px/600;r-md;padding 7px 16px | L4 | P1 |
| TC-BIO-FORM-010 | FR-BIO-010 | 自动连续开关存在 | 挂载 | 检查 | 「自动连续执行」标签 12px ink-muted + switch(mode-pill 同款) | L4 | P0 |
| TC-BIO-FORM-011 | FR-BIO-010 | 引导操作:开启自动连续 | 开关关 | 点击开关 | switch 状态=开;随表单提交 auto_continue=true;后续阶段不再出表单卡 | L4 | P0 |
| TC-BIO-FORM-012 | FR-BIO-010 | 自动连续可关闭 | 开关开 | 点击 | 状态=关;切回手动(下一阶段仍出表单) | L4 | P0 |
| TC-BIO-FORM-013 | FR-BIO-008 | input 聚焦态 | 未聚焦 | 聚焦 input | border-color=var(--pa-g-from)(focus 态) | L4 | P1 |
| TC-BIO-FORM-014 | FR-BIO-008 | 数字参数类型校验 | cpu 字段 | 输入非数字「abc」 | 提交被拦截/请求不发出;显示类型错误提示 | L4 | P0 |
| TC-BIO-FORM-015 | FR-BIO-008 | 必填参数空值 | 必填字段清空 | 点继续 | 不发出请求;该字段标错 | L4 | P1 |
| TC-BIO-FORM-016 | FR-BIO-008 | 范围校验 | 字段 min=1 max=64 | 输入 999 | 校验提示(1-64);不提交 | L4 | P1 |
| TC-BIO-FORM-017 | FR-BIO-008 | 可选参数留空 | 可选字段 | 留空提交 | 请求体不含该字段(或 null);后端按默认 | L4 | P1 |
| TC-BIO-FORM-018 | FR-BIO-009 | 提交中继续按钮禁用 | mock 慢响应 | 点击继续 | 按钮 disabled+加载中态(spinner);不重复提交 | L4 | P0 |
| TC-BIO-FORM-019 | FR-BIO-009 | 提交失败可重试 | mock confirm 500 | 点击继续 | 显示错误;按钮恢复可点;可再次提交 | L4 | P1 |
| TC-BIO-FORM-020 | FR-BIO-023 | 复用预填显示 | 归档预填 cpu=16 标注来源=存档 | 挂载 | input=16;来源标注=存档名称 | L4 | P0 |
| TC-BIO-FORM-021 | FR-BIO-008 | 多阶段表单逐阶段出现 | 手动模式 3 阶段 | 推进 | 每阶段执行前都渲染该阶段表单(标题阶段名更新) | L4 | P0 |
| TC-BIO-FORM-022 | FR-BIO-008 | 表单关闭时机 | 阶段已 running | 事件应用 | 表单卡消失/折叠(不再可编辑) | L4 | P1 |
| TC-BIO-FORM-023 | FR-BIO-008 | 键盘 Enter 提交 | input 聚焦 | 按 Enter | 触发继续(同点击) | L4 | P1 |
| TC-BIO-FORM-024 | FR-BIO-008 | Esc 放弃编辑 | 已改未提交 | 按 Esc | 恢复默认值(或提示放弃,两态断言其一) | L4 | P2 |
### 6.1.11 FILE 文件引导卡(flow-file-card,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-FILE-001 | FR-BIO-005 | 引导 UI 显示:缺失提示文案 | 阶段 await_files | 挂载 | 对话出现「请将 xxx 数据文件拖入窗口上传至服务器,或在聊天窗口中指定数据文件的具体路径」文案且点名 xxx 文件名 | L4 | P0 |
| TC-BIO-FILE-002 | FR-BIO-005 | 引导 UI 显示:文件引导卡 | 同上 | 挂载 | .flow-file-card 存在;内含拖放区与路径输入行 | L4 | P0 |
| TC-BIO-FILE-003 | FR-BIO-006 | 引导操作:拖拽上传 | 本地测试文件 | 拖入拖放区 | 发出 POST /api/bioflow/jobs/{id}/files(multipart);文件名正确 | L4 | P0 |
| TC-BIO-FILE-004 | FR-BIO-006 | XHR 进度百分比 | mock XHR 分片 | 上传 | 进度条 fill 宽度变化且旁注百分比 11px mono(如 45%)逐级上升至 100% | L4 | P0 |
| TC-BIO-FILE-005 | FR-BIO-006 | 进度条令牌复用 | 上传中 | 检查类名 | 使用 prog-track/prog-fill(track surface-2 r-pill 高 4px;fill --pa-gradient) | L4 | P1 |
| TC-BIO-FILE-006 | FR-BIO-006 | 点击上传 | 未拖入 | 点击拖放区 | 打开文件选择框;选择后上传 | L4 | P0 |
| TC-BIO-FILE-007 | FR-BIO-006 | 大文件不断流 | 456MB fixture(L5 mock) | 上传 | 进度连续更新至 100%;无超时错误 | L5-D | P0 |
| TC-BIO-FILE-008 | FR-BIO-007 | 路径输入行存在 | 挂载 | 检查 | input(同 8.2 规格)+「登记路径」pane-btn 同款按钮 | L4 | P0 |
| TC-BIO-FILE-009 | FR-BIO-007 | 引导操作:登记合法路径 | 输入合法服务器路径 | 点「登记路径」 | 发出 POST files {"server_path":路径};成功后显示登记项(含路径与状态) | L4 | P0 |
| TC-BIO-FILE-010 | FR-BIO-007 | 非法路径报错 | 输入 /nonexistent | 登记 | 显示后端 400 错误文案(PATH_NOT_EXIST) | L4 | P0 |
| TC-BIO-FILE-011 | FR-BIO-006 | 上传成功状态 | 上传完成 | 观察 | 进度 100%;文件登记入列表(name/size 显示) | L4 | P0 |
| TC-BIO-FILE-012 | FR-BIO-006 | 上传失败可重试 | mock 500 | 上传 | 错误文案显示;拖放区可再次上传 | L4 | P1 |
| TC-BIO-FILE-013 | FR-BIO-006 | 上传中拖放区禁用重复 | 上传进行中 | 再拖入 | 忽略/禁用(不发起第二个上传) | L4 | P1 |
| TC-BIO-FILE-014 | FR-BIO-006 | 文件满足后卡收起 | 阶段转 running | 观察 | 文件卡消失或标记已完成 | L4 | P1 |
| TC-BIO-FILE-015 | FR-BIO-005 | 缺多文件点名列表 | 缺 fasta+cds | 挂载 | 提示列出两个文件名 | L4 | P1 |
| TC-BIO-FILE-016 | FR-BIO-006 | 拖放区视觉规格 | 挂载 | 检查 computed | border 2px dashed --pa-hairline-strong;r-lg;padding 24px;提示 12px ink-subtle 居中 | L4 | P1 |
| TC-BIO-FILE-017 | FR-BIO-006 | 拖入态高亮 | 拖入悬停 | 检查 | border-color=gradient 45% 混色;背景=gradient 8% 混色 | L4 | P0 |
| TC-BIO-FILE-018 | FR-BIO-006 | 移动端触控上传 | 390×844 触摸 | 点击/长按上传 | 文件选择可用(触控目标≥44px) | L5-M | P1 |
| TC-BIO-FILE-019 | FR-BIO-007 | 路径输入聚焦态 | 未聚焦 | 聚焦 | border=--pa-g-from | L4 | P2 |
| TC-BIO-FILE-020 | FR-BIO-007 | 路径输入 Enter 提交 | 输入合法路径 | 按 Enter | 同点「登记路径」 | L4 | P1 |
| TC-BIO-FILE-021 | FR-BIO-006 | 类型不符文件 | 选择 .exe | 上传 | 前端拦截或后端 422 文案显示 | L4 | P1 |
| TC-BIO-FILE-022 | FR-BIO-006 | 空文件提示 | 0 字节 | 上传 | 按实现断言:提示空文件或成功后 size=0 显示 | L4 | P2 |
### 6.1.12 PROG 阶段进度卡(bioflow-progress-card,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-PROG-001 | FR-BIO-011 | 引导 UI 显示:进度卡渲染 | 阶段链确定 | 挂载 | .bioflow-progress-card 存在;复用 pipeline-card 结构(状态点/连接线/相位色令牌) | L4 | P0 |
| TC-BIO-PROG-002 | FR-BIO-011 | 引导操作:逐阶段点亮 | 3 阶段推进 | 应用事件 | 状态点顺序变化:done=--pa-t-done 底白 ✓;running=相位色底●+pulse;waiting=surface-3 底◌ | L4 | P0 |
| TC-BIO-PROG-003 | FR-BIO-011 | 引导 UI 显示:日志尾区 | 阶段 running | 观察 | 仅 running/failed 阶段展开日志区:--pa-code-bg 底、mono 11px、padding 8px 10px、max-height 96px 滚动 | L4 | P0 |
| TC-BIO-PROG-004 | FR-BIO-011 | 日志尾随 SSE 追加 | stage_log×3 | 应用 | 日志文本追加增长;滚动至底部 | L4 | P0 |
| TC-BIO-PROG-005 | FR-BIO-011 | done 阶段日志收起 | 阶段 done | 观察 | 该阶段日志区不展开(仅 running/failed 展开) | L4 | P1 |
| TC-BIO-PROG-006 | FR-BIO-012 | 失败标红 | 阶段 failed | 观察 | 状态点=--pa-error 底 ✕;状态文字 error 色 12px/600 | L4 | P0 |
| TC-BIO-PROG-007 | FR-BIO-012 | 失败三选一按钮出现 | 阶段 failed | 观察 | 重跑/跳过/改参数重跑三按钮(pane-btn 同款 12px,gap 8px)仅 failed 阶段显示 | L4 | P0 |
| TC-BIO-PROG-008 | FR-BIO-012 | 重跑生效 | failed | 点重跑 | 发出 rerun 请求;状态点转 running | L4 | P0 |
| TC-BIO-PROG-009 | FR-BIO-012 | 跳过生效 | failed | 点跳过 | 发出 skip 请求;状态=skipped(--pa-ink-subtle 底◌;文字 ink-subtle) | L4 | P0 |
| TC-BIO-PROG-010 | FR-BIO-012 | 改参数重跑生效 | failed | 点改参数重跑 | 出现参数表单(该阶段);提交后重跑 | L4 | P0 |
| TC-BIO-PROG-011 | FR-BIO-012 | skipped 态视觉 | 阶段 skipped | 检查 | 状态点=--pa-ink-subtle 底◌;文字 ink-subtle | L4 | P1 |
| TC-BIO-PROG-012 | FR-BIO-013 | 折叠分组 | 15 阶段链 | 挂载 | 阶段>10 自动分组折叠;组头 12px/600+展开箭头;默认展开运行中所在组 | L4 | P0 |
| TC-BIO-PROG-013 | FR-BIO-013 | 展开可见全部 | 折叠组 | 点组头 | 展开显示该组全部阶段 | L4 | P0 |
| TC-BIO-PROG-014 | FR-BIO-013 | ≤10 阶段不折叠 | 10 阶段 | 挂载 | 无折叠组头(平铺 10 状态点) | L4 | P1 |
| TC-BIO-PROG-015 | FR-BIO-014 | 断线回放刷新进度卡 | 快照到达 | 应用 | 卡片整体刷新为快照状态(1 done 1 running 1 waiting 精确对应) | L4 | P0 |
| TC-BIO-PROG-016 | FR-BIO-014 | 回放后日志尾恢复 | 快照含 log_tail | 应用 | running 阶段日志区显示快照日志尾 | L4 | P1 |
| TC-BIO-PROG-017 | FR-BIO-010 | 暂停态视觉 | 任务 paused | 观察 | 运行中状态点停止 pulse;显示「已暂停」徽章/文案 | L4 | P0 |
| TC-BIO-PROG-018 | FR-BIO-010 | 恢复后继续 | 任务 paused | 点恢复 | 下一阶段启动(running 状态推进) | L4 | P0 |
| TC-BIO-PROG-019 | FR-BIO-011 | 进度卡与流水线卡同款视觉 | 对比 PipelineCard | 检查 | 结构/状态点/连接线/相位色与 §4.4 pipeline-card 令牌一致(同款) | L4 | P1 |
| TC-BIO-PROG-020 | FR-BIO-012 | 失败后后续阶段 waiting | 阶段 2 failed | 观察 | 阶段 3+ 保持 waiting 不高亮 | L4 | P1 |
| TC-BIO-PROG-021 | FR-BIO-024 | 任务面板进度视图复用 | 面板内 | 观察 | 面板 DAG 与进度卡状态一致 | L4 | P1 |
| TC-BIO-PROG-022 | FR-BIO-012 | 三选一按钮键盘可达 | failed | Tab 至重跑按钮按 Enter | 触发重跑 | L4 | P1 |
| TC-BIO-PROG-023 | FR-BIO-011 | 日志尾 max-height 滚动 | 日志 >6 行 | 检查 computed | max-height=96px;overflow-y=auto | L4 | P2 |
| TC-BIO-PROG-024 | FR-BIO-011 | 移动端不溢出 | 390×844 | 挂载 | 卡片/日志区宽度≤容器;无横向滚动 | L5-M | P1 |
### 6.1.13 ARCH 存档提示卡(flow-archive-card,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-ARCH-001 | FR-BIO-020 | 引导 UI 显示:存档提示 | 任务 job_done | 观察 | 对话出现「本次生信任务已完成,是否存档?可按你的要求命名并描述」12.5px | L4 | P0 |
| TC-BIO-ARCH-002 | FR-BIO-020 | 引导操作:命名输入 | 提示卡存在 | 输入名称 | input 接受文本;无长度异常 | L4 | P0 |
| TC-BIO-ARCH-003 | FR-BIO-020 | 引导操作:描述输入 | 同上 | 输入描述 | 描述值随提交发送 | L4 | P0 |
| TC-BIO-ARCH-004 | FR-BIO-020 | 引导操作:点存档 | 已命名 | 点「存档」 | 发出 POST /api/bioflow/archives;body 含 job_id/name/description | L4 | P0 |
| TC-BIO-ARCH-005 | FR-BIO-020 | 存档按钮样式 | 挂载 | 检查 | 「存档」--pa-gradient 12.5px/600;「放弃」pane-btn 同款 12px | L4 | P1 |
| TC-BIO-ARCH-006 | FR-BIO-020 | 引导操作:放弃 | 提示卡存在 | 点「放弃」 | 卡片消失;无 POST /api/bioflow/archives 请求;任务无副作用 | L4 | P0 |
| TC-BIO-ARCH-007 | FR-BIO-021 | 引导 UI 显示:存档状态回复 | 存档完成事件 | 观察 | 消息显示存档状态:名称/位置/大小三要素 | L4 | P0 |
| TC-BIO-ARCH-008 | FR-BIO-021 | 名称缺省提交拦截 | 名称空 | 点存档 | 按钮禁用或提交被拦截(不发出空 name 请求) | L4 | P1 |
| TC-BIO-ARCH-009 | FR-BIO-021 | 存档中加载态 | mock 慢 | 点存档 | 「存档」按钮 disabled+spinner;完成后恢复 | L4 | P1 |
| TC-BIO-ARCH-010 | FR-BIO-021 | 存档失败提示 | mock 500 | 点存档 | 错误文案;按钮恢复可重试 | L4 | P1 |
| TC-BIO-ARCH-011 | FR-BIO-020 | 放弃后不重复提示 | 已放弃 | 观察 | 同一任务不再弹存档提示(或仅一次) | L4 | P2 |
| TC-BIO-ARCH-012 | FR-BIO-020 | 任务未完成无提示 | 任务 running | 观察 | 无存档提示卡 | L4 | P1 |
### 6.1.14 JOB 生信任务面板(biojobs-pane,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-JOB-001 | FR-BIO-024 | 面板容器与 TAB | 服务可达 | 打开 | .biojobs-pane 存在;TAB 走 bench-tab 样式 | L4 | P0 |
| TC-BIO-JOB-002 | FR-BIO-024 | 任务列表渲染 | 3 任务 | 打开 | 3 个 session-item 形态列表项:标题 13px+状态徽章 | L4 | P0 |
| TC-BIO-JOB-003 | FR-BIO-024 | 多任务浏览流畅 | 25 任务 | 滚动列表 | 列表渲染流畅(虚拟滚动或分页);无卡顿崩溃 | L5-D | P1 |
| TC-BIO-JOB-004 | FR-BIO-024 | 阶段 DAG 渲染 | 选中任务 | 查看 | 纵向 2px hairline 连接线;节点 8px 圆点按阶段状态取色 | L4 | P0 |
| TC-BIO-JOB-005 | FR-BIO-024 | DAG 状态取色 | 1 done 1 failed 1 running | 查看 | 三节点颜色分别=done/error/相位色 | L4 | P1 |
| TC-BIO-JOB-006 | FR-BIO-024 | manifest/日志浏览 | 阶段 done | 打开 | code-block 渲染(mono 12px,code-bg,滚动);manifest 与日志尾均可读 | L4 | P0 |
| TC-BIO-JOB-007 | FR-BIO-024 | 重跑按钮 | 任务 failed | 点重跑 | 发出 rerun 请求;面板状态更新 | L4 | P0 |
| TC-BIO-JOB-008 | FR-BIO-024 | 删除任务 | 任务存在 | 点删除+确认 | 发出 DELETE;列表移除 | L4 | P1 |
| TC-BIO-JOB-009 | FR-BIO-024 | 运行中删除禁用 | 任务 running | 检查 | 删除按钮禁用(409 预期) | L4 | P1 |
| TC-BIO-JOB-010 | FR-BIO-024 | 空任务列表 | 无任务 | 打开 | 空态文案显示 | L4 | P2 |
| TC-BIO-JOB-011 | FR-BIO-024 | 任务详情实时更新 | 任务 running | 观察 | 面板状态随 SSE 事件实时刷新 | L4 | P0 |
| TC-BIO-JOB-012 | FR-BIO-025 | 探活失败隐藏 TAB | health 不可达 | 初始化 | 「生信任务」TAB 不渲染 | L4 | P0 |
| TC-BIO-JOB-013 | FR-BIO-025 | 探活恢复显示 TAB | health 恢复 | 刷新 | TAB 出现 | L4 | P0 |
| TC-BIO-JOB-014 | FR-BIO-024 | 移动端 TAB 条接入 | 390×844 | 打开 | 生信 TAB 出现在移动端 tab 条;TAB 数断言更新 | L5-M | P1 |
| TC-BIO-JOB-015 | FR-BIO-024 | 进度数字显示 | 任务 33% | 查看 | 列表/详情显示进度 33% | L4 | P1 |
| TC-BIO-JOB-016 | FR-BIO-024 | 日志尾 80 行上限显示 | 日志 200 行 | 查看 | 面板显示 80 行(后端截断后原样展示) | L4 | P1 |
### 6.1.15 PANE 生信档案面板(bioarchive-pane,L4)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-PANE-001 | FR-BIO-022 | 面板容器与 TAB | 服务可达 | 打开 | .bioarchive-pane 存在;TAB 走 bench-tab | L4 | P0 |
| TC-BIO-PANE-002 | FR-BIO-022 | 档案列表 | 3 归档 | 打开 | 3 个列表项(标题+状态徽章/时间)按时间倒序 | L4 | P0 |
| TC-BIO-PANE-003 | FR-BIO-022 | 档案详情回看 | 选中归档 | 点开 | 显示详情:阶段链/参数/产物文件清单/报告 | L4 | P0 |
| TC-BIO-PANE-004 | FR-BIO-022 | 报告产物查看 | 归档含报告 | 详情内 | 报告可预览(HTML 渲染或打开) | L4 | P0 |
| TC-BIO-PANE-005 | FR-BIO-022 | 中间文件清单 | 归档含中间文件 | 详情 | 产物清单含中间文件条目 | L4 | P1 |
| TC-BIO-PANE-006 | FR-BIO-022 | 删除归档 | 选中归档 | 点删除+确认 | 发出 DELETE;列表移除;磁盘目录删除 | L4 | P0 |
| TC-BIO-PANE-007 | FR-BIO-022 | 删除二次确认 | 归档存在 | 点删除→取消 | 无 DELETE 请求 | L4 | P1 |
| TC-BIO-PANE-008 | FR-BIO-023 | 复用发起按钮 | 选中归档 | 点「复用发起」 | 发出 POST archives/{id}/run 或打开复用表单 | L4 | P0 |
| TC-BIO-PANE-009 | FR-BIO-023 | 复用预填表单 | 复用发起后 | 观察 | 参数表单出现且预填=存档参数 | L4 | P0 |
| TC-BIO-PANE-010 | FR-BIO-023 | 复用发起新任务 | 预填确认 | 确认 | 新任务出现在生信任务面板 | L4 | P0 |
| TC-BIO-PANE-011 | FR-BIO-022 | 空档案列表 | 无归档 | 打开 | 空态文案显示 | L4 | P2 |
| TC-BIO-PANE-012 | FR-BIO-022 | 归档大小显示 | 归档 1.2GB | 列表 | 大小显示(人类可读格式) | L4 | P2 |
| TC-BIO-PANE-013 | FR-BIO-025 | 探活失败隐藏档案 TAB | health 不可达 | 初始化 | 「生信档案」TAB 不渲染 | L4 | P0 |
| TC-BIO-PANE-014 | FR-BIO-025 | 探活恢复显示档案 TAB | health 恢复 | 刷新 | TAB 出现 | L4 | P0 |
| TC-BIO-PANE-015 | FR-BIO-022 | 移动端面板可切换 | 390×844 | 切到档案 TAB | 面板正常显示;列表可滚动 | L5-M | P1 |
| TC-BIO-PANE-016 | FR-BIO-023 | 复用按钮键盘可达 | 选中归档 | Tab+Enter | 触发复用发起 | L4 | P2 |
### 6.1.16 ACT UI 动作矩阵(每条 TC = 一个可交互元素 × 一个动作;TEST_PLAN §10.3)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-ACT-001 | FR-BIO-002 | 路径卡候选行·点击 | 候选 2 条 | 点击候选行 | 选中态样式生效(border/背景变化);回调参数=该行索引 | L4 | P0 |
| TC-BIO-ACT-002 | FR-BIO-002 | 路径卡候选行·双击 | 未选中 | 双击候选行 | 视为两次点击:状态保持选中;不产生重复回调 | L4 | P1 |
| TC-BIO-ACT-003 | FR-BIO-002 | 路径卡候选行·悬停 | 未选中 | hover 行 | 背景=surface-3 | L4 | P0 |
| TC-BIO-ACT-004 | FR-BIO-002 | 路径卡候选行·悬停移出 | 悬停中 | mouseleave | 背景恢复 surface-1;选中态不丢 | L4 | P1 |
| TC-BIO-ACT-005 | FR-BIO-002 | 路径卡候选行·键盘 Enter | 行聚焦 | 按 Enter | 选中该行(同点击) | L4 | P0 |
| TC-BIO-ACT-006 | FR-BIO-002 | 路径卡候选行·键盘 Esc | 弹层/聚焦态 | 按 Esc | 关闭弹层或取消聚焦,不改变已确认状态 | L4 | P2 |
| TC-BIO-ACT-007 | FR-BIO-002 | 确认按钮·点击 | 已选中 | 点击 | 触发确认回调一次 | L4 | P0 |
| TC-BIO-ACT-008 | FR-BIO-002 | 确认按钮·双击 | 已选中 | 双击 | 只触发一次回调(防抖) | L4 | P1 |
| TC-BIO-ACT-009 | FR-BIO-002 | 确认按钮·悬停 | 未选中 | hover | 视觉反馈(渐变增亮);功能仍禁用 | L4 | P2 |
| TC-BIO-ACT-010 | FR-BIO-002 | 确认按钮·键盘 Enter | 按钮聚焦且已选中 | 按 Enter | 触发确认 | L4 | P0 |
| TC-BIO-ACT-011 | FR-BIO-002 | 确认按钮·键盘 Esc | 按钮聚焦 | 按 Esc | 取消聚焦;无确认 | L4 | P2 |
| TC-BIO-ACT-012 | FR-BIO-002 | 确认按钮·禁用态 | 未选中 | 检查 | disabled;opacity=0.45;点击无回调 | L4 | P0 |
| TC-BIO-ACT-013 | FR-BIO-002 | 确认按钮·加载中态 | 确认请求中(mock 慢) | 检查 | disabled;spinner 显示;再次点击无重复请求 | L4 | P0 |
| TC-BIO-ACT-014 | FR-BIO-008 | 表单输入框·点击聚焦 | input | 点击 | input 获得焦点;focus border=--pa-g-from | L4 | P0 |
| TC-BIO-ACT-015 | FR-BIO-008 | 表单输入框·失焦 | 聚焦中 | 点击别处 | blur 触发;边框恢复;若有校验立即提示 | L4 | P0 |
| TC-BIO-ACT-016 | FR-BIO-008 | 表单输入框·键盘 Enter | input 聚焦 | 按 Enter | 触发继续(提交) | L4 | P0 |
| TC-BIO-ACT-017 | FR-BIO-008 | 表单输入框·键盘 Esc | input 聚焦已改 | 按 Esc | 撤销本次编辑恢复原值或放弃(两态断言其一) | L4 | P1 |
| TC-BIO-ACT-018 | FR-BIO-008 | 表单输入框·禁用态 | 阶段已 running | 检查 | input disabled | L4 | P0 |
| TC-BIO-ACT-019 | FR-BIO-008 | 表单输入框·悬停 | 未聚焦 | hover | 边框 hairline 不变(仅 focus 变渐变) | L4 | P2 |
| TC-BIO-ACT-020 | FR-BIO-009 | 继续按钮·点击 | 已编辑 | 点击 | 发出 confirm;参数=表单值 | L4 | P0 |
| TC-BIO-ACT-021 | FR-BIO-009 | 继续按钮·双击 | 可提交 | 双击 | 仅一次请求(提交中禁用) | L4 | P1 |
| TC-BIO-ACT-022 | FR-BIO-009 | 继续按钮·悬停 | 可提交 | hover | 渐变增亮反馈 | L4 | P2 |
| TC-BIO-ACT-023 | FR-BIO-009 | 继续按钮·键盘 Enter | 按钮聚焦 | 按 Enter | 提交 | L4 | P0 |
| TC-BIO-ACT-024 | FR-BIO-009 | 继续按钮·键盘 Esc | 按钮聚焦 | 按 Esc | 取消聚焦;不提交 | L4 | P2 |
| TC-BIO-ACT-025 | FR-BIO-009 | 继续按钮·禁用态 | 校验不通过 | 检查 | disabled;点击无请求 | L4 | P0 |
| TC-BIO-ACT-026 | FR-BIO-009 | 继续按钮·加载中态 | 提交中 | 检查 | disabled+spinner | L4 | P0 |
| TC-BIO-ACT-027 | FR-BIO-010 | 自动连续开关·点击开 | 开关关 | 点击 | switch 状态=开;auto_continue=true 提交 | L4 | P0 |
| TC-BIO-ACT-028 | FR-BIO-010 | 自动连续开关·点击关 | 开关开 | 点击 | 状态=关;切回手动 | L4 | P0 |
| TC-BIO-ACT-029 | FR-BIO-010 | 自动连续开关·双击 | 关 | 双击 | 最终状态=开(两次切换);无异常 | L4 | P2 |
| TC-BIO-ACT-030 | FR-BIO-010 | 自动连续开关·悬停 | 任意 | hover | 光标指针/背景反馈;不切换状态 | L4 | P2 |
| TC-BIO-ACT-031 | FR-BIO-010 | 自动连续开关·键盘 Enter | 开关聚焦 | 按 Enter | 切换状态 | L4 | P1 |
| TC-BIO-ACT-032 | FR-BIO-010 | 自动连续开关·键盘 Esc | 开关聚焦 | 按 Esc | 取消聚焦;状态不变 | L4 | P2 |
| TC-BIO-ACT-033 | FR-BIO-010 | 自动连续开关·禁用态 | 任务已暂停/未开始 | 检查 | disabled(按实现两态断言其一) | L4 | P1 |
| TC-BIO-ACT-034 | FR-BIO-006 | 拖放区·点击 | 未选择 | 点击 | 打开文件选择框(file input 触发) | L4 | P0 |
| TC-BIO-ACT-035 | FR-BIO-006 | 拖放区·悬停 | 未拖入 | hover | 样式不变(非拖入态) | L4 | P1 |
| TC-BIO-ACT-036 | FR-BIO-006 | 拖放区·拖入悬停 | 拖拽悬停中 | dragover | 拖入态:border=gradient 45%;背景=gradient 8% | L4 | P0 |
| TC-BIO-ACT-037 | FR-BIO-006 | 拖放区·离开 | 拖入中 | dragleave | 拖入态移除,恢复 dashed hairline-strong | L4 | P0 |
| TC-BIO-ACT-038 | FR-BIO-006 | 拖放区·拖入释放 | 拖入文件 | drop | 触发上传(POST multipart);进度出现 | L4 | P0 |
| TC-BIO-ACT-039 | FR-BIO-006 | 拖放区·禁用态 | 上传进行中 | 检查 | 再拖入不触发(忽略/禁用) | L4 | P0 |
| TC-BIO-ACT-040 | FR-BIO-006 | 拖放区·加载中态 | 上传中 | 检查 | 进度条可见;拖放区提示变化(百分比) | L4 | P0 |
| TC-BIO-ACT-041 | FR-BIO-007 | 路径输入行·点击聚焦 | input | 点击 | 焦点获得;边框渐变 | L4 | P0 |
| TC-BIO-ACT-042 | FR-BIO-007 | 路径输入行·失焦 | 聚焦中 | 移开 | 边框恢复 | L4 | P1 |
| TC-BIO-ACT-043 | FR-BIO-007 | 路径输入行·键盘 Enter | 已输入路径 | 按 Enter | 触发登记(同点按钮) | L4 | P0 |
| TC-BIO-ACT-044 | FR-BIO-007 | 路径输入行·键盘 Esc | 聚焦已输入 | 按 Esc | 清空输入或取消(两态断言其一) | L4 | P2 |
| TC-BIO-ACT-045 | FR-BIO-007 | 登记路径按钮·点击 | 合法路径 | 点击 | 发出登记请求 | L4 | P0 |
| TC-BIO-ACT-046 | FR-BIO-007 | 登记路径按钮·悬停 | 任意 | hover | pane-btn 悬停反馈;不触发请求 | L4 | P2 |
| TC-BIO-ACT-047 | FR-BIO-007 | 登记路径按钮·键盘 Enter | 按钮聚焦 | 按 Enter | 触发登记 | L4 | P1 |
| TC-BIO-ACT-048 | FR-BIO-007 | 登记路径按钮·禁用态 | input 空 | 检查 | disabled;点击无请求 | L4 | P0 |
| TC-BIO-ACT-049 | FR-BIO-007 | 登记路径按钮·加载中态 | 登记请求中 | 检查 | disabled+spinner | L4 | P1 |
| TC-BIO-ACT-050 | FR-BIO-012 | 重跑按钮·点击 | 阶段 failed | 点击 | 发出 rerun 请求 | L4 | P0 |
| TC-BIO-ACT-051 | FR-BIO-012 | 跳过按钮·点击 | 阶段 failed | 点击 | 发出 skip 请求;状态=skipped | L4 | P0 |
| TC-BIO-ACT-052 | FR-BIO-012 | 改参数重跑按钮·点击 | 阶段 failed | 点击 | 弹出该阶段参数表单 | L4 | P0 |
| TC-BIO-ACT-053 | FR-BIO-012 | 三选一按钮·悬停 | 阶段 failed | hover 每个按钮 | pane-btn 悬停反馈 | L4 | P2 |
| TC-BIO-ACT-054 | FR-BIO-012 | 三选一按钮·键盘 Enter | 重跑按钮聚焦 | 按 Enter | 触发重跑 | L4 | P0 |
| TC-BIO-ACT-055 | FR-BIO-012 | 三选一按钮·键盘 Esc | 改参数表单弹出 | 按 Esc | 表单关闭,不提交 | L4 | P1 |
| TC-BIO-ACT-056 | FR-BIO-012 | 三选一按钮·加载中态 | 重跑请求中 | 检查 | 三按钮 disabled | L4 | P1 |
| TC-BIO-ACT-057 | FR-BIO-012 | 三选一按钮·禁用态 | 阶段非 failed | 检查 | 按钮不渲染(仅 failed 显示) | L4 | P0 |
| TC-BIO-ACT-058 | FR-BIO-013 | 折叠组头·点击 | 15 阶段链折叠组 | 点击组头 | 展开/收起切换;箭头方向变化 | L4 | P0 |
| TC-BIO-ACT-059 | FR-BIO-013 | 折叠组头·双击 | 折叠组 | 双击 | 最终状态=与初始相反(两次切换) | L4 | P2 |
| TC-BIO-ACT-060 | FR-BIO-013 | 折叠组头·悬停 | 折叠组 | hover | 组头悬停反馈 | L4 | P2 |
| TC-BIO-ACT-061 | FR-BIO-013 | 折叠组头·键盘 Enter | 组头聚焦 | 按 Enter | 切换展开/收起 | L4 | P1 |
| TC-BIO-ACT-062 | FR-BIO-013 | 折叠组头·键盘 Esc | 展开中 | 按 Esc | 收起(或保持,两态断言其一) | L4 | P2 |
| TC-BIO-ACT-063 | FR-BIO-024 | 面板操作按钮(重跑)·点击 | 任务 failed | 点击 | 发出 rerun | L4 | P0 |
| TC-BIO-ACT-064 | FR-BIO-024 | 面板操作按钮(删除)·点击 | 任务存在 | 点击 | 弹确认层 | L4 | P0 |
| TC-BIO-ACT-065 | FR-BIO-024 | 面板操作按钮·悬停 | 任务行 | hover | pane-btn 悬停反馈 | L4 | P2 |
| TC-BIO-ACT-066 | FR-BIO-024 | 面板操作按钮·键盘 Enter | 删除按钮聚焦 | 按 Enter | 弹确认层 | L4 | P1 |
| TC-BIO-ACT-067 | FR-BIO-024 | 面板操作按钮·键盘 Esc | 确认层弹出 | 按 Esc | 关闭确认层不删除 | L4 | P1 |
| TC-BIO-ACT-068 | FR-BIO-024 | 面板操作按钮·禁用态 | 任务 running | 检查删除按钮 | disabled | L4 | P0 |
| TC-BIO-ACT-069 | FR-BIO-024 | 面板操作按钮·加载中态 | 重跑请求中 | 检查 | disabled+spinner | L4 | P1 |
| TC-BIO-ACT-070 | FR-BIO-023 | 面板复用发起按钮·点击 | 选中归档 | 点击 | 打开复用表单(预填) | L4 | P0 |
| TC-BIO-ACT-071 | FR-BIO-023 | 面板复用发起按钮·悬停 | 选中归档 | hover | 悬停反馈 | L4 | P2 |
| TC-BIO-ACT-072 | FR-BIO-023 | 面板复用发起按钮·键盘 Enter | 按钮聚焦 | 按 Enter | 打开复用表单 | L4 | P1 |
| TC-BIO-ACT-073 | FR-BIO-023 | 面板复用发起按钮·加载中态 | 表单加载中 | 检查 | disabled+spinner | L4 | P1 |
| TC-BIO-ACT-074 | FR-BIO-020 | 存档名称输入·点击聚焦 | 存档提示卡 | 点击 | 焦点;边框渐变 | L4 | P0 |
| TC-BIO-ACT-075 | FR-BIO-020 | 存档名称输入·失焦 | 聚焦中 | 移开 | 边框恢复 | L4 | P1 |
| TC-BIO-ACT-076 | FR-BIO-020 | 存档名称输入·键盘 Enter | 已输入名称 | 按 Enter | 触发存档 | L4 | P0 |
| TC-BIO-ACT-077 | FR-BIO-020 | 存档名称输入·键盘 Esc | 聚焦中 | 按 Esc | 清空或取消(两态断言其一) | L4 | P2 |
| TC-BIO-ACT-078 | FR-BIO-020 | 存档名称输入·禁用态 | 存档请求中 | 检查 | disabled | L4 | P0 |
| TC-BIO-ACT-079 | FR-BIO-020 | 存档按钮·点击 | 已命名 | 点击 | 发出 POST archives | L4 | P0 |
| TC-BIO-ACT-080 | FR-BIO-020 | 存档按钮·双击 | 可提交 | 双击 | 仅一次请求 | L4 | P1 |
| TC-BIO-ACT-081 | FR-BIO-020 | 存档按钮·悬停 | 可提交 | hover | 渐变增亮 | L4 | P2 |
| TC-BIO-ACT-082 | FR-BIO-020 | 存档按钮·键盘 Enter | 按钮聚焦 | 按 Enter | 触发存档 | L4 | P1 |
| TC-BIO-ACT-083 | FR-BIO-020 | 存档按钮·禁用态 | 名称空 | 检查 | disabled | L4 | P0 |
| TC-BIO-ACT-084 | FR-BIO-020 | 存档按钮·加载中态 | 存档中 | 检查 | disabled+spinner | L4 | P0 |
| TC-BIO-ACT-085 | FR-BIO-020 | 放弃按钮·点击 | 存档提示卡 | 点击 | 卡片消失;无请求 | L4 | P0 |
| TC-BIO-ACT-086 | FR-BIO-020 | 放弃按钮·悬停 | 提示卡 | hover | pane-btn 悬停反馈 | L4 | P2 |
| TC-BIO-ACT-087 | FR-BIO-020 | 放弃按钮·键盘 Enter | 按钮聚焦 | 按 Enter | 放弃(卡片消失) | L4 | P1 |
| TC-BIO-ACT-088 | FR-BIO-020 | 放弃按钮·键盘 Esc | 按钮聚焦 | 按 Esc | 取消聚焦;卡片保留 | L4 | P2 |
| TC-BIO-ACT-089 | FR-BIO-020 | 放弃按钮·加载中态 | 存档请求中 | 检查 | 放弃按钮 disabled(防误操作) | L4 | P1 |
| TC-BIO-ACT-090 | FR-BIO-024 | 面板列表项·点击 | 任务列表 | 点击任务项 | 选中并展开详情(DAG 显示) | L4 | P0 |
| TC-BIO-ACT-091 | FR-BIO-024 | 面板列表项·悬停 | 列表 | hover | session-item 悬停反馈 | L4 | P1 |
| TC-BIO-ACT-092 | FR-BIO-022 | 档案列表项·点击 | 档案列表 | 点击 | 选中并显示详情 | L4 | P0 |
| TC-BIO-ACT-093 | FR-BIO-022 | 档案列表项·悬停 | 列表 | hover | 悬停反馈 | L4 | P1 |
| TC-BIO-ACT-094 | FR-BIO-011 | 进度卡日志区·点击滚动 | 日志溢出 | 点击日志区 | 区域获得焦点可滚动;不触发其他动作 | L4 | P2 |
| TC-BIO-ACT-095 | FR-BIO-011 | 进度卡日志区·悬停 | 日志溢出 | hover | 显示滚动条/悬停反馈 | L4 | P2 |
#### 6.1.17 E2E 端到端主线(TEST_PLAN §11 九条 × 三档视口 M/T/D)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-E2E-001-M | FR-BIO-002/004 | E2E-01 主流程·移动端:候选路径卡出现 | mock LLM 正常;390×844 | 发送「帮我跑水稻 SPL 家族鉴定」 | 对话出现 .flow-path-card;候选行数量∈[2,3];每行含阶段序列文本 | L5-M | P0 |
| TC-BIO-E2E-002-M | FR-BIO-004 | E2E-01 主流程·移动端:点选与确认 | 候选卡已出现 | 点击第 1 候选行→点「确认此路径」 | 路径确认卡出现(逐阶段名称/用途/预计耗时);发出 POST /api/bioflow/jobs | L5-M | P0 |
| TC-BIO-E2E-003-M | FR-BIO-004 | E2E-01 主流程·移动端:任务面板出现新任务 | 任务已创建 | 切到「生信任务」TAB | 列表含新任务;状态=created | L5-M | P0 |
| TC-BIO-E2E-004-M | FR-BIO-005 | E2E-01 主流程·移动端:文件引导卡 | 起始阶段缺 fasta | 等待推进 | 对话出现缺文件提示(点名 fasta)+ .flow-file-card | L5-M | P0 |
| TC-BIO-E2E-005-M | FR-BIO-006 | E2E-01 主流程·移动端:拖拽上传金标数据 | 本地金标输入可用 | 拖入 Ft.SPL pep 文件 | 进度条百分比逐级推进至 100%;POST files 发出 | L5-M | P0 |
| TC-BIO-E2E-006-M | FR-BIO-008/009 | E2E-01 主流程·移动端:参数表单改一个参数 | 阶段待确认 | 表单卡出现后改 cpu=8→点「继续」 | 发出 confirm;请求体 params.cpu=8;阶段 running | L5-M | P0 |
| TC-BIO-E2E-007-M | FR-BIO-011 | E2E-01 主流程·移动端:进度卡逐阶段流转 | mock 全链 | 观察 | 状态点逐阶段点亮(waiting→running→done);运行中日志尾滚动更新 | L5-M | P0 |
| TC-BIO-E2E-008-M | FR-BIO-016 | E2E-01 主流程·移动端:报告预览 | 任务完成报告登记 | 切文档 TAB 打开 DocPane | 报告出现;预览白底(background=#FFFFFF);图可见 | L5-M | P0 |
| TC-BIO-E2E-009-M | FR-BIO-018 | E2E-01 主流程·移动端:导出 PDF | 报告已打开 | 点导出 PDF | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-M | P1 |
| TC-BIO-E2E-010-M | FR-BIO-020/021 | E2E-01 主流程·移动端:存档提示→存档→状态回复 | 任务完成 | 观察提示卡→输入名称→点存档 | POST archives 发出;回复消息含名称/位置/大小三要素 | L5-M | P0 |
| TC-BIO-E2E-011-M | FR-BIO-024 | E2E-01 主流程·移动端:档案面板出现 | 已存档 | 切「生信档案」TAB | 列表含新档案(名称正确) | L5-M | P0 |
| TC-BIO-E2E-012-M | FR-BIO-027 | E2E-01 主流程·移动端:布局不溢出 | 全程 | 观察各步骤 | .flow-path-card/.flow-form-card/.flow-file-card/.bioflow-progress-card 宽≤容器;无横向滚动 | L5-M | P1 |
| TC-BIO-E2E-001-T | FR-BIO-002/004 | E2E-01 主流程·平板:候选路径卡出现 | mock LLM 正常;768×1024 | 发送「帮我跑水稻 SPL 家族鉴定」 | 对话出现 .flow-path-card;候选行数量∈[2,3];每行含阶段序列文本 | L5-T | P0 |
| TC-BIO-E2E-002-T | FR-BIO-004 | E2E-01 主流程·平板:点选与确认 | 候选卡已出现 | 点击第 1 候选行→点「确认此路径」 | 路径确认卡出现(逐阶段名称/用途/预计耗时);发出 POST /api/bioflow/jobs | L5-T | P0 |
| TC-BIO-E2E-003-T | FR-BIO-004 | E2E-01 主流程·平板:任务面板出现新任务 | 任务已创建 | 切到「生信任务」TAB | 列表含新任务;状态=created | L5-T | P0 |
| TC-BIO-E2E-004-T | FR-BIO-005 | E2E-01 主流程·平板:文件引导卡 | 起始阶段缺 fasta | 等待推进 | 对话出现缺文件提示(点名 fasta)+ .flow-file-card | L5-T | P0 |
| TC-BIO-E2E-005-T | FR-BIO-006 | E2E-01 主流程·平板:拖拽上传金标数据 | 本地金标输入可用 | 拖入 Ft.SPL pep 文件 | 进度条百分比逐级推进至 100%;POST files 发出 | L5-T | P0 |
| TC-BIO-E2E-006-T | FR-BIO-008/009 | E2E-01 主流程·平板:参数表单改一个参数 | 阶段待确认 | 表单卡出现后改 cpu=8→点「继续」 | 发出 confirm;请求体 params.cpu=8;阶段 running | L5-T | P0 |
| TC-BIO-E2E-007-T | FR-BIO-011 | E2E-01 主流程·平板:进度卡逐阶段流转 | mock 全链 | 观察 | 状态点逐阶段点亮(waiting→running→done);运行中日志尾滚动更新 | L5-T | P0 |
| TC-BIO-E2E-008-T | FR-BIO-016 | E2E-01 主流程·平板:报告预览 | 任务完成报告登记 | 切文档 TAB 打开 DocPane | 报告出现;预览白底(background=#FFFFFF);图可见 | L5-T | P0 |
| TC-BIO-E2E-009-T | FR-BIO-018 | E2E-01 主流程·平板:导出 PDF | 报告已打开 | 点导出 PDF | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-T | P1 |
| TC-BIO-E2E-010-T | FR-BIO-020/021 | E2E-01 主流程·平板:存档提示→存档→状态回复 | 任务完成 | 观察提示卡→输入名称→点存档 | POST archives 发出;回复消息含名称/位置/大小三要素 | L5-T | P0 |
| TC-BIO-E2E-011-T | FR-BIO-024 | E2E-01 主流程·平板:档案面板出现 | 已存档 | 切「生信档案」TAB | 列表含新档案(名称正确) | L5-T | P0 |
| TC-BIO-E2E-012-T | FR-BIO-027 | E2E-01 主流程·平板:布局不溢出 | 全程 | 观察各步骤 | .flow-path-card/.flow-form-card/.flow-file-card/.bioflow-progress-card 宽≤容器;无横向滚动 | L5-T | P1 |
| TC-BIO-E2E-001-D | FR-BIO-002/004 | E2E-01 主流程·桌面:候选路径卡出现 | mock LLM 正常;1440×900 | 发送「帮我跑水稻 SPL 家族鉴定」 | 对话出现 .flow-path-card;候选行数量∈[2,3];每行含阶段序列文本 | L5-D | P0 |
| TC-BIO-E2E-002-D | FR-BIO-004 | E2E-01 主流程·桌面:点选与确认 | 候选卡已出现 | 点击第 1 候选行→点「确认此路径」 | 路径确认卡出现(逐阶段名称/用途/预计耗时);发出 POST /api/bioflow/jobs | L5-D | P0 |
| TC-BIO-E2E-003-D | FR-BIO-004 | E2E-01 主流程·桌面:任务面板出现新任务 | 任务已创建 | 切到「生信任务」TAB | 列表含新任务;状态=created | L5-D | P0 |
| TC-BIO-E2E-004-D | FR-BIO-005 | E2E-01 主流程·桌面:文件引导卡 | 起始阶段缺 fasta | 等待推进 | 对话出现缺文件提示(点名 fasta)+ .flow-file-card | L5-D | P0 |
| TC-BIO-E2E-005-D | FR-BIO-006 | E2E-01 主流程·桌面:拖拽上传金标数据 | 本地金标输入可用 | 拖入 Ft.SPL pep 文件 | 进度条百分比逐级推进至 100%;POST files 发出 | L5-D | P0 |
| TC-BIO-E2E-006-D | FR-BIO-008/009 | E2E-01 主流程·桌面:参数表单改一个参数 | 阶段待确认 | 表单卡出现后改 cpu=8→点「继续」 | 发出 confirm;请求体 params.cpu=8;阶段 running | L5-D | P0 |
| TC-BIO-E2E-007-D | FR-BIO-011 | E2E-01 主流程·桌面:进度卡逐阶段流转 | mock 全链 | 观察 | 状态点逐阶段点亮(waiting→running→done);运行中日志尾滚动更新 | L5-D | P0 |
| TC-BIO-E2E-008-D | FR-BIO-016 | E2E-01 主流程·桌面:报告预览 | 任务完成报告登记 | 切文档 TAB 打开 DocPane | 报告出现;预览白底(background=#FFFFFF);图可见 | L5-D | P0 |
| TC-BIO-E2E-009-D | FR-BIO-018 | E2E-01 主流程·桌面:导出 PDF | 报告已打开 | 点导出 PDF | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-D | P1 |
| TC-BIO-E2E-010-D | FR-BIO-020/021 | E2E-01 主流程·桌面:存档提示→存档→状态回复 | 任务完成 | 观察提示卡→输入名称→点存档 | POST archives 发出;回复消息含名称/位置/大小三要素 | L5-D | P0 |
| TC-BIO-E2E-011-D | FR-BIO-024 | E2E-01 主流程·桌面:档案面板出现 | 已存档 | 切「生信档案」TAB | 列表含新档案(名称正确) | L5-D | P0 |
| TC-BIO-E2E-012-D | FR-BIO-027 | E2E-01 主流程·桌面:布局不溢出 | 全程 | 观察各步骤 | .flow-path-card/.flow-form-card/.flow-file-card/.bioflow-progress-card 宽≤容器;无横向滚动 | L5-D | P1 |
| TC-BIO-E2E-013-M | FR-BIO-010 | E2E-02 自动连续·移动端 | mock 全链 | 开启自动连续开关→发起任务→中途暂停 | 阶段间无表单卡自动推进;暂停后停在下一阶段前(该阶段 waiting_confirm) | L5-M | P0 |
| TC-BIO-E2E-013-T | FR-BIO-010 | E2E-02 自动连续·平板 | mock 全链 | 同上 | 同上断言 | L5-T | P0 |
| TC-BIO-E2E-013-D | FR-BIO-010 | E2E-02 自动连续·桌面 | mock 全链 | 同上 | 同上断言 | L5-D | P0 |
| TC-BIO-E2E-014-M | FR-BIO-012 | E2E-03 失败注入·移动端:三选一 | mock 阶段 2 失败 | 推进至失败 | 进度卡标红(--pa-error ✕);三按钮出现 | L5-M | P0 |
| TC-BIO-E2E-015-M | FR-BIO-012 | E2E-03 失败注入·移动端:重跑成功 | 阶段 failed | 点重跑(mock 转成功) | 状态转 running→done | L5-M | P0 |
| TC-BIO-E2E-016-M | FR-BIO-012 | E2E-03 失败注入·移动端:跳过生效 | 阶段 failed | 点跳过 | 状态=skipped;后续阶段推进 | L5-M | P0 |
| TC-BIO-E2E-017-M | FR-BIO-012 | E2E-03 失败注入·移动端:改参数重跑 | 阶段 failed | 点改参数重跑→改参数→继续 | 表单出现;按新参数重跑成功 | L5-M | P0 |
| TC-BIO-E2E-014-T | FR-BIO-012 | E2E-03 失败注入·平板:三选一 | mock 阶段 2 失败 | 推进至失败 | 进度卡标红(--pa-error ✕);三按钮出现 | L5-T | P0 |
| TC-BIO-E2E-015-T | FR-BIO-012 | E2E-03 失败注入·平板:重跑成功 | 阶段 failed | 点重跑(mock 转成功) | 状态转 running→done | L5-T | P0 |
| TC-BIO-E2E-016-T | FR-BIO-012 | E2E-03 失败注入·平板:跳过生效 | 阶段 failed | 点跳过 | 状态=skipped;后续阶段推进 | L5-T | P0 |
| TC-BIO-E2E-017-T | FR-BIO-012 | E2E-03 失败注入·平板:改参数重跑 | 阶段 failed | 点改参数重跑→改参数→继续 | 表单出现;按新参数重跑成功 | L5-T | P0 |
| TC-BIO-E2E-014-D | FR-BIO-012 | E2E-03 失败注入·桌面:三选一 | mock 阶段 2 失败 | 推进至失败 | 进度卡标红(--pa-error ✕);三按钮出现 | L5-D | P0 |
| TC-BIO-E2E-015-D | FR-BIO-012 | E2E-03 失败注入·桌面:重跑成功 | 阶段 failed | 点重跑(mock 转成功) | 状态转 running→done | L5-D | P0 |
| TC-BIO-E2E-016-D | FR-BIO-012 | E2E-03 失败注入·桌面:跳过生效 | 阶段 failed | 点跳过 | 状态=skipped;后续阶段推进 | L5-D | P0 |
| TC-BIO-E2E-017-D | FR-BIO-012 | E2E-03 失败注入·桌面:改参数重跑 | 阶段 failed | 点改参数重跑→改参数→继续 | 表单出现;按新参数重跑成功 | L5-D | P0 |
| TC-BIO-E2E-018-M | FR-BIO-014 | E2E-04 断线回放·移动端 | 任务 3 阶段执行中 | 切断 SSE 30s→重连 | 进度卡恢复断线前状态;无进度丢失;日志尾恢复 | L5-M | P0 |
| TC-BIO-E2E-018-T | FR-BIO-014 | E2E-04 断线回放·平板 | 任务 3 阶段执行中 | 切断 SSE 30s→重连 | 进度卡恢复断线前状态;无进度丢失;日志尾恢复 | L5-T | P0 |
| TC-BIO-E2E-018-D | FR-BIO-014 | E2E-04 断线回放·桌面 | 任务 3 阶段执行中 | 切断 SSE 30s→重连 | 进度卡恢复断线前状态;无进度丢失;日志尾恢复 | L5-D | P0 |
| TC-BIO-E2E-019-M | FR-BIO-023 | E2E-05 存档复用·移动端 | 归档 XXX 存在 | 发送「用 XXX 存档任务的方法帮我跑玉米 bZIP」→确认预填表单→执行 | 表单预填=XXX 参数(来源标注 XXX);新任务按此参数执行 | L5-M | P0 |
| TC-BIO-E2E-019-T | FR-BIO-023 | E2E-05 存档复用·平板 | 归档 XXX 存在 | 同上 | 同上断言 | L5-T | P0 |
| TC-BIO-E2E-019-D | FR-BIO-023 | E2E-05 存档复用·桌面 | 归档 XXX 存在 | 同上 | 同上断言 | L5-D | P0 |
| TC-BIO-E2E-020-M | FR-BIO-025 | E2E-06 探活显隐·移动端 | 同部署 mock | 停 8098→刷新 | 「生信任务/生信档案」TAB 与生信块分支消失;恢复 8098→刷新→出现 | L5-M | P0 |
| TC-BIO-E2E-020-T | FR-BIO-025 | E2E-06 探活显隐·平板 | 同部署 mock | 停 8098→刷新 | 「生信任务/生信档案」TAB 与生信块分支消失;恢复 8098→刷新→出现 | L5-T | P0 |
| TC-BIO-E2E-020-D | FR-BIO-025 | E2E-06 探活显隐·桌面 | 同部署 mock | 停 8098→刷新 | 「生信任务/生信档案」TAB 与生信块分支消失;恢复 8098→刷新→出现 | L5-D | P0 |
| TC-BIO-E2E-021-M | FR-BIO-019 | E2E-07 图表调整·移动端 | 报告含图1 | 发送「图1 颜色换成红色」 | 触发绘图阶段重跑;新图回填报告;预览刷新(颜色变化) | L5-M | P0 |
| TC-BIO-E2E-021-T | FR-BIO-019 | E2E-07 图表调整·平板 | 报告含图1 | 发送「图1 颜色换成红色」 | 触发绘图阶段重跑;新图回填报告;预览刷新(颜色变化) | L5-T | P0 |
| TC-BIO-E2E-021-D | FR-BIO-019 | E2E-07 图表调整·桌面 | 报告含图1 | 发送「图1 颜色换成红色」 | 触发绘图阶段重跑;新图回填报告;预览刷新(颜色变化) | L5-D | P0 |
| TC-BIO-E2E-022-M | FR-BIO-026 | E2E-08 知识库问答·移动端 | flow_docs 已入库;生信会话 | 发送「identify 需要什么输入」 | 答案含引用块(源文件+章节);点引用跳转原文 | L5-M | P0 |
| TC-BIO-E2E-022-T | FR-BIO-026 | E2E-08 知识库问答·平板 | flow_docs 已入库;生信会话 | 发送「identify 需要什么输入」 | 答案含引用块(源文件+章节);点引用跳转原文 | L5-T | P0 |
| TC-BIO-E2E-022-D | FR-BIO-026 | E2E-08 知识库问答·桌面 | flow_docs 已入库;生信会话 | 发送「identify 需要什么输入」 | 答案含引用块(源文件+章节);点引用跳转原文 | L5-D | P0 |
| TC-BIO-E2E-023-M | FR-BIO-027 | E2E-09 三档视口·移动端布局 | 390×844;进度卡/面板可见 | 观察五卡片+两面板 | 卡片/面板/进度卡不溢出;触控目标≥44px(按钮/候选行命中区) | L5-M | P0 |
| TC-BIO-E2E-023-T | FR-BIO-027 | E2E-09 三档视口·平板布局 | 768×1024;进度卡/面板可见 | 观察五卡片+两面板 | 卡片/面板/进度卡不溢出;面板可切换 | L5-T | P0 |
| TC-BIO-E2E-023-D | FR-BIO-027 | E2E-09 三档视口·桌面布局 | 1440×900;进度卡/面板可见 | 观察五卡片+两面板 | 卡片/面板/进度卡不溢出;面板可切换 | L5-D | P0 |
| TC-BIO-E2E-024-M | FR-BIO-018 | E2E-01 主流程·移动端:导出 DOCX | 报告已打开 | 点导出 DOCX | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-M | P1 |
| TC-BIO-E2E-024-T | FR-BIO-018 | E2E-01 主流程·平板:导出 DOCX | 报告已打开 | 点导出 DOCX | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-T | P1 |
| TC-BIO-E2E-024-D | FR-BIO-018 | E2E-01 主流程·桌面:导出 DOCX | 报告已打开 | 点导出 DOCX | 下载事件触发;文件落盘且可打开(非 0 字节) | L5-D | P1 |
| TC-BIO-E2E-025-M | FR-BIO-001 | E2E 漏判安全·移动端 | mock | 发送「什么是基因家族」 | 走 qa 流;无 .flow-path-card;无 bioflow 请求 | L5-M | P0 |
| TC-BIO-E2E-025-T | FR-BIO-001 | E2E 漏判安全·平板 | mock | 发送「什么是基因家族」 | 走 qa 流;无 .flow-path-card;无 bioflow 请求 | L5-T | P0 |
| TC-BIO-E2E-025-D | FR-BIO-001 | E2E 漏判安全·桌面 | mock | 发送「什么是基因家族」 | 走 qa 流;无 .flow-path-card;无 bioflow 请求 | L5-D | P0 |
| TC-BIO-E2E-026-M | FR-BIO-007 | E2E 服务器路径登记·移动端 | 任务待文件 | 文件卡路径输入行输入合法路径→点登记 | 登记成功显示登记项;阶段推进 | L5-M | P1 |
| TC-BIO-E2E-026-T | FR-BIO-007 | E2E 服务器路径登记·平板 | 任务待文件 | 文件卡路径输入行输入合法路径→点登记 | 登记成功显示登记项;阶段推进 | L5-T | P1 |
| TC-BIO-E2E-026-D | FR-BIO-007 | E2E 服务器路径登记·桌面 | 任务待文件 | 文件卡路径输入行输入合法路径→点登记 | 登记成功显示登记项;阶段推进 | L5-D | P1 |
| TC-BIO-E2E-027-M | FR-BIO-010 | E2E-02 暂停恢复·移动端 | 任务暂停中 | 点恢复 | 从下一阶段继续执行 | L5-M | P0 |
| TC-BIO-E2E-027-T | FR-BIO-010 | E2E-02 暂停恢复·平板 | 任务暂停中 | 点恢复 | 从下一阶段继续执行 | L5-T | P0 |
| TC-BIO-E2E-027-D | FR-BIO-010 | E2E-02 暂停恢复·桌面 | 任务暂停中 | 点恢复 | 从下一阶段继续执行 | L5-D | P0 |
| TC-BIO-E2E-028-M | FR-BIO-017 | E2E 报告编辑·移动端 | 报告已打开 | 就地改文字→保存 | 文字更新落盘(刷新后仍在);走既有编辑链路 | L5-M | P1 |
| TC-BIO-E2E-028-T | FR-BIO-017 | E2E 报告编辑·平板 | 报告已打开 | 就地改文字→保存 | 文字更新落盘(刷新后仍在);走既有编辑链路 | L5-T | P1 |
| TC-BIO-E2E-028-D | FR-BIO-017 | E2E 报告编辑·桌面 | 报告已打开 | 就地改文字→保存 | 文字更新落盘(刷新后仍在);走既有编辑链路 | L5-D | P1 |
| TC-BIO-E2E-029-M | FR-BIO-024 | E2E 任务面板 DAG·移动端 | 任务 3 阶段 | 打开任务详情 | 纵向连接线渲染;3 节点圆点按状态取色 | L5-M | P1 |
| TC-BIO-E2E-029-T | FR-BIO-024 | E2E 任务面板 DAG·平板 | 任务 3 阶段 | 打开任务详情 | 纵向连接线渲染;3 节点圆点按状态取色 | L5-T | P1 |
| TC-BIO-E2E-029-D | FR-BIO-024 | E2E 任务面板 DAG·桌面 | 任务 3 阶段 | 打开任务详情 | 纵向连接线渲染;3 节点圆点按状态取色 | L5-D | P1 |
| TC-BIO-E2E-030-M | FR-BIO-022 | E2E 档案回看·移动端 | 归档存在 | 档案面板打开归档详情 | 详情显示阶段链/参数/产物/报告 | L5-M | P1 |
| TC-BIO-E2E-030-T | FR-BIO-022 | E2E 档案回看·平板 | 归档存在 | 档案面板打开归档详情 | 详情显示阶段链/参数/产物/报告 | L5-T | P1 |
| TC-BIO-E2E-030-D | FR-BIO-022 | E2E 档案回看·桌面 | 归档存在 | 档案面板打开归档详情 | 详情显示阶段链/参数/产物/报告 | L5-D | P1 |
| TC-BIO-E2E-031-M | FR-BIO-020 | E2E 放弃存档·移动端 | 存档提示卡出现 | 点「放弃」 | 卡片消失;无 POST /api/bioflow/archives;任务保持 done 无副作用 | L5-M | P1 |
| TC-BIO-E2E-031-T | FR-BIO-020 | E2E 放弃存档·平板 | 存档提示卡出现 | 点「放弃」 | 卡片消失;无 POST /api/bioflow/archives;任务保持 done 无副作用 | L5-T | P1 |
| TC-BIO-E2E-031-D | FR-BIO-020 | E2E 放弃存档·桌面 | 存档提示卡出现 | 点「放弃」 | 卡片消失;无 POST /api/bioflow/archives;任务保持 done 无副作用 | L5-D | P1 |
| TC-BIO-E2E-032-M | FR-BIO-023 | E2E 面板复用发起·移动端 | 归档存在 | 档案面板→选中→点复用发起→确认 | 表单预填=归档参数;新任务入生信任务面板 | L5-M | P1 |
| TC-BIO-E2E-032-T | FR-BIO-023 | E2E 面板复用发起·平板 | 归档存在 | 档案面板→选中→点复用发起→确认 | 表单预填=归档参数;新任务入生信任务面板 | L5-T | P1 |
| TC-BIO-E2E-032-D | FR-BIO-023 | E2E 面板复用发起·桌面 | 归档存在 | 档案面板→选中→点复用发起→确认 | 表单预填=归档参数;新任务入生信任务面板 | L5-D | P1 |
| TC-BIO-E2E-033-M | FR-BIO-010 | E2E 自动连续可关闭·移动端 | 自动连续任务运行中 | 关闭自动连续开关 | 下一阶段前出现参数表单卡(切回手动) | L5-M | P1 |
| TC-BIO-E2E-033-T | FR-BIO-010 | E2E 自动连续可关闭·平板 | 自动连续任务运行中 | 关闭自动连续开关 | 下一阶段前出现参数表单卡(切回手动) | L5-T | P1 |
| TC-BIO-E2E-033-D | FR-BIO-010 | E2E 自动连续可关闭·桌面 | 自动连续任务运行中 | 关闭自动连续开关 | 下一阶段前出现参数表单卡(切回手动) | L5-D | P1 |
| TC-BIO-E2E-034-M | FR-BIO-024 | E2E 任务面板删除·移动端 | 非运行任务存在 | 面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-M | P1 |
| TC-BIO-E2E-034-T | FR-BIO-024 | E2E 任务面板删除·平板 | 非运行任务存在 | 面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-T | P1 |
| TC-BIO-E2E-034-D | FR-BIO-024 | E2E 任务面板删除·桌面 | 非运行任务存在 | 面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-D | P1 |
| TC-BIO-E2E-035-M | FR-BIO-022 | E2E 档案删除·移动端 | 归档存在 | 档案面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-M | P1 |
| TC-BIO-E2E-035-T | FR-BIO-022 | E2E 档案删除·平板 | 归档存在 | 档案面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-T | P1 |
| TC-BIO-E2E-035-D | FR-BIO-022 | E2E 档案删除·桌面 | 归档存在 | 档案面板点删除→确认 | 发出 DELETE;列表移除;刷新后仍无 | L5-D | P1 |
| TC-BIO-E2E-036-M | FR-BIO-007 | E2E 聊天窗口指定路径·移动端 | 任务待文件 | 在聊天输入合法服务器路径并发送 | 路径登记成功;文件引导卡更新;阶段推进 | L5-M | P1 |
| TC-BIO-E2E-036-T | FR-BIO-007 | E2E 聊天窗口指定路径·平板 | 任务待文件 | 在聊天输入合法服务器路径并发送 | 路径登记成功;文件引导卡更新;阶段推进 | L5-T | P1 |
| TC-BIO-E2E-036-D | FR-BIO-007 | E2E 聊天窗口指定路径·桌面 | 任务待文件 | 在聊天输入合法服务器路径并发送 | 路径登记成功;文件引导卡更新;阶段推进 | L5-D | P1 |
#### 6.1.18 DEPLOY 三形态部署(L2/L3 断言 + L2s 部署点冒烟)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-DEPLOY-001 | FR-BIO-027 | 只 rag:反代不注册 | BIOFLOW_ENABLED 缺省(false)启动 BFF | 检查路由表 | 无 /api/bioflow/* 路由 | L2 | P0 |
| TC-BIO-DEPLOY-002 | FR-BIO-027 | 只 rag:前端无生信痕迹 | 只 rag 部署;GET health 404 | 打开前端 | 无「生信任务/生信档案」TAB;无生信块分支;Composer 无生信上传分支 | L3 | P0 |
| TC-BIO-DEPLOY-003 | FR-BIO-027 | 只 rag:零请求 8098 | 只 rag 部署 | 打开前端并提问 | 网络面板无 /api/bioflow/* 请求 | L3 | P0 |
| TC-BIO-DEPLOY-004 | FR-BIO-027 | 只生信:8098 直连 | 仅部署生信服务 | GET :8098/api/bioflow/health | 200;catalog/jobs/chat 全部可用(不经 BFF) | L2 | P0 |
| TC-BIO-DEPLOY-005 | FR-BIO-027 | 只生信:报告降级下载 HTML | 只生信;任务 done | 取报告 | 返回 HTML 直下(Content-Type=text/html;Content-Disposition attachment 或页面内嵌,两态断言其一) | L2 | P0 |
| TC-BIO-DEPLOY-006 | FR-BIO-027 | 同部署:反代启用 | BIOFLOW_ENABLED=true | GET http://BFF/api/bioflow/health | 200 且响应体=直连响应体 | L2 | P0 |
| TC-BIO-DEPLOY-007 | FR-BIO-027 | 同部署:前端显形 | 同部署;health 200 | 打开前端 | 生信 TAB 出现;五类卡片/两面板可访问 | L3 | P0 |
| TC-BIO-DEPLOY-008 | FR-BIO-028 | BFF 停生信服务仍工作 | 同部署;停 BFF | 直连 8098 跑 mini 任务 | 任务正常完成(创建/确认/事件) | L2s | P0 |
| TC-BIO-DEPLOY-009 | FR-BIO-028 | BFF 重启不影响生信任务 | 同部署;任务 in-flight | 重启 BFF | 任务不受影响;8098 进程存活;GET jobs 仍含该任务 | L2s | P0 |
| TC-BIO-DEPLOY-010 | FR-BIO-027 | 三形态环境变量矩阵 | 三组配置 fixture | 逐组启动 BFF | 路由注册与否与 BIOFLOW_ENABLED 严格一致(3/3) | L2 | P1 |
| TC-BIO-DEPLOY-011 | FR-BIO-025 | 探活超时前端不白屏 | health 超时(mock 挂起) | 打开前端 | 页面正常渲染(无生信 TAB);无未捕获异常 | L3 | P1 |
| TC-BIO-DEPLOY-012 | FR-BIO-027 | 只生信形态 vstore 降级 | 只生信 | 跑流程咨询 | 检索不可用时 planner 走 LLM 直出(标记 llm_only);不 5xx | L2 | P1 |
#### 6.1.19 REG 回归与串扰(L3/L4/L5,bioflow 引入不得破坏既有功能)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-REG-001 | FR-BIO-001 | QA 主流程无串扰 | 同部署;mock normal | 完整跑 E2E-01(QA 五相位) | 全相位通过;无 bioflow 请求产生 | L5-D | P0 |
| TC-BIO-REG-002 | FR-BIO-001 | 检索模式无串扰 | mock | 检索模式提问 | 只出来源不出答案块(与既有行为一致) | L5-D | P0 |
| TC-BIO-REG-003 | FR-BIO-001 | docgen 全链无串扰 | 同部署 | 写文档→编辑→导出 | 全部走既有 docgen 链路;无 bioflow 拦截 | L5-D | P0 |
| TC-BIO-REG-004 | FR-BIO-001 | 会话管理无串扰 | 同部署 | 新建/切换/删除会话 | 行为与既有一致 | L5-D | P1 |
| TC-BIO-REG-005 | FR-BIO-001 | 意图词典改动不打乱 docgen | 词典全表 | 跑 cases_intent.md(docgen 版)30 条 | docgen 判定 30/30 与既有表一致 | L3 | P0 |
| TC-BIO-REG-006 | FR-BIO-001 | 红线文件零改动 | git checkout 基线 | diff 五文件 | modes.js/labels.js/bench.js/qa.js/parser.js 无 diff | L3 | P0 |
| TC-BIO-REG-007 | FR-BIO-011 | PipelineCard 零改动 | 进度卡复用 | diff | PipelineCard.vue 无 diff;两卡同款视觉 | L3 | P1 |
| TC-BIO-REG-008 | FR-BIO-001 | BenchPanel TAB 数更新 | 同部署 | 数 TAB | 生信 TAB 计入后总数=既有+2;关服务时恢复既有数 | L4 | P0 |
| TC-BIO-REG-009 | FR-BIO-016 | doc_artifacts 与生信报告并存 | 同部署 | 查看文档工作台 | 既有 docgen 文档与生信报告同列表可切换;互不覆盖 | L5-D | P0 |
| TC-BIO-REG-010 | FR-BIO-001 | 首屏性能不劣化 | 同部署 | 测首屏 | 首屏时间与引入前基线差 <500ms | L5-D | P2 |
| TC-BIO-REG-011 | FR-BIO-001 | 主题切换生信组件适配 | 同部署 | 切深/浅 | 五卡片两面板令牌随主题(--pa-* 自动适配,无硬编码色) | L4 | P0 |
| TC-BIO-REG-012 | FR-BIO-001 | i18n 文案走 bioflow.js | 前端构建 | 检索文案键 | 生信文案全部在 i18n/bioflow.js;labels.js 未动 | L3 | P1 |
| TC-BIO-REG-013 | FR-BIO-001 | 生信会话与 QA 会话隔离 | 同部署 | 两会话并行操作 | 各自消息/任务状态互不串扰 | L5-D | P1 |
| TC-BIO-REG-014 | FR-BIO-001 | 既有 E2E 冒烟 6 条 | 同部署 | 跑 smoke.spec 三视口 | 6/6 pass(占位回退失效后走真实分支仍过) | L5 | P1 |
| TC-BIO-REG-015 | FR-BIO-001 | QA 上游 402 降级不受影响 | mock 402 | 提问 | fallback 证据列表展示与既有一致 | L5-D | P1 |
#### 6.1.20 GOLD 金标与发布(L2s 部署点冒烟 + 编译门禁)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-GOLD-001 | FR-BIO-030 | 金标 24 ID 全等 | bioflow-gf 镜像;金标输入 | docker run identify | 输出集合与预期 24 成员 ID 全等;diff 输出为空 | L2s | P0 |
| TC-BIO-GOLD-002 | FR-BIO-030 | 金标冒烟脚本 | 镜像与数据就位 | bash bioflow_kernel/tests/smoke_golden.sh | 退出码 0;stdout 含 PASS | L2s | P0 |
| TC-BIO-GOLD-003 | FR-BIO-030 | 金标重复可复现 | 同上 | 连跑 2 次 | 两次输出集合一致(确定性) | L2s | P1 |
| TC-BIO-GOLD-004 | FR-BIO-032 | 18 入口 --help 冒烟 | 4 镜像 | 逐条 python -B -m cli.run_* --help | 18/18 退出码 0;无 traceback | L2s | P0 |
| TC-BIO-GOLD-005 | FR-BIO-032 | compile_bioflow.sh 编译产出 | 源码树 | 跑编译脚本(TL 执行后 T 验证) | 产出 .so 与明文白名单文件;无编译错误 | L2s | P0 |
| TC-BIO-GOLD-006 | FR-BIO-032 | 白名单外无明文 | 编译产物 | 检查产物 | 白名单外模块均为 .so(无 .py 明文残留) | L2s | P1 |
| TC-BIO-GOLD-007 | FR-BIO-032 | build_all.sh 4 镜像 | 构建环境 | 检查 docker images | bioflow-gf/bioflow-rnaseq/bioflow-wgs/bioflow-interproscan 四 tag 存在 | L2s | P0 |
| TC-BIO-GOLD-008 | FR-BIO-032 | SHA256SUMS | 构建产物目录 | 校验 | 文件存在且每条 sha256 与产物一致 | L2s | P0 |
| TC-BIO-GOLD-009 | FR-BIO-032 | 泄露门禁扫描 | 构建产物 | 扫描凭据模式 | 无 ACCESS_KEY/SECRET/密码类命中 | L2s | P0 |
| TC-BIO-GOLD-010 | FR-BIO-032 | 镜像启动冒烟 | 4 镜像 | docker run --help 版入口 | 4/4 容器启动并退出码 0 | L2s | P0 |
| TC-BIO-GOLD-011 | FR-BIO-029 | 资源限制生效验证 | 镜像 | docker run --cpus 2 --memory 4g 跑冒烟 | 容器内可见限制(/sys/fs/cgroup 或 nproc 断言) | L2s | P1 |
| TC-BIO-GOLD-012 | FR-BIO-029 | BIOFLOW_DATA 只读 | 镜像 | 挂载 :ro 跑冒烟 | 容器内写 /bioflow-data 失败(Permission denied) | L2s | P1 |
| TC-BIO-GOLD-013 | FR-BIO-032 | rag 侧装配开关 | rag 部署树 | 检查配置文件 | BIOFLOW_ENABLED 键存在且默认 false | L2s | P0 |
| TC-BIO-GOLD-014 | FR-BIO-032 | 生信服务编译白名单 | 编译产物 | 检查 | main.py/config.py/schemas.py/db.py 明文;业务模块 .so | L2s | P1 |
| TC-BIO-GOLD-015 | FR-BIO-032 | 内核映射表产物 | A1 交付 | 检查 bioflow_kernel/stage_image_map.json | JSON 合法;覆盖基因家族链 18 阶段 | L2s | P0 |
#### 6.1.21 P0 冒烟(优先级 P0 快速验证集,TL 放行/验收快速通道)
| 编号 | 对应 FR | 标题 | 前置条件 | 步骤 | 预期结果 | 测试层 | 优先级 |
|---|---|---|---|---|---|---|---|
| TC-BIO-SMOKE-001 | FR-BIO-001 | P0 冒烟:分流命中 | mock | 发送「帮我跑水稻 SPL 家族鉴定」 | 进入生信流(出现路径卡或 bioflow 请求) | L5-D | P0 |
| TC-BIO-SMOKE-002 | FR-BIO-001 | P0 冒烟:漏判安全 | mock | 发送「什么是基因家族」 | 走 qa;无 bioflow 请求 | L5-D | P0 |
| TC-BIO-SMOKE-003 | FR-BIO-025 | P0 冒烟:探活 | mock | 打开应用(health 200) | 生信 TAB 可见 | L5-D | P0 |
| TC-BIO-SMOKE-004 | FR-BIO-002 | P0 冒烟:候选路径 | mock LLM | 读 plan_ready | 候选数∈[2,3] 且含阶段序列 | L2 | P0 |
| TC-BIO-SMOKE-005 | FR-BIO-004 | P0 冒烟:任务创建 | mock | POST jobs | 201 且 stages 入表 | L2 | P0 |
| TC-BIO-SMOKE-006 | FR-BIO-031 | P0 冒烟:状态机 | mock docker | 3 阶段任务跑通 | 全部 done;事件序正确 | L1 | P0 |
| TC-BIO-SMOKE-007 | FR-BIO-014 | P0 冒烟:事件回放 | 任务中途 | 连 events | 快照+补齐 | L2 | P0 |
| TC-BIO-SMOKE-008 | FR-BIO-029 | P0 冒烟:docker 拼装 | mock | 拼 identify 命令 | 含 --rm/--user/-v×3/--cpus/--memory/-e | L1 | P0 |
| TC-BIO-SMOKE-009 | FR-BIO-030 | P0 冒烟:金标 | 镜像就位 | 金标 diff | 输出为空 | L2s | P0 |
| TC-BIO-SMOKE-010 | FR-BIO-028 | P0 冒烟:反代开关 | BIOFLOW_ENABLED=true | GET BFF health | 200 | L2 | P0 |
| TC-BIO-SMOKE-011 | FR-BIO-011 | P0 冒烟:进度卡流转 | mock 事件 | 前端应用 | 状态点逐阶段点亮 | L4 | P0 |
| TC-BIO-SMOKE-012 | FR-BIO-012 | P0 冒烟:三选一 | 阶段 failed | 检查三按钮 | 重跑/跳过/改参数重跑出现 | L4 | P0 |
| TC-BIO-SMOKE-013 | FR-BIO-020 | P0 冒烟:存档 | 任务 done | POST archives | 201;磁盘目录存在 | L2 | P0 |
| TC-BIO-SMOKE-014 | FR-BIO-023 | P0 冒烟:复用 | 归档存在 | archives/{id}/run | 201;参数=归档值 | L2 | P0 |
| TC-BIO-SMOKE-015 | FR-BIO-016 | P0 冒烟:报告登记 | 任务 done | 登记 | doc_artifacts 新行 | L2 | P0 |
| TC-BIO-SMOKE-016 | FR-BIO-019 | P0 冒烟:图表调整 | 报告含图 | revise | 绘图阶段重跑;图更新 | L2 | P0 |
| TC-BIO-SMOKE-017 | FR-BIO-026 | P0 冒烟:知识问答 | flow_docs 入库 | 咨询 | 答案含引用块 | L2 | P0 |
| TC-BIO-SMOKE-018 | FR-BIO-027 | P0 冒烟:三形态 | 三配置 fixture | 逐形态启动 | 3/3 断言通过 | L2 | P0 |
| TC-BIO-SMOKE-019 | FR-BIO-032 | P0 冒烟:--help 18 入口 | 镜像 | 逐条 --help | 18/18 退出码 0 | L2s | P0 |
| TC-BIO-SMOKE-020 | FR-BIO-032 | P0 冒烟:SHA256SUMS | 产物 | 校验 | 全部匹配 | L2s | P0 |
| TC-BIO-SMOKE-021 | FR-BIO-006 | P0 冒烟:上传 | 任务待文件 | 上传小文件 | 200;files 列表+1 | L2 | P0 |
| TC-BIO-SMOKE-022 | FR-BIO-007 | P0 冒烟:路径登记 | 合法路径 | POST files server_path | 200;登记可见 | L2 | P0 |
| TC-BIO-SMOKE-023 | FR-BIO-010 | P0 冒烟:暂停恢复 | 任务 running | pause→resume | 状态迁移正确 | L2 | P0 |
| TC-BIO-SMOKE-024 | FR-BIO-024 | P0 冒烟:面板渲染 | 任务存在 | 打开面板 | 列表+DAG 渲染 | L4 | P0 |
| TC-BIO-SMOKE-025 | FR-BIO-022 | P0 冒烟:档案面板 | 归档存在 | 打开面板 | 档案列表渲染 | L4 | P0 |
### 6.2 追溯矩阵(FR-BIO → TC-BIO)
| FR | TC-BIO(引用即覆盖,≥1 条) |
|---|---|
| FR-BIO-001 | INTENT-001~010,022~030,040~047; API-001,005~010,013~015,019,020,136; STORE-001,002,022; REG-001~006,010,012~015; SMOKE-001,002; E2E-025-M/T/D; ACT-030 |
| FR-BIO-002 | INTENT-001~010; API-002,021~026,114,137,145; STORE-003; PATH-001~011,015,016,018~020; ACT-001~013; SMOKE-004; E2E-001-M/T/D |
| FR-BIO-003 | API-003,004; RUN-034; PATH-012; INTENT-003 |
| FR-BIO-004 | API-027~031,107,138,149; STORE-004; PATH-013,014,017; SMOKE-005; E2E-001~003-M/T/D |
| FR-BIO-005 | RUN-017,018,032; FILE-001,002,015; E2E-004-M/T/D |
| FR-BIO-006 | API-039~041,046~054,105,120; STORE-010; FILE-003~007,011~018,021,022; ACT-034~040; SMOKE-021; E2E-005-M/T/D |
| FR-BIO-007 | API-042~045; FILE-008~010,019,020; ACT-041~049; SMOKE-022; E2E-026,036-M/T/D |
| FR-BIO-008 | API-056,058,121; RUN-019,020; FORM-001~006,013~018,021,022; ACT-014~019; E2E-006-M/T/D |
| FR-BIO-009 | API-057,059~061,150; STORE-011; FORM-007~009,018,019,023,024; ACT-020~026; E2E-006-M/T/D |
| FR-BIO-010 | API-067~070,122,147,148; RUN-006,007,021~023; STORE-012,013; FORM-010~012; PROG-017,018; ACT-027~033; SMOKE-023; E2E-013,027,033-M/T/D |
| FR-BIO-011 | API-071~076,108,127; RUN-013; STORE-005,007; PROG-001~005,019,023,024; JOB-006,016; ACT-094,095; SMOKE-011; E2E-007-M/T/D |
| FR-BIO-012 | API-062~066,140; RUN-002~005,024,045; STORE-006,014; PROG-006~011,020,022; ACT-050~057; SMOKE-012; E2E-014~017-M/T/D |
| FR-BIO-013 | PROG-012~014; ACT-058~062 |
| FR-BIO-014 | API-013,017,077~083,126,128; SSE-001~032; STORE-008,009,020,021; PROG-015,016; SMOKE-007; E2E-018-M/T/D |
| FR-BIO-015 | API-104,124,125; FLOW-005,006 |
| FR-BIO-016 | API-123; FLOW-003,004,007; REG-009; SMOKE-015; E2E-008-M/T/D |
| FR-BIO-017 | API-143; E2E-028-M/T/D |
| FR-BIO-018 | E2E-009,024-M/T/D |
| FR-BIO-019 | API-084~086,144; INTENT-033; FLOW-008; SMOKE-016; E2E-021-M/T/D |
| FR-BIO-020 | API-087~089,098,129,130; ARCH-001~006,011,012; ACT-074~089; SMOKE-013; E2E-010,031-M/T/D |
| FR-BIO-021 | API-131; DB-012; STORE-017; ARCH-007~010; E2E-010-M/T/D |
| FR-BIO-022 | API-090~093,141,142; DB-007; STORE-019; PANE-001~007,011,012,015; ACT-092,093; SMOKE-025; E2E-030,035-M/T/D |
| FR-BIO-023 | API-011,029,094~097,132; INTENT-034~039; STORE-015; FORM-020; PANE-008~010,016; ACT-070~073; SMOKE-014; E2E-019,032-M/T/D |
| FR-BIO-024 | API-032~038,112,113; RUN-028,029,044; DB-006,011; STORE-018; PROG-021; JOB-001~016; ACT-063~069,090,091; SMOKE-024; E2E-003,011,029,034-M/T/D |
| FR-BIO-025 | API-099,133; STORE-016; JOB-012,013; PANE-013,014; DEPLOY-011; SMOKE-003; E2E-020-M/T/D |
| FR-BIO-026 | API-012; INTENT-045; FLOW-009; SMOKE-017; E2E-022-M/T/D |
| FR-BIO-027 | DEPLOY-001~007,010,012; SMOKE-018; E2E-012,023-M/T/D |
| FR-BIO-028 | API-100~103,134,135; DB-001~005,008,009; FLOW-001,002; DEPLOY-008,009; SMOKE-010 |
| FR-BIO-029 | API-115~119; RUN-012,014,016,031,035~037; KERN-001~009,024; GOLD-011,012; SMOKE-008 |
| FR-BIO-030 | KERN-010,011,014~020; GOLD-001~003; SMOKE-009 |
| FR-BIO-031 | API-016,109~111,139,146; RUN-001,008~011,025~027,030,033,038~043,046; DB-010; SMOKE-006 |
| FR-BIO-032 | KERN-012,013,021~023; GOLD-004~010,013~015; SMOKE-019,020 |
> 覆盖自核:32/32 FR-BIO 全部有 TC 引用;每个 TC-BIO 均映射至少 1 个 FR(见每行「对应 FR」列);无孤儿 TC。模块计数与规模门禁见 docs/team/report_bioflow_test1.md。