Skip to content

FNOS-034 测试用例 ​

测试范围与需求分析 ​

被测对象是 fnOS 授权目录选择器的承载形式:从工具栏 28px 按钮上的 TreeSelect 下拉,改为 conversation.input.overlay 里贴齐输入卡片的浮层。选择语义(父子独立勾选、勾选即插入引用、取消即移除)必须原样保持。

执行任务见 PLAN-FNOS-034,覆盖需求功能:

覆盖功能关键风险点
FNOS-034-01 选择器改为输入卡片宽浮层是否仍写死像素宽度;是否与指令面板共用锚点;高度是否越出视口
FNOS-034-02 保持原有选择语义父子勾选是否被折叠;取消勾选是否漏删引用;会话间是否串状态
FNOS-034-03 浮层有明确收起出口点外部/Esc/再点图标是否都能关;点卡片内部是否误关

测试环境 ​

环境用途是否作为验收依据
包级测试(vitest)几何规则、槽位注册形状、树数据搬运、开关 store是(逻辑层)
构建pnpm --filter @tnnevol/dsh-fnos run build 产出 lib/client.js是(产物)
FPK + 真实 fnOS NAS浮层在真实输入卡片上的呈现、真实授权目录树的勾选与引用增删是(验收依据)

本地 DSH Web 不作为验收依据

@tnnevol/dsh-fnos 注册 fnOS 设置命名空间、fnOS JS SDK 桥和网关前缀路由,脱离 fnOS 宿主没有可提供的能力,因此按本地 DSH Web的约定不进本地 profile。

本需求的验收一律以 FPK 在真实 NAS 安装后的表现为准。开发期间若需观察前端几何,只能作为实现自检,不能计入验收结论。

包级:pnpm --filter @tnnevol/dsh-fnos run check(typecheck + vitest 369 条)。

FPK:pnpm run build 后在应用中心安装,按 TC-101 起的真机用例执行。

测试用例 ​

FNOS-034-01 选择器改为输入卡片宽浮层 ​

ID覆盖验收步骤预期执行环境
TC-001FNOS-034-01-AC-01用真实 SlotCore 注册浮层条目,读 conversation.input.overlay 的条目列表官方 slash-menu/command-popup/feedback-dialog 原样保留,新条目排在最后包级
TC-002FNOS-034-01-AC-01重复注册同一 id 与 priority抛出 already has an entry,证明必须用自有 id包级
TC-003FNOS-034-01-AC-02断言样式源码面板规则内没有 px 宽度、没有 560px、没有 100vw包级
TC-004FNOS-034-01-AC-02断言面板规则 left: 0 / right: 0 / bottom: calc(100% + 4px)与上游斜杠菜单同一套几何包级
TC-005FNOS-034-01-AC-03断言面板使用 useAnchoredMaxHeight 且顶部留 84高度按视口上方可用空间钳制,与斜杠菜单同值包级
TC-006FNOS-034-01-AC-03读树区与标题栏样式树区 overflow: auto 自己滚,标题栏 flex: none 固定包级
TC-101FNOS-034-01-AC-02真实 NAS 打开选择器,量面板与输入框的 getBoundingClientRect左右偏差为 0,宽度相等真实 NAS
TC-102FNOS-034-01-AC-02真实 NAS 上把浏览器窗口拉窄,再量一次面板跟随输入框收窄,左右仍齐边,无横向滚动真实 NAS

FNOS-034-02 保持原有选择语义 ​

ID覆盖验收步骤预期执行环境
TC-007FNOS-034-02-AC-01selectedPaths(['/vol1', '/vol1/media'])两条都保留,不做父子折叠包级
TC-008FNOS-034-02-AC-01selectedPaths 传入非绝对路径、重复项、空值只留绝对路径并去重;空值归一为空数组包级
TC-009FNOS-034-02-AC-01懒加载子节点后 updateChildren 并回父节点子节点挂上、父节点 isLeaf 置 false、兄弟节点引用不变包级
TC-010FNOS-034-02-AC-02断言引用插入仍走 slash/input-insert-reference 与官方 chip 占位插入路径未变,草稿投影与 CAS 跨度数学保持原样包级
TC-011FNOS-034-02-AC-03store 上展开 A 会话后读 B 会话A 为 true、B 为 false包级
TC-012FNOS-034-02-AC-03toggle 交叉翻转两个会话;重复 set 同一状态各自独立翻转;重复设置不重复通知包级
TC-013FNOS-034-02-AC-03closeAll 后读各会话;退订后再变更全部关闭且只通知一次;退订后不再通知包级
TC-014FNOS-034-02-AC-01读树节点 key/value用内部路径而非可读语义路径(Host 路由只认内部路径)包级
TC-103FNOS-034-02-AC-01真实 NAS 勾选父目录与子目录各一两条都被勾选并各自插入引用真实 NAS
TC-104FNOS-034-02-AC-01真实 NAS 取消一个已勾选目录对应引用从草稿中移除,其余引用不变真实 NAS
TC-105FNOS-034-02-AC-02真实 NAS 勾选后发送消息模型收到 @/path/ 形式的 NAS 路径真实 NAS

