App
以下用例覆盖 iOS、Android、macOS;标明“桌面端”的用例同时覆盖 macOS 与 Windows。首次登录必须使用真新设备或已按发布说明清理的测试设备,不能只卸载界面程序后假定状态为空。
浏览器登录与账号
APP-01~03 首装登录、Profile 激活与换账号
APP-01 以新设备完成 AUTH-01、AUTH-04、AUTH-07;APP-02 完成 AUTH-02、AUTH-03、AUTH-06;APP-03 完成 AUTH-05。三条共同通过标准是:只批准一次即可进入已登录且断开的状态;不会先报“授权未完成”再靠第二次点击成功;A/B 账号、endpoint、profile 与资源绝不串用。
AUTH-01 登录单飞
前置: 未登录,浏览器可正常授权。
- 连续快速点击两次“登录”,或在第一次请求尚未完成时再次点击。
- 完成浏览器批准并返回 App。
通过: 只创建一次设备授权、只打开一个授权页;按钮在处理中不可重复提交。批准后一次成功,App 保持断开,不自动建立 VPN/TUN 连接。
AUTH-02 URL 前 busy 只重试一次
前置: 用测试桩令 Core 在生成授权 URL 前返回 engine_busy。
- 第一次注入一次 busy,点击登录。
- 再注入连续两次 busy,重新点击登录。
通过: 第一次由同一登录操作自动重试一次并打开唯一授权页;第二次总共只尝试两次,随后显示可操作的初始化失败提示,不循环、不一直加载,用户可再次发起登录。
AUTH-03 URL 后禁止重放
前置: Core 已发出授权 URL,随后返回 busy 或晚到失败。
- 点击登录并确认浏览器已打开。
- 等待本次操作结束,观察浏览器和客户端日志。
通过: App 不重启本次授权、不再打开第二个 URL,也不创建第二份 profile;已有授权仍可完成,失败时允许用户明确重试并取得新链接。
AUTH-04 异常授权可重新开始
分别使用测试环境制造:浏览器拒绝/服务失败、空授权参数、过期链接、已使用链接。
通过: 每种情况都不激活空 profile 或旧 profile,不残留“登录授权”无限等待;提示能区分失败或过期,并提供“重试”。重试必须取得新链接,批准后可正常登录。
AUTH-05 浏览器账号是最终账号
前置: App 曾登录 A;浏览器当前登录 B,A/B 的组织、网络和资源明显不同。
- 退出 A,从 App 发起登录,在浏览器以 B 批准。
- 检查设置、服务、节点、出口和活动日志。
- 再退出 B,在浏览器切回 A 后重复。
通过: 浏览器实际批准的账号决定 App 身份;B 登录后任何页面均无 A 的姓名、profile、组织、网络或资源,反向切换同样不串号。
AUTH-06 多 profile/endpoint 精确激活
前置: 设备已有 endpoint A/profile A,再从 App 对 endpoint B 发起登录。
- 在浏览器批准 B。
- 记录激活的 endpoint、profile ID、组织 ID 和网络 ID,再刷新资源。
通过: 只激活本次登记生成的 profile B;所有后续 current-context 与目录请求都带 profile B,界面只显示 B 的组织/网络和资源,不按旧指针或列表首项误选 A。
AUTH-07 官方 authority 与三类 pin 完整
前置: 使用候选发布包;准备一台无 Core source 的设备,以及一台已有合法 source 的设备。
- 在无 source 设备首次登录,通过诊断记录核对实际启动参数。
- 在已有 source 设备重新授权,核对原 source 的信任数据。
通过: 首次登录只使用发布包内不可变的官方 authentication authority,并完整传入 Noise public key、QUIC public key、Envelope key pin;三者任一缺失或不匹配都必须失败关闭。远端普通产品配置不能改写该信任根;已有 Core source 也不能被发布包默认 pin 覆盖。
组织与网络切换
APP-04 目录与当前项准确
- 用同一账号准备一个组织/网络组合和多个组合两种数据。
- 打开“当前组织与网络”和切换弹窗。
通过: 组织在上、网络在下,名称与 NSD 一致;当前项清楚且不重复“组织/网络”字样。单组合布局紧凑且不可误切换;多组合均可选择,不显示无权限组合。
APP-05 切换、超时与取消
- 正常切换到另一个网络,切换中尝试操作背景页面。
- 注入慢请求:前 10 秒观察,满 10 秒后点击“取消”。
- 分别让取消被服务端接受、拒绝或与成功响应交错到达。
通过: 使用透明遮罩和居中白色加载弹窗,背景不可操作;10 秒前不出现取消,满 10 秒后可取消。取消是请求,不能先本地伪装成功;最终只呈现服务端确认的旧或新组合。切换完成必须同时匹配 active profile、组织 ID、网络 ID 和 Space 目录,且切换本身不自动连接。
APP-06 刚登录/切换后立即连接
- 登录或切换成功后,在资源刷新仍进行时立即点击连接。
- 同时观察服务、节点和出口刷新。
通过: 连接不因低优先级刷新持续返回 busy,也不等待固定 10 秒;刷新随后正常完成。登录与切换后初始仍是断开,只有用户点击才连接。
APP-07 generation 防旧数据覆盖
- 在网络 A 发起慢刷新,立即切到网络 B 并让 B 刷新先返回。
- 再让 A 的旧请求返回;重复“退出 A 账号后登录 B 账号”的交错请求。
通过: 只接受当前账号、active profile、组织/网络匹配且 generation 更新的结果;A 或较旧 generation 不得覆盖 B。B 的服务、节点、出口和当前项始终保持最新。
服务、节点与出口
APP-08 服务可见性与打开
- 准备本网络自有、授权给当前账号、未授权和另一网络的服务。
- 搜索、刷新并打开 HTTP、TCP/UDP 等已支持服务。
通过: 仅显示当前账号在当前网络可见的服务;搜索、Short DNS、协议、端口、状态和打开方式准确,断开与连接时提示符合真实可用性。
APP-09 节点范围与 Ping
- 准备本账号节点、授权节点、未授权节点和离线节点。
- 查看分组、详情并对允许的节点执行 Ping。
通过: “我的节点”和“已授权给我的节点”分组清楚、标题垂直居中;Node IP、DNS、在线状态与 NSD 一致。只允许访问获准节点,撤权后列表与实际 Ping 都收敛为不可用。
APP-10 未选出口时开启
- 清空已选出口并点击出口开关。
通过: 开关保持关闭,只出现简短提示“请先选择出口”,不弹出多余确认框,不偷偷选择默认出口。
APP-11 出口选择与真实路由
- 打开出口列表,核对候选与间距;选择后开启、切换、关闭。
- 每步检查公网 IP、默认/CIDR 路由、DNS 和私网保留流量。
通过: 全部文案统一为“出口”,列表紧凑且状态明确;开关、运行时和真实流量一致,失败不伪装为已开启,关闭后路由与 DNS 完整恢复。
APP-21 服务菜单恰好两个选项
- 在窄屏手机和桌面端打开服务列表的筛选/分组菜单。
- 分别选择“全部协议”和“按协议分组”。
通过: 菜单恰好只有这两个选项,左右内边距紧凑且可触控;前者为普通列表,后者按协议分组,搜索结果和资源数量不因切换丢失。
页面、平台与生命周期
APP-12 活动日志导航
- 移动端从设置进入活动日志再返回;桌面端从同名入口打开并关闭。
通过: 导航和返回行为与相邻页面一致,导航项、页面标题都叫“活动日志”,不会出现“审计日志”或跳回错误页。
APP-13 通用生命周期
在已连接和断开两种状态分别执行前后台切换、锁屏、休眠、网络切换、系统杀进程与冷启动。
通过: 状态能恢复或给出明确失败;界面连接状态与真实流量一致,不崩溃、不重复登录、不长期停在启动页。
APP-14 普通升级
- 以当前支持版本创建身份、登录、切换组织/网络并保存连接偏好。
- 覆盖安装候选版本;桌面端普通升级来源必须为 build 22 或更高,移动端按正常商店升级路径执行。
通过: 可启动、登录和连接,现有 Device 身份、profile、组织/网络与设置均保留,不触发旧桌面清理。已验证桌面 build 1–21 的一次性迁移不是本用例,必须另跑权限与升级中的专门场景。
APP-15 响应式页面状态
在最小支持手机宽度、横屏、桌面窄窗和宽窗检查服务、节点、出口、设置的加载、空态、错误态和长文本。
通过: 相同层级使用统一间距与对齐;内容不溢出、不大面积无意义留白,错误态不会伪装成空数据。
APP-16 iOS VPN
- 新装后登录,确认尚未连接;首次连接分别测试拒绝和允许系统 VPN 权限。
- 允许后连接/断开,杀掉 App、让系统回收 PacketTunnel 后再连接。
通过: 登录不启动 VPN;拒绝后保持断开并可重试,允许后只建立一个 PacketTunnel。系统回收后可重新准备并连接,退出账号会停止隐藏的 App VPN,但不删除 Device 登记。
APP-17 Android VPN
- 新装登录后首次连接,分别拒绝和允许
VpnService权限。 - 连接/断开,强停 App、系统回收 VPN 后重启并重连。
通过: 登录不启动 VPN;拒绝后无残留通知、TUN 或假连接,重试可再次授权。允许后只有一个前台 VPN 实例,回收后状态收敛并可重连;退出账号先停止隐藏 VPN。
APP-18 macOS Helper
- 在没有 Helper 的 Mac 首次连接,分别拒绝和允许安装/提权。
- 使用带新 Helper 的候选包覆盖升级,再连接与断开。
通过: 只有用户连接时才请求 Helper;拒绝后保持断开且提示可重试。允许后 Helper 版本与 App 匹配,升级能安全替换;断开或退出时清理 App 自己建立的 TUN、路由和 DNS。
APP-19 macOS 单实例、菜单与退出
- 连续启动 App 两次,检查主窗口、菜单栏图标和后台进程。
- 依次使用菜单的打开、连接、断开和退出。
- 分别在 App-owned 与 CLI-owned Core 运行时退出 App。
通过: 只保留一个 App 实例和一个菜单栏图标,菜单状态与主界面一致。退出清理 App-owned 运行时;不得强停 CLI-owned 运行时,遇占用应准确提示而不是再拉起第二个实例。
APP-20 桌面端设备页
- 管理员和普通成员分别打开设备页;准备本人、获准和无权查看的设备。
- 搜索、刷新并查看设备详情,再与当前网络的节点页对照。
通过: 设备页按组织范围展示当前账号获准的 Device,节点页按当前网络展示 Node;二者身份、归属、版本与在线状态一致但不混为同一概念,无权限设备不可见。
APP-22 全部弹窗与版本更新一致
- 在移动端和桌面端依次触发登录失败、空间切换、退出账号、重置设备、连接错误和版本更新弹窗。
- 测试短文案、两行长文案、取消、确认、加载中及失败重试。
通过: 同类弹窗使用一致的遮罩、圆角、标题、正文、按钮顺序和紧凑间距;加载居中,不是白屏或左侧 spinner,背景不可误操作。版本更新弹窗在各平台准确显示版本/build、更新内容和可用动作,不重复弹出、不阻塞启动,取消与升级结果真实。
失败记录
任何崩溃、启动页卡死、无限授权、账号/网络串数据或连接状态与真实流量不一致都按 P0/P1 反馈。测试者只需写复现描述并上传截图、录屏或日志,不要求先判断技术原因。