# 必测项 → 自动化 转换提示词(子提示词) > **配合主提示词使用**。本文件只覆盖「必测项」专项的特殊处理(来源、结构、映射、双协议、step 级回写)。 > 通用规则——技术栈 / DeviceDriver 接口 / 脚本模板 / 元素发现工作流 / 边跑边写调试 / 失败截图 / 报告——**一律遵循** `prompts/ones_to_automation.md`,此处不重复。 > 冲突时,以本子提示词的「必测项专项」约定为准。 --- ## 1. 必测项来源(ONES) - 团队 `98Q19ZsW`(`sz.ones.cn`) - 测试计划:**`必测项-AI自动化`** plan uuid `CQz9YCNX` - 用例库:**`App 必测项`** library uuid `EPfZfC9Y`(97 条) - `ones` 二进制:`/Users/woan/local/bin/ones` - 读取: ```bash # 列表(注意:list 不返回 steps) /Users/woan/local/bin/ones testcase case list EPfZfC9Y # 单条完整步骤(控制用例必须用这个拿 steps) /Users/woan/local/bin/ones testcase case search --key 15974 # WiFi控制设备 /Users/woan/local/bin/ones testcase case search --key 15975 # 蓝牙控制设备 ``` --- ## 2. 必测项的两种结构(转换前必须理解) 必测项**不是**一种新用例,而是两类已有维度的「视图」: ### A. 添加(connect)—— 按单品,每型号一条 case - 分布在品类模块(摄像头/灯&WiFi/蓝牙/开关/URC HUB/温湿度&hub/Lock/扫地机 类),约 73 条「添加X验证」。 - 每条 ONES case → 一个设备的添加流程 → 落到 `tests//_connect.test.ts`。 - 主键 = ONES 用例号(`number`)。 ### B. 控制(control)—— 2 条超级用例,按连接协议分组,**每个 step = 一个单品的核心控制** | ONES | 名称 | 步数 | 前置条件 | |---|---|---|---| | `15975` (uuid `Lqpkx6mp`) | 蓝牙控制设备 | 49 | 关 WiFi/热点、开蓝牙 | | `15974` (uuid `Vp7vuhbu`) | WiFi控制设备 | 56 | 开 WiFi/热点、关蓝牙 | - 控制粒度在 **step**,不在 case。主键 = `(ones_number, step_uuid)`。 - 同一设备(Bot/Lock/Curtain/Meter…)在两条里都出现 → 两个控制断言(不同协议)。 - camera / robot / osc **只在 WiFi** 出现(本身是 WiFi 设备)。 - 控制内容不止开关:meter 温湿度校正、camera 出流停留 3min、robot 清扫/暂停/回充、Humidifier2 绑温湿度计、curtain/roller 百分比。 - 落到对应设备的 `tests//_control.test.ts`(多数断言主提示词流程里已存在)。 ### C. 非单品(本次不转,除非用户要求) ~12 条平台级:登录/房间/消息中心/场景/覆盖安装。归 `tests/automation/` 或平台用例,不在「各单品添加+控制」范围。 --- ## 3. 落点原则 **必测是「视图」,不是「副本」。不要新建 `tests/必测/` 目录。** 每条必测项映射到已有的 `{device}_connect.test.ts`(添加) / `{device}_control.test.ts`(控制),用**标记 + manifest**去选,而不是搬代码。这与「步骤沉到 `utils/common`、`.test.ts` 只做薄编排」一致。 --- ## 4. 品类模块 → 仓库目录映射 | ONES 模块 | 仓库目录 | |---|---| | 摄像头类 | `camera`(出流类也可拆 `osc`) | | 灯类&WiFi | `ceiling_light` / `strip_light` / `color_bulb` / `humidifier` / `air_condition` | | 蓝牙类 | `curtain` / `sensor` / `fan` / `remote` | | 开关类 | `plug`(含 Relay Switch / Garage Door) | | URC HUB | `hub` / `urc` / `bot` | | 温湿度&hub类 | `meter` / `hub` / `sensor` | | Lock类 | `lock` / `keypad` | | 扫地机类 | `robot` | 设备名取 `config/device.config.ts` 的 `DEVICE_CONFIG`,不要在脚本里写死。 --- ## 5. 映射 manifest(核心产物) 生成 `test-plan/must-test.manifest.ts`,作为「ONES 必测项 ↔ 代码 ↔ 回写 ↔ 覆盖率」的中间层。**双主键**:添加按 case,控制按 step。 ```ts // test-plan/must-test.manifest.ts —— 由 scripts/gen-must-test-manifest.ts 从 ONES 生成,勿手改 export type MustTestItem = | { kind: 'add'; ones: number; name: string; cat: string; device: string; file: string; testName: string; status: 'done'|'todo'|'na' } | { kind: 'ctrl'; ones: 15974|15975; step: string; proto: 'wifi'|'ble'; name: string; cat: string; device: string; action: string; file: string; testName: string; status: 'done'|'todo'|'na' }; export const MUST_TEST: MustTestItem[] = [ { kind:'add', ones:91013, name:'添加Plug验证', cat:'plug', device:'Plug 4D', file:'tests/plug/plug_connect.test.ts', testName:'[P0] 通过BLE添加Plug', status:'todo' }, { kind:'ctrl', ones:15974, step:'', proto:'wifi', name:'点击控制Plug 开/关', cat:'plug', device:'Plug 4D', action:'开/关', file:'tests/plug/plug_control.test.ts', testName:'[P0][ble+wifi] 开/关 Plug', status:'todo' }, // ... 全部 添加 case + 两条控制用例的全部 step ]; ``` **生成脚本要点**(`scripts/gen-must-test-manifest.ts`): 1. `case list EPfZfC9Y` → 取全部「添加X验证」case(模块属品类) → 生成 `kind:'add'` 行。 2. `case search --key 15974/15975` → 遍历 `steps[]`,每步生成 `kind:'ctrl'` 行,带 `step.uuid` / `proto` / 从 `desc` 解析的 `device`+`action`。 3. 用第 4 节映射表填 `cat`,用 `DEVICE_CONFIG` 填 `device`,推断目标 `file`。 4. `status` 初始 `todo`,实现后由测试运行结果回填(见第 9 节)。 --- ## 6. P0 标记约定(带 ONES 锚点) **关键:锚点必须打在 `reporter.record(名称, ...)` 的名称里**——结果写入 `reports/.results.json` 用的是 record 名称,`buildAnchoredPayloads` 从中解析 `[ONES:号(#step)]` 做回写。`it()` 标题里也加同一锚点作**备注**(测试报告里可见、便于追溯),但回写不读 it 标题。 ```ts // it 标题:加 [ONES:号] 作备注(可读/可追溯) it(`[ONES:15968] 通过BLE添加${deviceName}设备`, async () => { // ... // reporter.record 名称:加 [P0][ONES:号] —— 这是回写真正依据 reporter.record(`[P0][ONES:15968] 添加${deviceName}`, 'PASS', dur, detail); }); // 控制(协议相关):record 名称带 用例号#step_uuid + 协议;协议由 PROTO 环境变量切(见 §7) const CTRL = process.env.PROTO === 'wifi' ? '[P0][ONES:15974#][wifi]' : '[P0][ONES:15975#][ble]'; reporter.record(`${CTRL} 开/关 ${deviceName}`, status, dur, detail); ``` - 一条 ONES step 可由多个用例覆盖 → 用同一 step 锚点,回写自动聚合(fail>skip>pass)。 - 筛选:`vitest -t '\[P0\]'`(全量) / 结果文件里按 `[ble]`/`[wifi]` 区分协议。 ### 同品类多型号:设备维度动态锚点 一个品类的脚本只测默认设备,但同品类多个 UI 相似型号(如 Curtain/Curtain3/BlindTilt)应共用脚本、各自回写。**不要写死 ONES 号**,改用 `utils/common/ones-anchor.helper.ts` 按当前设备动态解析: ```ts import { onesAdd, onesCtrl } from '../../utils/common'; const ADD_ANCHOR = onesAdd('curtain', deviceName); // 添加: 按 CURTAIN_DEVICE 解析 const CTRL_CURTAIN = onesCtrl('curtain', deviceName); // 控制: 按设备 + PROTO 解析 reporter.record(`${ADD_ANCHOR} 添加窗帘设备`, ...); ``` - `ANCHORS` map(在 `ones-anchor.helper.ts`)按 `品类 → 设备名(DEVICE_CONFIG) → {add, ctrlBle, ctrlWifi}` 维护;**新增型号补一行即可**。 - 跑法:**换 `_DEVICE` 环境变量按型号多跑几遍**(× PROTO),每遍写到该型号的 ONES 用例。 ```bash CURTAIN_DEVICE='Curtain3 2B' PROTO=ble npx vitest run tests/curtain ``` - 约束:每个型号要是账号里真实存在的设备才能跑(变体覆盖上限 = 真机数量)。 - UI **不相似**的型号(需新写)→ 单独脚本 + 自己的锚点,不走此复用。 --- ## 7. 双协议运行模式(本次确定:双协议覆盖) 控制必测**两种协议都要跑**,以与 ONES 的两条用例 1:1 对齐。协议是**运行模式**,靠前置切换手机网络: - `PROTO=ble`:关 WiFi/热点、开蓝牙 → 跑所有 `[ble]` 控制(对应 15975) - `PROTO=wifi`:开 WiFi/热点、关蓝牙 → 跑所有 `[wifi]` 控制(对应 15974) - 切换动作优先 `adb`(Android)/串口;无法自动化时,按 [[feedback-manual-navigation]] 让用户手动切换并确认后继续。 - 仅在该协议下存在的设备(camera/robot/osc 只在 wifi)才生成对应模式的断言。 ```jsonc // package.json "test:must:add": "vitest run -t '\\[P0\\].*添加'", "test:must:ctrl:ble": "PROTO=ble vitest run -t '\\[P0\\].*\\[ble\\]'", "test:must:ctrl:wifi": "PROTO=wifi vitest run -t '\\[P0\\].*\\[wifi\\]'", "test:must": "npm run test:must:add && npm run test:must:ctrl:ble && npm run test:must:ctrl:wifi" ``` --- ## 8. 控制 step → 断言 转换规则 每个 step 是「操作 + 预期」,转成该设备 control 测试里的一条断言: - `step.desc` = 操作(如「点击控制Bot 不加密开&不加密关&加密按压」)→ 拆成对应控制动作序列。 - `step.result` = 预期(如「对应Bot固件响应动作」)→ 断言(状态变更 / UI 反馈 / 出流成功 / 图表加载)。 - 复杂控制按设备类型走既有 helper:开关类用控制 helper;meter 校正走设置页校正流程;camera 出流后**停留 3min**再断言画面/水印;robot 断言清扫/暂停/回充状态。 - 多数动作主提示词的 control 流程已实现 → 复用,不重写;仅补必测特有断言并打 P0 锚点。 --- ## 9. step 级结果回写 ONES(正确方法:GraphQL mutation) > ⚠️ **必须走 `ones graphql` mutation,不要用 curl 直连 REST `.../cases/update`。** > `ones config show` 会把 token 打码成 `***`,curl 直连必然 `401 AuthFailure.InvalidToken`; > 而 `ones graphql` 复用 CLI 登录认证、无需 token/PAT,且已在权限白名单内。 > 此机制已在 `utils/ones-sync.ts` 的 `postPayloads` 实现,跑 `scripts/sync-ones-results.ts` 即用。 **key 拼接规则(确定式):** - case: `testcase_plan_case--` - step: `testcase_plan_case_step---` **写入 mutation:** ```bash # case 级 ones graphql 'mutation { updateTestcasePlanCase(key: "testcase_plan_case-CQz9YCNX-", result: "passed") { key } }' # step 级(result 字段名是 step_result,不是 execute_result/result) ones graphql 'mutation { updateTestcasePlanCaseStep(key: "testcase_plan_case_step-CQz9YCNX--", step_result: "passed", actual_result: "开/关成功") { key } }' ``` - `result` / `step_result` 取值:`passed` / `failed` / `skipped` / `to_do`(PASS→passed、FAIL→failed、SKIP→skipped)。 **必测项据此:** - **按用例聚合、一趟写完(批量规则)**:同一用例的所有 step 结果先聚合,在**一次回写流程里**写完该用例的全部 step、再写 case 级 result——不要把一个用例的步骤分散到多次回写里逐个触发。(`buildAnchoredPayloads` 已按 caseUUID 聚合 step,`postPayloads` 对一个用例的 steps 连续写完再写 case,即满足此规则。GraphQL 不支持单请求多 mutation,故实现上是同一趟内连续多次 mutation,效果即"一次性更新该用例多个步骤"。) - **添加/功能 case**:只写 case 级 `updateTestcasePlanCase`。 - **控制用例 15974 / 15975**:case 级 result 由 step 聚合(全跑完才 passed/failed,否则 `to_do`)。`[ble]`→15975、`[wifi]`→15974。 - 匹配靠测试名 `[ONES:号#step]` 锚点(已在 `buildAnchoredPayloads` 实现),不用 LCS 误配。 **回写参数已固化(用例固定、仅新增)**:`test-plan/ones-writeback-params.json` 保存了计划全部用例(号→`uuid`)+ 15974/15975 的步骤 uuid。用例与步骤 uuid 与具体计划无关,**plan UUID 是回写时唯一变量**——后续给定任意必测项 plan 链接,取出 planUUID 即可按上面 key 规则拼出所有 case/step key 直接回写,无需重新查 ONES。用例新增后重跑 `npm run gen:writeback-params` 刷新。 **读回校验:** ```bash ones graphql '{ testcasePlanCaseSteps(filter: { testcasePlan: { uuid_in: ["CQz9YCNX"] }, testcaseCase: { uuid_in: [""] } }, limit: 60) { key stepResult actualResult } }' ``` (注意:查询用驼峰 `stepResult`/`actualResult`,filter 用 `testcasePlan`/`testcaseCase` 嵌套 `uuid_in`。) --- ## 10. 覆盖率核对 用 manifest 对照 ONES 必测清单,产出未实现列表: - `add` 行:哪些「添加X」还没有对应 `_connect` 测试。 - `ctrl` 行:两条用例共 105 步,哪些 step 还没对应断言。 - 输出「已实现 / todo / na(无实体设备或暂不支持)」三态,na 必须 `log` 说明原因,不可静默跳过。 --- ## 11. 端到端工作流 1. `gen-must-test-manifest.ts` 从 ONES 拉取 → 生成 `must-test.manifest.ts`。 2. 按 manifest 的 `todo` 行,在对应 `_connect`/`_control` 测试里补断言并打 `[P0][ONES:...]` 锚点(遵循主提示词「边跑边写」)。 3. `npm run test:must`(添加 + ble + wifi 三段);协议切换不可自动化时请用户手动配合。 4. 结果按锚点回写 ONES plan `CQz9YCNX`(添加按 case、控制按 step)。 5. 更新 manifest `status`,刷新覆盖率。 --- ## 相关记忆 [[project-must-test-ones-source]] · [[project-maestro-conversion]] · [[feedback-test-case-reuse]] · [[feedback-manual-navigation]]