FNOS-034-03 浮层有明确收起出口 ​

ID覆盖验收步骤预期执行环境
TC-015FNOS-034-03-AC-01断言点卡片外的关闭逻辑与卡片内豁免命中 [data-composer-card] 时不关闭,否则关闭包级
TC-016FNOS-034-03-AC-02断言 Escape 的 keydown 处理存在 Esc 关闭分支包级
TC-017FNOS-034-03-AC-03断言按钮走同一个 store 的 toggle再点图标关闭,aria-expanded 同步包级
TC-018FNOS-034-03-AC-01/02断言收起后两个全局监听器都被移除无残留 pointerdown/keydown 监听包级

FNOS-034-04 层级始终低于指令面板 ​

ID覆盖验收步骤预期执行环境
TC-019FNOS-034-04-AC-01读面板规则里的 z-index为 99(低于指令面板的 100),且没有写回 100包级
TC-110FNOS-034-04-AC-01真实 NAS 同时打开指令面板与选择器指令面板显示在上,选择器不被遮挡真实 NAS

FNOS-034-05 面板不提供搜索 ​

ID覆盖验收步骤预期执行环境
TC-020FNOS-034-05-AC-01断言面板源码不含 filterTreeNode 与 searchPlaceholder包级
TC-111FNOS-034-05-AC-01真实 NAS 打开选择器面板内没有搜索框,目录树完整展示真实 NAS

FNOS-034-06 面板内新建文件夹与空文件 ​

