@harmonyos-arkts/d2h 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +15 -13
- package/.claude-plugin/plugin.json +13 -7
- package/AGENTS.md +5 -5
- package/README.md +212 -212
- package/agents/android-to-hmos-00-orchestrator.md +318 -318
- package/agents/d2h.md +157 -157
- package/dist/bin/install-opencode.js +30 -30
- package/docs/environment-check.md +86 -86
- package/install-opencode.sh +160 -160
- package/opencode/agents.json +16 -16
- package/opencode/vscode-d2h-package.json +7 -7
- package/opencode/vscode-d2h-plugin.mjs +29 -29
- package/package.json +54 -54
- package/schemas/android-source-manifest.schema.json +25 -25
- package/schemas/checkpoint-provenance.schema.json +67 -67
- package/schemas/final-acceptance.schema.json +29 -29
- package/schemas/managed-evidence-index.schema.json +15 -15
- package/schemas/managed-evidence.schema.json +114 -114
- package/schemas/migration-config.schema.json +51 -51
- package/schemas/migration-report-index.schema.json +39 -39
- package/schemas/migration-report-item.schema.json +51 -51
- package/schemas/migration-report-summary.schema.json +25 -25
- package/schemas/migration-status.schema.json +202 -202
- package/schemas/preflight.schema.json +60 -60
- package/schemas/source-order-audit.schema.json +16 -16
- package/schemas/source-provenance-event.schema.json +19 -19
- package/schemas/spec-app-shard.schema.json +45 -45
- package/schemas/spec-fact-corrections-shard.schema.json +13 -13
- package/schemas/spec-features-shard.schema.json +43 -43
- package/schemas/spec-index.schema.json +26 -26
- package/schemas/spec-interactions-shard.schema.json +40 -40
- package/schemas/spec-page.schema.json +98 -98
- package/schemas/spec-pages-index.schema.json +1 -1
- package/schemas/spec-unresolved-shard.schema.json +1 -1
- package/schemas/task-envelope.schema.json +109 -109
- package/schemas/task-plan.schema.json +341 -341
- package/scripts/check-environment.mjs +320 -320
- package/skills/android2hmos_resources_convert/SKILL.md +180 -180
- package/skills/android2hmos_resources_convert/references/image-conversion-rules.md +230 -230
- package/skills/android2hmos_resources_convert/references/svg-fix-patterns.md +175 -175
- package/skills/android2hmos_resources_convert/references/xml-drawable-to-svg-rules.md +513 -513
- package/skills/arkts-app-identity/SKILL.md +238 -238
- package/skills/arkts-i18n/SKILL.md +496 -496
- package/skills/arkts-i18n/evals/evals.json +84 -84
- package/skills/arkts-i18n/references/code-examples.md +302 -302
- package/skills/arkts-i18n/references/common-pitfalls.md +391 -391
- package/skills/arkts-i18n/references/dynamic-language-switch.md +604 -604
- package/skills/arkts-i18n/references/hardcoded-string-scanner.md +348 -348
- package/skills/arkts-i18n/references/language-codes.md +104 -104
- package/skills/arkts-i18n/references/resource-file-structure.md +775 -775
- package/skills/arkts-i18n/references/static-vs-dynamic.md +242 -242
- package/skills/arkts-i18n/references/v1-compat.md +244 -244
- package/skills/arkts-i18n/scripts/audit_i18n_completeness.sh +174 -174
- package/skills/arkts-icon-sizing/SKILL.md +211 -211
- package/skills/arkts-icon-sizing/scripts/icon_audit.py +131 -131
- package/skills/arkts-icon-sizing/scripts/icon_autofix.py +88 -88
- package/skills/arkts-icon-sizing/scripts/icon_dims.py +179 -179
- package/skills/arkts-icon-sizing/scripts/icon_fix.py +119 -119
- package/skills/arkts-mvvm-architecture/SKILL.md +613 -613
- package/skills/d2h-hypium-forge/SKILL.md +309 -309
- package/skills/d2h-hypium-forge/references/functional-spec-template.md +140 -140
- package/skills/d2h-hypium-forge/references/official-api.md +135 -135
- package/skills/d2h-hypium-forge/references/pitfalls.md +98 -98
- package/skills/d2h-hypium-forge/references/testability-template.md +71 -71
- package/skills/d2h-hypium-forge/scripts/_common_template.py +659 -659
- package/skills/d2h-hypium-forge/scripts/analyze_results.py +165 -165
- package/skills/d2h-hypium-forge/scripts/assert_audit.py +107 -107
- package/skills/d2h-hypium-forge/scripts/collect_runtime_pages.py +169 -169
- package/skills/d2h-hypium-forge/scripts/forge_report.py +325 -325
- package/skills/d2h-hypium-forge/scripts/inject_resource_ids.py +114 -114
- package/skills/d2h-hypium-forge/scripts/lint_asserts.py +80 -80
- package/skills/d2h-hypium-forge/scripts/lint_locate.py +60 -60
- package/skills/d2h-hypium-forge/scripts/merge_appgraph.py +249 -249
- package/skills/d2h-hypium-forge/scripts/precondition.py +140 -140
- package/skills/d2h-hypium-forge/scripts/preinject_ids.py +232 -232
- package/skills/d2h-hypium-forge/scripts/probe.py +197 -197
- package/skills/d2h-hypium-forge/scripts/run_direct.py +823 -823
- package/skills/d2h-hypium-forge/scripts/run_parallel.py +121 -121
- package/skills/d2h-hypium-forge/scripts/scan_features.py +255 -255
- package/skills/d2h-hypium-forge/scripts/upgrade_asserts.py +66 -66
- package/skills/d2h-hypium-forge/scripts/validate_scenarios.py +84 -84
- package/skills/d2h-page-develop/SKILL.md +112 -112
- package/skills/d2h-page-develop/agents/openai.yaml +7 -7
- package/skills/d2h-page-spec-generate/SKILL.md +206 -206
- package/skills/d2h-page-spec-generate/scripts/build_batch_report.py +227 -227
- package/skills/d2h-utg-ai-generate/SKILL.md +128 -128
- package/skills/d2h-utg-ai-generate/references/click-paths-schema.json +76 -76
- package/skills/d2h-utg-ai-generate/references/extraction-guide.md +34 -34
- package/skills/d2h-utg-ai-generate/references/facts-contract.md +96 -96
- package/skills/d2h-utg-ai-generate/references/page-schema.json +61 -61
- package/skills/d2h-utg-ai-generate/references/utg-schema.json +89 -89
- package/skills/d2h-utg-ai-generate/scripts/build_page_json.py +314 -314
- package/skills/d2h-utg-ai-generate/scripts/build_utg.py +123 -123
- package/skills/d2h-utg-ai-generate/scripts/capture_from_page_json.ts +280 -280
- package/skills/d2h-utg-ai-generate/scripts/utg_common.py +524 -524
- package/skills/d2h-utg-ai-generate/scripts/utg_html.py +489 -489
- package/skills/d2h-utg-ai-generate/scripts/validate_utg.py +69 -69
- package/skills/d2h-utg-ai-generate/scripts/vendor/D3-LICENSE +13 -13
- package/skills/d2h-utg-ai-generate/scripts/vendor/d3-7.9.0.min.js +2 -2
- package/skills/d2h-utg-ai-generate/tests/test_pipeline.py +369 -369
- package/skills/d2h-utg-static-generate/SKILL.md +73 -73
- package/skills/d2h-utg-static-generate/references/discoveries.md +38 -38
- package/skills/d2h-utg-static-generate/scripts/generate.py +499 -499
- package/skills/d2h-utg-static-generate/tests/test_static.py +335 -335
- package/skills/d2h-utg-static-generate/tests/verify-offline-html.py +60 -60
- package/skills/d2h-utg-static-generate/tests/verify-produced-fixture.py +131 -131
- package/skills/harmonyos-migration-playbook/SKILL.md +83 -83
- package/skills/harmonyos-migration-playbook/agents/openai.yaml +7 -7
- package/skills/harmonyos-migration-playbook/references/arkts-compile.md +24 -24
- package/skills/harmonyos-migration-playbook/references/harmony-runtime.md +53 -53
- package/skills/harmonyos-migration-playbook/references/lesson-lifecycle.md +45 -45
- package/skills/harmonyos-migration-playbook/references/protocol-e2e.md +23 -23
- package/skills/harmonyos-migration-playbook/references/ui-automation.md +53 -53
- package/skills/harmonyos-migration-playbook/references/windows-environment.md +38 -38
- package/skills/maintaining-migration-report/SKILL.md +144 -144
- package/skills/maintaining-migration-report/references/final-acceptance.md +48 -48
- package/skills/maintaining-migration-report/references/source-provenance.md +66 -66
- package/skills/managing-d2h-toolchain/SKILL.md +24 -24
- package/skills/managing-d2h-toolchain/environment-requirements.json +16 -16
- package/skills/managing-d2h-toolchain/scripts/manage-toolchain.mjs +98 -98
- package/skills/managing-d2h-toolchain/toolchain.json +16 -16
- package/skills/native-library-substitution/SKILL.md +384 -384
- package/skills/native-library-substitution/references/native-library-substitution.json +56905 -56905
- package/skills/native-library-substitution/references/native-library-substitution.md +163 -163
- package/skills/preparing-migration-workspace/SKILL.md +131 -131
- package/skills/reviewing-migration-process/SKILL.md +62 -62
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
# 功能规格文档(Functional Spec)— 模板与填写指南
|
|
2
|
-
|
|
3
|
-
> **用途**:转化完成后的功能验证基准。每份 spec 对应一个业务功能域,由**代码理解阶段**产出,
|
|
4
|
-
> 作为 **d2h-hypium-forge 用例设计**的唯一输入。规格 = 测试预期的唯一来源。
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 使用流程
|
|
9
|
-
|
|
10
|
-
```
|
|
11
|
-
安卓源码 → [宿主 agent 代码理解] → functional_spec.md(本文档格式)
|
|
12
|
-
↓
|
|
13
|
-
scenarios.json(场景清单)
|
|
14
|
-
↓
|
|
15
|
-
[d2h-hypium-forge] → testcases/*.py → 执行 → 标定
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## 模板
|
|
21
|
-
|
|
22
|
-
```markdown
|
|
23
|
-
# 功能规格:<功能域名>
|
|
24
|
-
|
|
25
|
-
## 元信息
|
|
26
|
-
| 字段 | 值 |
|
|
27
|
-
|---|---|
|
|
28
|
-
| spec_id | FS-<模块>-<序号>(如 FS-goods-001) |
|
|
29
|
-
| 业务域 | <如:商品/交易/账户/消息> |
|
|
30
|
-
| 安卓源模块 | <如 feature/goods> |
|
|
31
|
-
| 鸿蒙源模块 | <如 features/goods> |
|
|
32
|
-
| 置信度 | <已读全/部分/骨架> |
|
|
33
|
-
| 转化状态 | <已转化/部分转化/未转化> |
|
|
34
|
-
| 可测试性级别 | <A/B/C(对照 testability-requirements.md T-10)> |
|
|
35
|
-
|
|
36
|
-
## 1. 功能概述
|
|
37
|
-
<一段话:用户视角这个功能做什么、核心业务价值、入口路径>
|
|
38
|
-
|
|
39
|
-
## 2. 业务规则(BR)
|
|
40
|
-
| 规则 ID | 规则描述 | 源码依据(安卓) | 源码依据(鸿蒙) | 测试含义 |
|
|
41
|
-
|---|---|---|---|---|
|
|
42
|
-
| BR-01 | <默认值/联动/互斥/守卫> | file.java:L120 | Index.ets:L45 | <翻译成什么断言> |
|
|
43
|
-
| BR-02 | ... | ... | ... | ... |
|
|
44
|
-
|
|
45
|
-
## 3. 状态机
|
|
46
|
-
| 当前态 | 事件/动作 | 次态 | 可观察效果(断言锚点) |
|
|
47
|
-
|---|---|---|---|
|
|
48
|
-
| <初始态> | <用户操作> | <目标态> | <UI 变化/数据变更/系统事件> |
|
|
49
|
-
|
|
50
|
-
## 4. 数据流
|
|
51
|
-
| 输入 | 处理 | 输出 | 断言方式 |
|
|
52
|
-
|---|---|---|---|
|
|
53
|
-
| <用户输入/系统事件> | <业务逻辑> | <UI 变化/持久化/网络请求> | <equals/checked/hilog/absent> |
|
|
54
|
-
|
|
55
|
-
## 5. 断言锚点清单
|
|
56
|
-
| 锚点 | 类型 | 控件 ID / 文本 / hilog | 断言范式 |
|
|
57
|
-
|---|---|---|---|
|
|
58
|
-
| <如:价格文本> | 文本值 | tc_goods_price | equals |
|
|
59
|
-
| <如:加入购物车按钮> | 控件状态 | btn_add_cart | enabled/disabled |
|
|
60
|
-
| <如:加入成功 Toast> | 瞬态浮层 | hilog tag=GoodsVM | hilog_tail |
|
|
61
|
-
| <如:购物车数量> | 结构计数 | goods_item | find_all count |
|
|
62
|
-
|
|
63
|
-
## 6. 边界与异常
|
|
64
|
-
| 场景 | 输入条件 | 预期行为 | 断言要点 |
|
|
65
|
-
|---|---|---|---|
|
|
66
|
-
| <如:库存为 0> | stock=0 | 购买按钮禁用 | checked/disabled |
|
|
67
|
-
| <如:网络断开> | 离线 | 显示空态页 | exist(EmptyNetwork) |
|
|
68
|
-
| <如:未登录> | token 过期 | 跳登录页 | 路由断言 |
|
|
69
|
-
|
|
70
|
-
## 7. 测试场景(直接消费)
|
|
71
|
-
| 场景 ID | 场景描述 | test_intent | 断言范式 | 优先级 |
|
|
72
|
-
|---|---|---|---|---|
|
|
73
|
-
| S-01 | <动宾结构描述> | 功能交互类 | 效果断言 | P0 |
|
|
74
|
-
| S-02 | ... | 配置生效类 | 生效链断言 | P0 |
|
|
75
|
-
| S-03 | ... | 导航流转类 | 终点效果 | P1 |
|
|
76
|
-
|
|
77
|
-
## 8. 依赖与环境
|
|
78
|
-
| 依赖项 | 状态 | 说明 |
|
|
79
|
-
|---|---|---|
|
|
80
|
-
| 登录 | <不需要/Mock 可测/需真实账号> | ... |
|
|
81
|
-
| 网络 | <不需要/Mock Server/真实 API> | ... |
|
|
82
|
-
| 权限 | <无/相机/位置/...> | ... |
|
|
83
|
-
| mock 通道 | <有/无>(如有,说明激活方式) | ... |
|
|
84
|
-
|
|
85
|
-
## 9. 可测试性缺口
|
|
86
|
-
| 缺口 ID | 缺 TR 编号 | 描述 | 影响 | 建议修复 |
|
|
87
|
-
|---|---|---|---|---|
|
|
88
|
-
| G-01 | TR-0501 | Base URL 硬编码 | 无法切 Mock Server | 加配置变量 |
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 填写规则
|
|
94
|
-
|
|
95
|
-
### BR(业务规则)——从源码推导,不从直觉
|
|
96
|
-
|
|
97
|
-
| 来源 | ✅ 正确 | ❌ 错误 |
|
|
98
|
-
|---|---|---|
|
|
99
|
-
| 默认值 | `settings.getBoolean('answer', true)` → "默认开启" | "直觉上应该默认关闭" |
|
|
100
|
-
| 联动 | `if (!answer) { allAngles.setEnabled(false) }` → "关闭应答联动禁用任意角度" | "一般这种开关会联动" |
|
|
101
|
-
| 守卫 | `if (stock <= 0) { button.disabled = true }` → "库存≤0 按钮禁用" | "没库存应该不能买" |
|
|
102
|
-
|
|
103
|
-
> **历史教训**:RTA TC05(守卫条件记错)与 GW 搜索(选中不切主页),两次实证直觉必错。
|
|
104
|
-
|
|
105
|
-
### test_intent 分类与断言范式选型
|
|
106
|
-
|
|
107
|
-
| test_intent | 测试目的 | 正确断言范式 | 反例 |
|
|
108
|
-
|---|---|---|---|
|
|
109
|
-
| 资源渲染类 | 图标/文案加载成功 | exist/equals 即目的本身 | — |
|
|
110
|
-
| 功能交互类 | 操作产生业务效果 | 效果断言(值变化/计数增减/checked 翻转) | 仅 exist |
|
|
111
|
-
| 配置生效类 | 设置改变全局行为 | 生效链(改设置→回业务页→断言输出变化) | 仅在设置页断言 |
|
|
112
|
-
| 导航流转类 | 状态迁移到正确目的地 | 终点效果(城市选中→顶栏变新城市名) | 仅"目标页可达" |
|
|
113
|
-
| 状态机类 | 状态转移规律 | 前置态断言→触发→后置态断言(成对) | 只断后置态 |
|
|
114
|
-
| 数据输入类 | 输入被正确处理 | 输入→输出值断言(搜索词→结果计数) | 仅"页面有结果" |
|
|
115
|
-
|
|
116
|
-
### 优先级
|
|
117
|
-
|
|
118
|
-
| 级别 | 含义 | 分配原则 |
|
|
119
|
-
|---|---|---|
|
|
120
|
-
| P0 | 核心正向路径 | 每个业务域至少 1 条 |
|
|
121
|
-
| P1 | 重要分支/边界 | 联动/互斥/持久化/异常处理 |
|
|
122
|
-
| P2 | 补充场景 | 边缘功能/极端边界 |
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## 示例:FS-goods-001 规格选择弹窗(CoolMall 节选)
|
|
127
|
-
|
|
128
|
-
> 完整版见 `ForgeDemos/CoolMall/docs/functional-spec-goods-001.md`
|
|
129
|
-
|
|
130
|
-
| 规则 ID | 规则描述 | 测试含义 |
|
|
131
|
-
|---|---|---|
|
|
132
|
-
| BR-01 | 初始未选规格,数量默认 1 | 打开弹窗断言"请选择规格"存在 + 数量=1 |
|
|
133
|
-
| BR-02 | 未选规格或库存≤0 → 购买按钮 disabled | `BY.key('btn_buy').enabled(False)` |
|
|
134
|
-
| BR-03 | 价格 fallback:spec.price → goods.price | 选规格后 equals 新价 |
|
|
135
|
-
|
|
136
|
-
| 场景 ID | 场景 | test_intent | 断言 | 优先级 |
|
|
137
|
-
|---|---|---|---|---|
|
|
138
|
-
| S-01 | 选中规格后价格/库存/按钮联动 | 功能交互类 | 值变化 + enabled 翻转 | P0 |
|
|
139
|
-
| S-02 | 立即购买跨页一致性 | 配置生效类 | 订单确认页 equals 规格/单价/数量 | P0 |
|
|
140
|
-
| S-03 | stock=0 时购买拦截 | 功能交互类 | disabled + 点击无跳转 | P1 |
|
|
1
|
+
# 功能规格文档(Functional Spec)— 模板与填写指南
|
|
2
|
+
|
|
3
|
+
> **用途**:转化完成后的功能验证基准。每份 spec 对应一个业务功能域,由**代码理解阶段**产出,
|
|
4
|
+
> 作为 **d2h-hypium-forge 用例设计**的唯一输入。规格 = 测试预期的唯一来源。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 使用流程
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
安卓源码 → [宿主 agent 代码理解] → functional_spec.md(本文档格式)
|
|
12
|
+
↓
|
|
13
|
+
scenarios.json(场景清单)
|
|
14
|
+
↓
|
|
15
|
+
[d2h-hypium-forge] → testcases/*.py → 执行 → 标定
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 模板
|
|
21
|
+
|
|
22
|
+
```markdown
|
|
23
|
+
# 功能规格:<功能域名>
|
|
24
|
+
|
|
25
|
+
## 元信息
|
|
26
|
+
| 字段 | 值 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| spec_id | FS-<模块>-<序号>(如 FS-goods-001) |
|
|
29
|
+
| 业务域 | <如:商品/交易/账户/消息> |
|
|
30
|
+
| 安卓源模块 | <如 feature/goods> |
|
|
31
|
+
| 鸿蒙源模块 | <如 features/goods> |
|
|
32
|
+
| 置信度 | <已读全/部分/骨架> |
|
|
33
|
+
| 转化状态 | <已转化/部分转化/未转化> |
|
|
34
|
+
| 可测试性级别 | <A/B/C(对照 testability-requirements.md T-10)> |
|
|
35
|
+
|
|
36
|
+
## 1. 功能概述
|
|
37
|
+
<一段话:用户视角这个功能做什么、核心业务价值、入口路径>
|
|
38
|
+
|
|
39
|
+
## 2. 业务规则(BR)
|
|
40
|
+
| 规则 ID | 规则描述 | 源码依据(安卓) | 源码依据(鸿蒙) | 测试含义 |
|
|
41
|
+
|---|---|---|---|---|
|
|
42
|
+
| BR-01 | <默认值/联动/互斥/守卫> | file.java:L120 | Index.ets:L45 | <翻译成什么断言> |
|
|
43
|
+
| BR-02 | ... | ... | ... | ... |
|
|
44
|
+
|
|
45
|
+
## 3. 状态机
|
|
46
|
+
| 当前态 | 事件/动作 | 次态 | 可观察效果(断言锚点) |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| <初始态> | <用户操作> | <目标态> | <UI 变化/数据变更/系统事件> |
|
|
49
|
+
|
|
50
|
+
## 4. 数据流
|
|
51
|
+
| 输入 | 处理 | 输出 | 断言方式 |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| <用户输入/系统事件> | <业务逻辑> | <UI 变化/持久化/网络请求> | <equals/checked/hilog/absent> |
|
|
54
|
+
|
|
55
|
+
## 5. 断言锚点清单
|
|
56
|
+
| 锚点 | 类型 | 控件 ID / 文本 / hilog | 断言范式 |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| <如:价格文本> | 文本值 | tc_goods_price | equals |
|
|
59
|
+
| <如:加入购物车按钮> | 控件状态 | btn_add_cart | enabled/disabled |
|
|
60
|
+
| <如:加入成功 Toast> | 瞬态浮层 | hilog tag=GoodsVM | hilog_tail |
|
|
61
|
+
| <如:购物车数量> | 结构计数 | goods_item | find_all count |
|
|
62
|
+
|
|
63
|
+
## 6. 边界与异常
|
|
64
|
+
| 场景 | 输入条件 | 预期行为 | 断言要点 |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| <如:库存为 0> | stock=0 | 购买按钮禁用 | checked/disabled |
|
|
67
|
+
| <如:网络断开> | 离线 | 显示空态页 | exist(EmptyNetwork) |
|
|
68
|
+
| <如:未登录> | token 过期 | 跳登录页 | 路由断言 |
|
|
69
|
+
|
|
70
|
+
## 7. 测试场景(直接消费)
|
|
71
|
+
| 场景 ID | 场景描述 | test_intent | 断言范式 | 优先级 |
|
|
72
|
+
|---|---|---|---|---|
|
|
73
|
+
| S-01 | <动宾结构描述> | 功能交互类 | 效果断言 | P0 |
|
|
74
|
+
| S-02 | ... | 配置生效类 | 生效链断言 | P0 |
|
|
75
|
+
| S-03 | ... | 导航流转类 | 终点效果 | P1 |
|
|
76
|
+
|
|
77
|
+
## 8. 依赖与环境
|
|
78
|
+
| 依赖项 | 状态 | 说明 |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| 登录 | <不需要/Mock 可测/需真实账号> | ... |
|
|
81
|
+
| 网络 | <不需要/Mock Server/真实 API> | ... |
|
|
82
|
+
| 权限 | <无/相机/位置/...> | ... |
|
|
83
|
+
| mock 通道 | <有/无>(如有,说明激活方式) | ... |
|
|
84
|
+
|
|
85
|
+
## 9. 可测试性缺口
|
|
86
|
+
| 缺口 ID | 缺 TR 编号 | 描述 | 影响 | 建议修复 |
|
|
87
|
+
|---|---|---|---|---|
|
|
88
|
+
| G-01 | TR-0501 | Base URL 硬编码 | 无法切 Mock Server | 加配置变量 |
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 填写规则
|
|
94
|
+
|
|
95
|
+
### BR(业务规则)——从源码推导,不从直觉
|
|
96
|
+
|
|
97
|
+
| 来源 | ✅ 正确 | ❌ 错误 |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| 默认值 | `settings.getBoolean('answer', true)` → "默认开启" | "直觉上应该默认关闭" |
|
|
100
|
+
| 联动 | `if (!answer) { allAngles.setEnabled(false) }` → "关闭应答联动禁用任意角度" | "一般这种开关会联动" |
|
|
101
|
+
| 守卫 | `if (stock <= 0) { button.disabled = true }` → "库存≤0 按钮禁用" | "没库存应该不能买" |
|
|
102
|
+
|
|
103
|
+
> **历史教训**:RTA TC05(守卫条件记错)与 GW 搜索(选中不切主页),两次实证直觉必错。
|
|
104
|
+
|
|
105
|
+
### test_intent 分类与断言范式选型
|
|
106
|
+
|
|
107
|
+
| test_intent | 测试目的 | 正确断言范式 | 反例 |
|
|
108
|
+
|---|---|---|---|
|
|
109
|
+
| 资源渲染类 | 图标/文案加载成功 | exist/equals 即目的本身 | — |
|
|
110
|
+
| 功能交互类 | 操作产生业务效果 | 效果断言(值变化/计数增减/checked 翻转) | 仅 exist |
|
|
111
|
+
| 配置生效类 | 设置改变全局行为 | 生效链(改设置→回业务页→断言输出变化) | 仅在设置页断言 |
|
|
112
|
+
| 导航流转类 | 状态迁移到正确目的地 | 终点效果(城市选中→顶栏变新城市名) | 仅"目标页可达" |
|
|
113
|
+
| 状态机类 | 状态转移规律 | 前置态断言→触发→后置态断言(成对) | 只断后置态 |
|
|
114
|
+
| 数据输入类 | 输入被正确处理 | 输入→输出值断言(搜索词→结果计数) | 仅"页面有结果" |
|
|
115
|
+
|
|
116
|
+
### 优先级
|
|
117
|
+
|
|
118
|
+
| 级别 | 含义 | 分配原则 |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| P0 | 核心正向路径 | 每个业务域至少 1 条 |
|
|
121
|
+
| P1 | 重要分支/边界 | 联动/互斥/持久化/异常处理 |
|
|
122
|
+
| P2 | 补充场景 | 边缘功能/极端边界 |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 示例:FS-goods-001 规格选择弹窗(CoolMall 节选)
|
|
127
|
+
|
|
128
|
+
> 完整版见 `ForgeDemos/CoolMall/docs/functional-spec-goods-001.md`
|
|
129
|
+
|
|
130
|
+
| 规则 ID | 规则描述 | 测试含义 |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| BR-01 | 初始未选规格,数量默认 1 | 打开弹窗断言"请选择规格"存在 + 数量=1 |
|
|
133
|
+
| BR-02 | 未选规格或库存≤0 → 购买按钮 disabled | `BY.key('btn_buy').enabled(False)` |
|
|
134
|
+
| BR-03 | 价格 fallback:spec.price → goods.price | 选规格后 equals 新价 |
|
|
135
|
+
|
|
136
|
+
| 场景 ID | 场景 | test_intent | 断言 | 优先级 |
|
|
137
|
+
|---|---|---|---|---|
|
|
138
|
+
| S-01 | 选中规格后价格/库存/按钮联动 | 功能交互类 | 值变化 + enabled 翻转 | P0 |
|
|
139
|
+
| S-02 | 立即购买跨页一致性 | 配置生效类 | 订单确认页 equals 规格/单价/数量 | P0 |
|
|
140
|
+
| S-03 | stock=0 时购买拦截 | 功能交互类 | disabled + 点击无跳转 | P1 |
|
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
# Hypium 官方 API 速查(提炼自 developer.huawei.com 应用UI测试(基于Python)文档)
|
|
2
|
-
|
|
3
|
-
> 源文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/hypium-python-guidelines(2026-06-05 版)
|
|
4
|
-
> 本文只保留生成脚本高频用到的部分;完整语义以官方文档为准。
|
|
5
|
-
|
|
6
|
-
## 工程结构
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
project/
|
|
10
|
-
├── testcases/ # 用例 XXX.py + 同名 XXX.json
|
|
11
|
-
├── resource/ # 模板图片等资源(get_resource_path 优先搜此)
|
|
12
|
-
├── config/user_config.xml
|
|
13
|
-
└── main.py # 入口
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
用例生命周期:`setup`(前置)/ `process`(步骤)/ `teardown`(清理)。Step/CheckPoint/MESSAGE 会进报告。测试套模式:TestSuite 类 + TC_ 前缀自动扫描用例。
|
|
17
|
-
|
|
18
|
-
## 控件定位(BY)
|
|
19
|
-
|
|
20
|
-
**优先级:属性 > 图片 > 比例坐标**(坐标点击前后各做一次属性断言)。
|
|
21
|
-
|
|
22
|
-
```python
|
|
23
|
-
from hypium import BY, UiDriver
|
|
24
|
-
from hypium.model import MatchPattern, UiParam, KeyCode
|
|
25
|
-
|
|
26
|
-
driver.find_component(BY.text("蓝牙")) # 第一个匹配
|
|
27
|
-
driver.find_all_components(BY.type("Button")) # 全部匹配,取 [n]
|
|
28
|
-
driver.touch(BY.text("蓝牙")) # 查找并点击
|
|
29
|
-
|
|
30
|
-
# 模糊匹配(第二个参数)
|
|
31
|
-
BY.text("看过", MatchPattern.CONTAINS) # 模板文案/长标题必用
|
|
32
|
-
BY.text("今天星期", MatchPattern.STARTS_WITH)
|
|
33
|
-
BY.text(".+", MatchPattern.REGEXP)
|
|
34
|
-
|
|
35
|
-
# 组合
|
|
36
|
-
BY.text("蓝牙").type("Button").key("bluetooth_switch")
|
|
37
|
-
|
|
38
|
-
# 相对位置(锚点不可再用相对定位)
|
|
39
|
-
BY.type("Button").isAfter(BY.text("显示通知图标")) # 控件树前序遍历顺序
|
|
40
|
-
BY.type("Image").isBefore(BY.text("账号"))
|
|
41
|
-
BY.type("Image").within(BY.key("nav_container"))
|
|
42
|
-
BY.text("蓝牙").inWindow("com.huawei.hmos.settings") # 限定窗口
|
|
43
|
-
|
|
44
|
-
# XPath(不能与其他属性混用,较慢,兜底用)
|
|
45
|
-
BY.xpath("//*[@text='可用 WLAN']/ancestor::List/ListItemGroup/ListItem[1]//Text/following::Image")
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
支持属性:text/key/type/hint(支持模糊);checkable/longClickable/clickable/scrollable/enabled/focused/selected/checked(bool)。
|
|
49
|
-
|
|
50
|
-
## 图片与坐标
|
|
51
|
-
|
|
52
|
-
```python
|
|
53
|
-
driver.touch_image("/path/template.jpeg") # 需 opencv-python;只匹配最佳一处
|
|
54
|
-
b = driver.find_image("template.jpeg") # 返回 Rect
|
|
55
|
-
driver.touch((0.52, 0.98)) # 比例坐标
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## 窗口
|
|
59
|
-
|
|
60
|
-
```python
|
|
61
|
-
from hypium.model import WindowFilter
|
|
62
|
-
w = driver.find_window(WindowFilter().bundle_name("com.x").actived(True))
|
|
63
|
-
driver.check_window(WindowFilter().focused(True), bundle_name="com.x")
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## 触控
|
|
67
|
-
|
|
68
|
-
```python
|
|
69
|
-
driver.touch(target, mode=UiParam.NORMAL|LONG|DOUBLE, scroll_target=BY.type("Scroll"), wait_time=0.1)
|
|
70
|
-
# scroll_target:在滚动容器内查找并点击——视口外控件首选,勿手工预滑动
|
|
71
|
-
driver.long_click(target, press_time=2, offset=(0.1, 0.1)) # offset 为控件内比例
|
|
72
|
-
driver.swipe(UiParam.UP, distance=40, area=BY.type("Scroll"), side=UiParam.RIGHT, start_point=(0.8,0.8), swipe_time=0.3)
|
|
73
|
-
# ⚠ distance=滑动区域总长百分比(1-100),非像素
|
|
74
|
-
driver.slide((100,200), (300,400), slide_time=0.3) # 精确滑动,起止可为 BY/控件/坐标
|
|
75
|
-
driver.drag(start, end, area=BY.type("Slider"), press_time=1, drag_time=1)
|
|
76
|
-
driver.pinch_in/out(BY.type("Image"), direction="horizontal")
|
|
77
|
-
driver.multi_finger_touch([(0.1,0.2),(0.3,0.4)])
|
|
78
|
-
# 自定义手势
|
|
79
|
-
from hypium.uidriver import Gesture
|
|
80
|
-
g = Gesture().start(pos, 2).move_to(p2).pause(1)
|
|
81
|
-
driver.inject_gesture(g) # 多指:inject_multi_finger_gesture([g1,g2])
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## 输入与按键
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
from hypium.model import InputTextMode
|
|
88
|
-
driver.input_text(BY.type("TextInput"), "hello") # 默认先清空;中文剪贴板粘贴
|
|
89
|
-
driver.input_text(c, "x", mode=InputTextMode().paste(True).addition(True))
|
|
90
|
-
driver.clear_text(BY.type("TextInput"))
|
|
91
|
-
driver.press_key(KeyCode.POWER, mode=UiParam.LONG)
|
|
92
|
-
driver.press_combination_key(KeyCode.CTRL_LEFT, KeyCode.SHIFT_LEFT, KeyCode.F)
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## 应用/设备管理
|
|
96
|
-
|
|
97
|
-
```python
|
|
98
|
-
driver.start_app(bundle, ability, wait_time=1)
|
|
99
|
-
driver.stop_app(bundle)
|
|
100
|
-
driver.install_app(path, "-r")
|
|
101
|
-
driver.uninstall_app(bundle)
|
|
102
|
-
driver.clear_app_data(bundle) # 清应用数据(重置持久化状态首选)
|
|
103
|
-
driver.hdc("list targets")
|
|
104
|
-
driver.shell("ls -l") # 设备侧
|
|
105
|
-
host.shell("dir") # PC 侧
|
|
106
|
-
driver.push_file(local, device_path); driver.pull_file(device, local); driver.has_file(p)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
## 断言
|
|
110
|
-
|
|
111
|
-
```python
|
|
112
|
-
host.check_equal(a, b, "a != b"); host.check_greater(a, b)
|
|
113
|
-
|
|
114
|
-
driver.check_component_exist(BY.type("Button"), expect_exist=True, wait_time=5,
|
|
115
|
-
scroll_target=BY.type("Scroll")) # 负断言 expect_exist=False
|
|
116
|
-
driver.check_component(BY.key("xxx"), checked=True) # 属性断言 kwargs: id/text/key/type/
|
|
117
|
-
# enabled/focused/clickable/scrollable/checked/checkable
|
|
118
|
-
driver.check_image_exist("t.jpeg", similarity=0.95, timeout=3, mode="template"|"sift")
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## 等与轮询
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
comp = driver.wait_for_component(BY.text("xx"), 5) # 秒;找不到返回 None
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## 执行与报告
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
python -m hypium # 交互控制台;run/list/help
|
|
131
|
-
# 常用:run -l Case1;Case2 -sn SN1 -rp report路径 -ta screenshot:true
|
|
132
|
-
# harmonyrun 执行器等价:cd 项目目录 && harmonyrun hypium run . -d SN --case XXX_001
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
报告:`reports/<时间戳>/`(details/ 步骤截图、result/*.xml、log/、summary_report.html、summary.ini、task_info.record)。xdevice 执行器下为 report_data.json(含逐条耗时)。
|
|
1
|
+
# Hypium 官方 API 速查(提炼自 developer.huawei.com 应用UI测试(基于Python)文档)
|
|
2
|
+
|
|
3
|
+
> 源文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/hypium-python-guidelines(2026-06-05 版)
|
|
4
|
+
> 本文只保留生成脚本高频用到的部分;完整语义以官方文档为准。
|
|
5
|
+
|
|
6
|
+
## 工程结构
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
project/
|
|
10
|
+
├── testcases/ # 用例 XXX.py + 同名 XXX.json
|
|
11
|
+
├── resource/ # 模板图片等资源(get_resource_path 优先搜此)
|
|
12
|
+
├── config/user_config.xml
|
|
13
|
+
└── main.py # 入口
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
用例生命周期:`setup`(前置)/ `process`(步骤)/ `teardown`(清理)。Step/CheckPoint/MESSAGE 会进报告。测试套模式:TestSuite 类 + TC_ 前缀自动扫描用例。
|
|
17
|
+
|
|
18
|
+
## 控件定位(BY)
|
|
19
|
+
|
|
20
|
+
**优先级:属性 > 图片 > 比例坐标**(坐标点击前后各做一次属性断言)。
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from hypium import BY, UiDriver
|
|
24
|
+
from hypium.model import MatchPattern, UiParam, KeyCode
|
|
25
|
+
|
|
26
|
+
driver.find_component(BY.text("蓝牙")) # 第一个匹配
|
|
27
|
+
driver.find_all_components(BY.type("Button")) # 全部匹配,取 [n]
|
|
28
|
+
driver.touch(BY.text("蓝牙")) # 查找并点击
|
|
29
|
+
|
|
30
|
+
# 模糊匹配(第二个参数)
|
|
31
|
+
BY.text("看过", MatchPattern.CONTAINS) # 模板文案/长标题必用
|
|
32
|
+
BY.text("今天星期", MatchPattern.STARTS_WITH)
|
|
33
|
+
BY.text(".+", MatchPattern.REGEXP)
|
|
34
|
+
|
|
35
|
+
# 组合
|
|
36
|
+
BY.text("蓝牙").type("Button").key("bluetooth_switch")
|
|
37
|
+
|
|
38
|
+
# 相对位置(锚点不可再用相对定位)
|
|
39
|
+
BY.type("Button").isAfter(BY.text("显示通知图标")) # 控件树前序遍历顺序
|
|
40
|
+
BY.type("Image").isBefore(BY.text("账号"))
|
|
41
|
+
BY.type("Image").within(BY.key("nav_container"))
|
|
42
|
+
BY.text("蓝牙").inWindow("com.huawei.hmos.settings") # 限定窗口
|
|
43
|
+
|
|
44
|
+
# XPath(不能与其他属性混用,较慢,兜底用)
|
|
45
|
+
BY.xpath("//*[@text='可用 WLAN']/ancestor::List/ListItemGroup/ListItem[1]//Text/following::Image")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
支持属性:text/key/type/hint(支持模糊);checkable/longClickable/clickable/scrollable/enabled/focused/selected/checked(bool)。
|
|
49
|
+
|
|
50
|
+
## 图片与坐标
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
driver.touch_image("/path/template.jpeg") # 需 opencv-python;只匹配最佳一处
|
|
54
|
+
b = driver.find_image("template.jpeg") # 返回 Rect
|
|
55
|
+
driver.touch((0.52, 0.98)) # 比例坐标
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 窗口
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from hypium.model import WindowFilter
|
|
62
|
+
w = driver.find_window(WindowFilter().bundle_name("com.x").actived(True))
|
|
63
|
+
driver.check_window(WindowFilter().focused(True), bundle_name="com.x")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 触控
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
driver.touch(target, mode=UiParam.NORMAL|LONG|DOUBLE, scroll_target=BY.type("Scroll"), wait_time=0.1)
|
|
70
|
+
# scroll_target:在滚动容器内查找并点击——视口外控件首选,勿手工预滑动
|
|
71
|
+
driver.long_click(target, press_time=2, offset=(0.1, 0.1)) # offset 为控件内比例
|
|
72
|
+
driver.swipe(UiParam.UP, distance=40, area=BY.type("Scroll"), side=UiParam.RIGHT, start_point=(0.8,0.8), swipe_time=0.3)
|
|
73
|
+
# ⚠ distance=滑动区域总长百分比(1-100),非像素
|
|
74
|
+
driver.slide((100,200), (300,400), slide_time=0.3) # 精确滑动,起止可为 BY/控件/坐标
|
|
75
|
+
driver.drag(start, end, area=BY.type("Slider"), press_time=1, drag_time=1)
|
|
76
|
+
driver.pinch_in/out(BY.type("Image"), direction="horizontal")
|
|
77
|
+
driver.multi_finger_touch([(0.1,0.2),(0.3,0.4)])
|
|
78
|
+
# 自定义手势
|
|
79
|
+
from hypium.uidriver import Gesture
|
|
80
|
+
g = Gesture().start(pos, 2).move_to(p2).pause(1)
|
|
81
|
+
driver.inject_gesture(g) # 多指:inject_multi_finger_gesture([g1,g2])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 输入与按键
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from hypium.model import InputTextMode
|
|
88
|
+
driver.input_text(BY.type("TextInput"), "hello") # 默认先清空;中文剪贴板粘贴
|
|
89
|
+
driver.input_text(c, "x", mode=InputTextMode().paste(True).addition(True))
|
|
90
|
+
driver.clear_text(BY.type("TextInput"))
|
|
91
|
+
driver.press_key(KeyCode.POWER, mode=UiParam.LONG)
|
|
92
|
+
driver.press_combination_key(KeyCode.CTRL_LEFT, KeyCode.SHIFT_LEFT, KeyCode.F)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 应用/设备管理
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
driver.start_app(bundle, ability, wait_time=1)
|
|
99
|
+
driver.stop_app(bundle)
|
|
100
|
+
driver.install_app(path, "-r")
|
|
101
|
+
driver.uninstall_app(bundle)
|
|
102
|
+
driver.clear_app_data(bundle) # 清应用数据(重置持久化状态首选)
|
|
103
|
+
driver.hdc("list targets")
|
|
104
|
+
driver.shell("ls -l") # 设备侧
|
|
105
|
+
host.shell("dir") # PC 侧
|
|
106
|
+
driver.push_file(local, device_path); driver.pull_file(device, local); driver.has_file(p)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 断言
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
host.check_equal(a, b, "a != b"); host.check_greater(a, b)
|
|
113
|
+
|
|
114
|
+
driver.check_component_exist(BY.type("Button"), expect_exist=True, wait_time=5,
|
|
115
|
+
scroll_target=BY.type("Scroll")) # 负断言 expect_exist=False
|
|
116
|
+
driver.check_component(BY.key("xxx"), checked=True) # 属性断言 kwargs: id/text/key/type/
|
|
117
|
+
# enabled/focused/clickable/scrollable/checked/checkable
|
|
118
|
+
driver.check_image_exist("t.jpeg", similarity=0.95, timeout=3, mode="template"|"sift")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 等与轮询
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
comp = driver.wait_for_component(BY.text("xx"), 5) # 秒;找不到返回 None
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 执行与报告
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
python -m hypium # 交互控制台;run/list/help
|
|
131
|
+
# 常用:run -l Case1;Case2 -sn SN1 -rp report路径 -ta screenshot:true
|
|
132
|
+
# harmonyrun 执行器等价:cd 项目目录 && harmonyrun hypium run . -d SN --case XXX_001
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
报告:`reports/<时间戳>/`(details/ 步骤截图、result/*.xml、log/、summary_report.html、summary.ini、task_info.record)。xdevice 执行器下为 report_data.json(含逐条耗时)。
|