ID覆盖验收步骤预期执行环境
TC-021FNOS-034-06-AC-01断言入口形态标题栏没有新建按钮;菜单含文件夹与文件两项包级
TC-022FNOS-034-06-AC-02断言右键处理目录右键弹出上下文菜单(不是直接开弹框);命中文件时不弹菜单包级
TC-023FNOS-034-06-AC-03断言成功后的树更新用 updateChildren 并入当前层,不整树重取包级
TC-024FNOS-034-06-AC-04parseCreateRequest 合法请求返回规范化的 {parent,name,kind}包级
TC-025FNOS-034-06-AC-04父目录为相对路径 / ../ / 空串相对与空串拒绝;.. 被规范化且仍为绝对路径包级
TC-026FNOS-034-06-AC-04kind 传非 directory/file,或缺失一律拒绝包级
TC-027FNOS-034-06-AC-04名称含 /、\、/abs、../escape全部拒绝包级
TC-028FNOS-034-06-AC-04名称含 : * ? " < > |全部拒绝(SMB 兼容)包级
TC-029FNOS-034-06-AC-04名称含控制字符(NUL/BEL/换行)全部拒绝包级
TC-030FNOS-034-06-AC-04名称为 .、..、空串、纯空白、超 255 字符全部拒绝;255 字符通过包级
TC-031FNOS-034-06-AC-04名称含中文、空格、点、短横线、前导点接受(去首尾空白后)包级
TC-032FNOS-034-06-AC-05断言错误码到文案的映射已存在/权限不足/空间不足/只读各有独立文案包级
TC-037FNOS-034-06-AC-06断言弹层打开时的豁免条件存在 floatingOpen(弹框或菜单打开);两条全局关闭监听均带该守卫包级
TC-038FNOS-034-06-AC-07断言菜单定位方式自绘菜单,position: fixed + 鼠标坐标;落点经 clampMenuPosition 收进视口包级
TC-039FNOS-034-06-AC-07断言菜单收起条件点击菜单外或 Esc 时 setContextMenu(undefined)包级
TC-040FNOS-034-08-AC-01断言右键与菜单项可见性文件也能右键;新建项只对目录显示包级
TC-041FNOS-034-08-AC-02断言菜单项图标三个菜单项各带语义图标;删除项用 is-danger包级
TC-042FNOS-034-08-AC-03断言删除确认形态用 Popconfirm 就地确认(不再弹 Modal);确认按钮 danger包级
TC-043FNOS-034-08-AC-05断言删除后的本地清理removeNode、entries.delete、勾选过滤包级
TC-044FNOS-034-08-AC-04parseDeleteRequest 校验绝对路径通过;相对/空/NUL 拒绝;.. 规范化包级
TC-120FNOS-034-08-AC-01/02真实 NAS 右键文件与目录文件菜单只有删除;目录有新建两项 + 删除;图标正常真实 NAS
TC-121FNOS-034-08-AC-03/05真实 NAS 删除一个自建文件夹先弹确认;确认后条目消失,勾选与引用一并清除真实 NAS
TC-122FNOS-034-08-AC-04真实 NAS 尝试删除授权根提示根目录不可删除,条目仍在真实 NAS
TC-118FNOS-034-06-AC-07真实 NAS 在树中段右键菜单出现在光标附近(不是面板角落)真实 NAS
TC-045FNOS-034-06-AC-08断言菜单渲染位置用 createPortal 挂到 document.body;面板规则含 backdrop-filter包级
TC-046FNOS-034-08-AC-06断言浮层守卫覆盖所有 portal 浮层floatingOpen 含 createTarget 与 contextMenu;新增浮层漏加即失败包级
TC-047FNOS-034-09-AC-01断言授权入口与 SDK 路径标题栏含 authorizeDirectory,走 pickAuthorizedDirectory包级
TC-048FNOS-034-09-AC-02/03断言授权成功后的两个后续动作同时调用 applyEntries 与 requestPersistAuthorizedDirectories包级
TC-049FNOS-034-10-AC-01/03settings 为空、缓存有值settings 被回填为缓存值;缓存文件未被清空包级
TC-050FNOS-034-10-AC-02settings 已有值、缓存是旧的以 settings 为准写文件;不回填 settings包级
TC-051FNOS-034-11-AC-01/02GET 返回内置前缀响应含 builtin 三项;设置页渲染只读区包级
TC-052FNOS-034-09-AC-047 种取消形态(undefined / cancel 状态 / 文案配 null、缺失、非数组 data / AbortError / 取消异常)一律 cancelled,不产生提示包级
TC-053FNOS-034-09-AC-05access_denied 与 code === 1 普通失败前者判权限,后者判接口失败包级
TC-054FNOS-034-09-AC-02三种成功形态(data 数组 / 裸路径 / paths)都返回 picked 与正确路径包级
TC-055FNOS-034-08-AC-03确认后请求是否真的发出目标取自 ref;请求早于本地状态清理;变异测试可捕获回归包级
TC-056FNOS-034-08-AC-07Popconfirm 尺寸无 width/style/className;样式表不覆盖;文案 ≤30 字包级
TC-119FNOS-034-06-AC-07真实 NAS 打开菜单后点面板其他位置菜单收起,面板保持打开真实 NAS
TC-117FNOS-034-06-AC-06真实 NAS 打开新建弹框后点击各处面板保持打开;关闭弹框后面板仍在真实 NAS
TC-112FNOS-034-06-AC-01/03真实 NAS 从右键菜单新建文件夹并填名弹框可提交,新文件夹出现在该层,其它已展开节点保持展开真实 NAS
TC-113FNOS-034-06-AC-02真实 NAS 在目录上右键先弹出上下文菜单(新建文件夹/新建文件),选一项后进入命名弹框,父目录为该目录真实 NAS
TC-114FNOS-034-06-AC-05真实 NAS 用已存在的名字新建提示「同名文件或文件夹已存在」,不覆盖原条目真实 NAS

FNOS-034-07 气泡提示只在被省略时出现 ​

ID覆盖验收步骤预期执行环境
TC-033FNOS-034-07-AC-01/03断言承载方式用 Typography.Text + ellipsis={{ showTooltip: true, rows: 1 }},不手写宽度测量包级
TC-034FNOS-034-07-AC-03断言不再自行判定源码里没有 scrollWidth >、ResizeObserver、loadingdone包级
TC-035FNOS-034-07-AC-03断言 children 为纯文本Typography.Text 内是 {name}(Semi 的 ellipsis 只支持 string)包级
TC-036FNOS-034-07-AC-01/02断言标签样式容器 min-width: 0(不撑开);文本不自定义 text-overflow/white-space(交给 Typography)包级
TC-115FNOS-034-07-AC-01真实 NAS:悬停一个名字较短、未被截断的目录不出现气泡提示真实 NAS
TC-116FNOS-034-07-AC-02真实 NAS:把窗口拉窄使名字被省略号截断,再悬停出现气泡提示并显示完整路径真实 NAS
TC-106FNOS-034-03-AC-01真实 NAS 打开面板后点页面空白处面板收起真实 NAS
TC-107FNOS-034-03-AC-01真实 NAS 打开面板后点回输入框面板保持打开真实 NAS
TC-108FNOS-034-03-AC-02真实 NAS 打开面板后按 Esc面板收起真实 NAS
TC-109FNOS-034-03-AC-03真实 NAS 连点 fnOS 图标两次先开、再关真实 NAS

测试执行结果 ​

已执行(包级) ​

ID结果执行日期证据/备注
TC-001通过2026-10-28tests/client/input-picker-panel.spec.ts「浮层注册在 conversation.input.overlay,且排在官方条目之后」
TC-002通过2026-10-28同文件「使用自有 id,不替换指令面板与命令选择」
TC-003通过2026-10-28tests/client/input-picker-geometry.spec.ts「不写任何固定像素宽度」
TC-004通过2026-10-28同文件「左右对齐锚点」「浮在输入卡片上沿之上」
TC-005通过2026-10-28同文件「面板用锚定的最大高度」「顶部留出会话头部的安全距离」
TC-006通过2026-10-28同文件「树区自己滚动,标题栏固定」
TC-007通过2026-10-28input-picker-panel.spec.ts「保留父子同时勾选的路径」
TC-008通过2026-10-28同文件「丢弃非绝对路径并去重」「空值归一成空数组」
TC-009通过2026-10-28同文件两条 updateChildren 用例
TC-010通过2026-10-28tests/contracts/package-contract.spec.ts「keeps fnOS file and folder references in the native input draft」
TC-011通过2026-10-28input-picker-panel.spec.ts「展开一个会话不影响另一个会话」
TC-012通过2026-10-28同文件 toggle 交叉与「重复设置同一状态不触发通知」
TC-013通过2026-10-28同文件 closeAll 与退订两条
TC-014通过2026-10-28同文件「节点 key 与 value 都用内部路径」
TC-015通过2026-10-28input-picker-geometry.spec.ts「点击输入卡片外部收起」
TC-016通过2026-10-28同文件「按 Esc 收起」
TC-017通过2026-10-28同文件「再点工具栏图标收起」
TC-018通过2026-10-28同文件「收起时监听器被移除」
TC-019通过2026-10-28input-picker-geometry.spec.ts「面板 z-index 必须比指令面板的 100 低一级」
TC-020通过2026-10-28同文件「Tree 不开启 filterTreeNode,也不带搜索占位符」
TC-021通过2026-10-29同文件「标题栏没有新建入口,新建只从右键菜单进入」
TC-022通过2026-10-28同文件「右键目录可打开新建弹框;命中文件不提供新建」
TC-023通过2026-10-28同文件「创建成功后把新条目并进已展开的那一层」
TC-024通过2026-10-28tests/host/authorized-create-request.spec.ts「接受合法请求」
TC-025通过2026-10-28同文件「父目录必须是绝对路径」「父目录里的 .. 会被规范化」
TC-026通过2026-10-28同文件「kind 只接受 directory 与 file」
TC-027通过2026-10-28同文件「拒绝任何路径分隔符(含反斜杠)」
TC-028通过2026-10-28同文件「拒绝 SMB 下非法的保留字符」
TC-029通过2026-10-28同文件「拒绝控制字符」
TC-030通过2026-10-28同文件「拒绝 . 与 ..」「拒绝空名与纯空白」「拒绝超长名称」
TC-031通过2026-10-28同文件「去掉首尾空白后接受常见名字」「允许中文、空格、点与短横线」
TC-032通过2026-10-28input-picker-geometry.spec.ts「错误按原因给出可操作文案」
TC-037通过2026-10-29input-picker-geometry.spec.ts「弹层打开时不因点外部销毁整个面板」等三条
TC-038通过2026-10-29同文件「菜单自绘并落在鼠标坐标上」「菜单落点被收进视口」
TC-045通过2026-10-29input-picker-geometry.spec.ts「菜单经 Portal 挂到 body」
TC-046通过2026-10-29同文件「每个 portal 浮层的开关状态都纳入了 floatingOpen 守卫」
TC-047通过2026-10-29input-picker-geometry.spec.ts「标题栏提供授权入口,走 fnOS 原生选择器」
TC-048通过2026-10-29同文件「授权成功同时刷新树与持久化」
TC-049通过2026-10-29gateway-proxy-route.spec.ts「restores settings from the cached allowlist」
TC-050通过2026-10-29同文件「keeps settings authoritative when they already carry paths」
TC-051通过2026-10-29同文件「returns the built-in prefixes alongside the editable snapshot」
TC-052通过2026-10-29authorized-directory-picker.spec.ts「取消不报错」7 条 + picker-result.spec.ts 对应 6 条
TC-053通过2026-10-29同文件「access_denied 归为权限问题」「code === 1 不再一律当权限问题」
TC-054通过2026-10-29同文件「成功路径」3 条
TC-055通过2026-10-29delete-entry-contract.spec.ts 4 条;变异验证:还原 bug 后立即失败
TC-056通过2026-10-29同文件 3 条
TC-039通过2026-10-29同文件「点击菜单外或按 Esc 自动收起菜单」
TC-040通过2026-10-29input-picker-geometry.spec.ts「文件也能右键(可删除),新建项只对目录显示」
TC-041通过2026-10-29同文件「菜单项带图标」「菜单含删除项,且用危险色区分」
TC-042通过2026-10-29同文件「删除用 Popconfirm 就地确认,不再弹整块 Modal」
TC-043通过2026-10-29同文件「删除成功后把条目从树与勾选中摘掉」
TC-044通过2026-10-29tests/host/authorized-create-request.spec.ts「删除条目:请求体校验」5 条
TC-033通过2026-10-28input-picker-geometry.spec.ts「用 Semi Typography 的 ellipsis 承载省略与提示」
TC-034通过2026-10-28同文件「不再自己量 scrollWidth,也不手写 Tooltip 分支」
TC-035通过2026-10-28同文件「ellipsis 的 children 必须是纯文本」
TC-036通过2026-10-28同文件「容器允许收缩」「不自定义 text-overflow」
TC-057通过2026-10-29authorized-directory-picker.spec.ts「非 0 code 且没有路径按取消处理,不弹错误」「非 0 code 配未知文案与 data: null 时同样静默」;对应 BUG-01
TC-058通过2026-10-29input-picker-geometry.spec.ts「标题栏两个按钮都不用原生 title,授权用文案按钮」

包级总量:39 个测试文件 / 369 条全绿(pnpm --filter @tnnevol/dsh-fnos run check);run build 产出 lib/client.js 2.14 MB。

已执行(真实 NAS) ​

ID结果日期证据
TC-101 ~ TC-122通过2026-10-306.1.15 FPK 在真实 NAS 走应用中心安装后,提出人确认整体验收通过;本轮重点复验了取消授权不再误报、标题栏文案按钮与去掉原生气泡。逐条细节未单独截图取证

Bug 记录 ​

ID现象原因修复回归
BUG-01在面板点「授权目录」唤起 fnOS 原生选择器后直接关掉,页面弹「无法授权该目录。」取消时返回体是解析成功、code 非 0、没有路径的普通响应;判定链把「非 0 code」当失败,于是用户什么都没做却被报错。此前几轮修补分别覆盖了 undefined、status: 'cancel'、取消文案与 code: 0 无路径,恰好漏掉这一种组合判定改用官方类型:AppBridgeResponse 只有 code/msg/data,没有取消专用 code;官方只记录 AppAuthCallbackStatus 的 cancel 与 AppAuthCallbackError 的 access_denied。因此「没有路径且没有这两种标记」一律按取消静默处理,status: 'error' 与 access_denied 仍照旧报错authorized-directory-picker.spec.ts 新增两条;原有 access_denied 报错用例保持通过

未覆盖与后续验证 ​

项原因后续动作
浮层在真实输入卡片上的宽度对齐包级只能断言样式规则,无法测出运行时的 --dsh-composer-card-max-width按 TC-101/TC-102 在真实 NAS 上量
真实授权目录树的勾选与引用增删需要 fnOS 生命周期环境变量提供的授权路径按 TC-103 ~ TC-105 在真实 NAS 上验证
三个关闭出口的实际手感依赖真实事件与焦点行为按 TC-106 ~ TC-109 在真实 NAS 上验证
与指令面板的真实叠放需要真实打开两个面板按 TC-110 在真实 NAS 上验证
新建条目真的落到磁盘包级只覆盖请求校验与树更新,未触碰真实文件系统按 TC-112 ~ TC-114 在真实 NAS 上验证

最终结论 ​

上表所列包级用例全部通过;真机验收于 2026-10-30 通过(提出人在真实 NAS 上确认 6.1.15)。此前几轮真机反馈(取消授权误报、标题栏按钮与原生气泡、层级与宽度)均已修复并复验;本地 DSH Web 的观感不作为验收依据。

基于 VitePress 构建