@pzy560117/opentest 0.1.14 → 0.1.15

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.14",
2
+ "version": "0.1.15",
3
3
  "languages": [
4
4
  {
5
5
  "id": "en",
@@ -25,6 +25,32 @@ If a repository already has an Android harness, use the closest existing paths b
25
25
 
26
26
  The canonical Midscene slot is `tests/android/midscene/`.
27
27
 
28
+ ## Natural-language GUI scenario rules
29
+
30
+ Midscene-facing GUI scenarios are natural-language Markdown, not command scripts.
31
+ Use `tests/android/midscene/*.md` or `docs/opentest/acceptance/*.md` for concise
32
+ Agent instructions, visual anchors, memory variables, expected visual assertions,
33
+ self-healing notes, and cleanup intent.
34
+
35
+ Do not put `adb`, `python -m pytest`, `npm run`, `aapt`, or `dumpsys` commands in GUI action steps.
36
+ Those commands belong to runner/evidence setup, teardown, security review, and report collection.
37
+
38
+ ## Minimum Midscene harness
39
+
40
+ For `android-app` rows with `visual-acceptance`, `e2e`, or GUI integration evidence, author/heal must create the minimum Midscene harness instead of leaving permanent pytest skips:
41
+
42
+ - `package.json` with `npm run test:android`.
43
+ - `tests/android/midscene/*.test.ts` or Midscene YAML that reads the natural-language scenario.
44
+ - A pytest wrapper that checks device/APK prerequisites, runs ADB smoke, calls `npm run test:android` when model environment is ready, and archives `midscene_run/report/*.html`.
45
+
46
+ If that harness is missing, record an author/heal gap and build it before claiming visual acceptance. ADB-only smoke is valid smoke evidence, not a substitute for Midscene visual evidence.
47
+
48
+ ## Model credential handling
49
+
50
+ Do not ask the user to paste secrets into chat. When no recognized Midscene key is present, ask the user to set process environment variables or confirm the local mapping.
51
+
52
+ Recognized OpenAI-compatible variables normally include `MIDSCENE_MODEL_API_KEY` or `OPENAI_API_KEY`, plus base URL/model variables when the provider needs them. For unknown key variables such as `SSS_API_KEY`, ask for provider, OpenAI-compatible base URL, model name/family, and permission to map that variable for the current process.
53
+
28
54
  ## Default Route
29
55
 
30
56
  ```text
@@ -40,6 +66,7 @@ opentest-android-app
40
66
  User-facing entry is pytest. Prefer `python -m pytest tests_py -v` in an existing Android harness, or `scripts/opentest-run-android.ps1` when the repository owns the fixed layout.
41
67
 
42
68
  Run `npm run test:android` only when Midscene model environment variables are complete or when debugging Midscene directly.
69
+ When model environment variables are complete, the pytest wrapper must call `npm run test:android`; if it cannot, treat the missing bridge as an author/heal gap.
43
70
 
44
71
  ## Required Evidence
45
72
 
@@ -12,20 +12,27 @@
12
12
  - fixture/reset:
13
13
  - status: pending
14
14
 
15
- ### Environment
15
+ ### Natural-Language Scenario
16
16
 
17
- - ADB status:
18
- - model env status:
19
- - app version/build:
20
- - device/app metadata:
21
-
22
- ### Steps
17
+ - precondition:
18
+ - AI memory variables:
19
+ - self-healing notes: permission dialogs, onboarding, keyboard, overlays, scrolling
23
20
 
24
- 1.
21
+ | Step | Agent action instruction | Visual assertion |
22
+ | --- | --- | --- |
23
+ | 1 | | |
25
24
 
26
25
  ### Expected Outcome
27
26
 
28
- -
27
+ -
28
+
29
+ ### Runner/Evidence Setup
30
+
31
+ - tool route: opentest-android-app | android-midscene-pytest | pytest wrapper | @midscene/android
32
+ - ADB status:
33
+ - model env status:
34
+ - app version/build:
35
+ - device/app metadata:
29
36
 
30
37
  ### Read-Back Contract
31
38
 
@@ -27,7 +27,7 @@ Write PASS, FAIL, or blocked evidence to cases and matrix.
27
27
  1. Read the matrix, fixtures, and `docs/opentest/acceptance/`.
28
28
  2. Select the acceptance tool from the matrix execution surface.
29
29
  3. `web-browser`: Playwright MCP/CLI; `@playwright/test` for durable regression; Midscene only for visual assist.
30
- 4. `android-app`: `opentest-android-app` plus `android-midscene-pytest`, `python -m pytest tests_py -v`, ADB smoke, Midscene HTML, logcat, and `midscene_run`; block missing prerequisites.
30
+ 4. `android-app`: execute the natural-language scenario through `opentest-android-app`/`android-midscene-pytest`; keep commands in runner/evidence (ADB smoke, logcat, `midscene_run`). Visual rows need Midscene HTML or blocked/heal evidence.
31
31
  5. `desktop-gui`: `opentest-desktop-gui`, project GUI automation or `@midscene/computer`, screenshot/recording, metadata, and read-back.
32
32
  6. `api`: `opentest-api`, project API command or `pytest` with `httpx`/`requests`, schema, fixtures, read-after-write, and cleanup/teardown.
33
33
  7. For CRUD/data changes, execute the full chain from the workflow reference.
@@ -17,8 +17,9 @@ Use this adapter for `android-app` matrix rows.
17
17
  1. Use `android-midscene-pytest` as the detailed Android execution skill when available.
18
18
  2. Keep durable Android assets in the fixed layout from `test-asset-layout.md`: `tests/android/tests_py/`, `tests/android/midscene/`, and `scripts/opentest-run-android.ps1` or an existing Android harness command.
19
19
  3. User-facing execution should enter through pytest, normally `python -m pytest tests_py -v` in an existing harness or the repository's Android test entry.
20
- 4. Run `npm run test:android` only when model environment variables are ready or when debugging the Midscene layer.
21
- 5. Mark blocked when ADB, emulator/device, APK path, package name, model credentials, fixture data, or stable result surface is missing.
20
+ 4. For visual/e2e rows, ensure a minimum Midscene harness exists (`package.json`, `npm run test:android`, and `tests/android/midscene/`); if missing, route to author/heal.
21
+ 5. Run `npm run test:android` only when model environment variables are ready or when debugging the Midscene layer.
22
+ 6. Mark blocked when ADB, emulator/device, APK path, package name, model credentials, fixture data, or stable result surface is missing.
22
23
 
23
24
  ## Evidence Contract
24
25
 
@@ -21,7 +21,9 @@ Turn the matrix into executable tests, fixtures, seed/teardown notes, and accept
21
21
  1. Read `matrix` and `fixtures` from `.opentest.yaml`.
22
22
  2. Preserve each row's requirement source and expected behavior. Do not rewrite acceptance cases around current implementation names, component internals, or existing test files.
23
23
  3. Place assets in the fixed layout from `test-asset-layout.md`; default to pytest under `tests/` when no project framework exists, and do not convert required framework evidence to `none`. Missing implementation means evidence stays pending.
24
- 4. Create/update fixtures, seed, teardown, users, roles, entities, files/images, and assertion surfaces.
25
- 5. For CRUD/data changes, author the full acceptance flow: create -> list -> detail -> update -> read back -> delete -> confirm absence -> teardown.
26
- 6. Record any gap/blocker with reason and risk.
27
- 7. Write `.opentest.yaml` fields: `fixtures`, `acceptance`, then run `bash "$OPENTEST_GUARD" author --apply`.
24
+ 4. For GUI surfaces, author a natural-language GUI scenario for the agent/Midscene, and keep commands in runner/evidence setup or reports.
25
+ 5. For Android visual/e2e rows, create the minimum Midscene harness: `package.json`, `npm run test:android`, `tests/android/midscene/`, and pytest bridge/report archiving.
26
+ 6. Create/update fixtures, seed, teardown, users, roles, entities, files/images, and assertion surfaces.
27
+ 7. For CRUD/data changes, author the full acceptance flow: create -> list -> detail -> update -> read back -> delete -> confirm absence -> teardown.
28
+ 8. Record any gap/blocker with reason and risk.
29
+ 9. Write `.opentest.yaml` fields: `fixtures`, `acceptance`, then run `bash "$OPENTEST_GUARD" author --apply`.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: opentest-run
3
- description: "OpenTest phase 3: run project verification commands in targeted, fast, full, ci-like, or pre-push mode."
3
+ description: "OpenTest phase 3: run verification."
4
4
  ---
5
5
 
6
6
  # OpenTest Run
7
7
 
8
- Run matrix-driven commands and write reports under `docs/opentest/runs/`.
8
+ Run matrix-driven commands and write run evidence.
9
9
 
10
10
  ## Required references
11
11
 
@@ -30,10 +30,11 @@ Run matrix-driven commands and write reports under `docs/opentest/runs/`.
30
30
  ## Steps
31
31
 
32
32
  1. Read `run_mode`, matrix, fixtures, required evidence, and fixed asset layout.
33
- 2. Choose by matrix execution surface: MCP/CLI or `npx playwright test` for `web-browser`; `opentest-android-app` or `python -m pytest tests_py -v` for `android-app`, with `npm run test:android` only when model env is ready or debugging Midscene; `opentest-desktop-gui` for `desktop-gui`; `opentest-api` or `python -m pytest tests/api -v` for `api`.
34
- 3. Prefer explicit project commands; otherwise use `python -m pytest` for code-level tests.
35
- 4. For coverage, prefer `python -m pytest --cov=. --cov-report=term-missing`.
36
- 5. Smoke evidence is required unless the matrix says not applicable.
37
- 6. For `pre-push`, run or record format/check, lint, type, unit, targeted integration, smoke, and `git diff --check`.
38
- 7. Write `run_report`, `coverage_report`, `smoke_report`, or `pre_push_report` when required.
39
- 8. Run `bash "$OPENTEST_GUARD" run --apply`.
33
+ 2. Choose by matrix execution surface: MCP/CLI or `npx playwright test` for `web-browser`; `opentest-android-app` or `python -m pytest tests_py -v` for `android-app`; `opentest-desktop-gui` for `desktop-gui`; `opentest-api` or `python -m pytest tests/api -v` for `api`.
34
+ 3. For Android visual rows, the pytest wrapper must call `npm run test:android` when model env is ready/debugging; missing harness -> author/heal.
35
+ 4. Prefer explicit project commands; otherwise use `python -m pytest` for code-level tests.
36
+ 5. For coverage, prefer `python -m pytest --cov=. --cov-report=term-missing`.
37
+ 6. Smoke evidence is required unless the matrix says not applicable.
38
+ 7. For `pre-push`, run or record format/check, lint, type, unit, targeted integration, smoke, and `git diff --check`.
39
+ 8. Write `run_report`, `coverage_report`, `smoke_report`, or `pre_push_report` when required.
40
+ 9. Run `bash "$OPENTEST_GUARD" run --apply`.
@@ -25,6 +25,31 @@ scripts/
25
25
 
26
26
  标准 Midscene 槽位是 `tests/android/midscene/`。
27
27
 
28
+ ## 自然语言 GUI 场景
29
+
30
+ 给 Midscene 执行的 GUI 场景必须是自然语言 Markdown,不是命令脚本。
31
+ 使用 `tests/android/midscene/*.md` 或 `docs/opentest/acceptance/*.md` 记录简短的
32
+ Agent 动作指令、视觉锚点、AI 记忆变量、期望视觉断言、自愈说明和清理意图。
33
+
34
+ 不要把 `adb`、`python -m pytest`、`npm run`、`aapt` 或 `dumpsys` 命令写进 GUI 操作步骤。
35
+ 这些命令只属于 runner/evidence 的环境准备、teardown、安全检查和报告采集。
36
+
37
+ ## 最小 Midscene harness
38
+
39
+ 对 `android-app` 中 `visual-acceptance`、`e2e` 或 GUI 集成证据行,author/heal 必须创建最小 Midscene harness,不能只留下永久 pytest skip:
40
+
41
+ - `package.json`,包含 `npm run test:android`。
42
+ - `tests/android/midscene/*.test.ts` 或读取自然语言场景的 Midscene YAML。
43
+ - pytest wrapper 负责检查设备/APK 前置、执行 ADB 冒烟、在模型环境就绪时调用 `npm run test:android`,并归档 `midscene_run/report/*.html`。
44
+
45
+ 缺少该 harness 时,记录 author/heal 缺口并先补齐,再宣称视觉验收。只跑 ADB smoke 可以作为冒烟证据,但不能替代 Midscene 视觉证据。
46
+
47
+ ## 模型凭据处理
48
+
49
+ 不要要求用户把密钥贴到聊天里。没有识别到 Midscene key 时,让用户设置进程环境变量,或确认本地变量映射方式。
50
+
51
+ 常见 OpenAI-compatible 变量包括 `MIDSCENE_MODEL_API_KEY` 或 `OPENAI_API_KEY`,provider 需要时还要 base URL/model 变量。遇到未知 key 变量(如 `SSS_API_KEY`),先询问 provider、OpenAI-compatible base URL、模型名/family,以及是否允许在当前进程做映射许可。
52
+
28
53
  ## 默认路线
29
54
 
30
55
  ```text
@@ -40,6 +65,7 @@ opentest-android-app
40
65
  面向用户的入口是 pytest。优先使用现有 Android harness 中的 `python -m pytest tests_py -v`,或仓库采用固定目录时的 `scripts/opentest-run-android.ps1`。
41
66
 
42
67
  只有 Midscene 模型环境变量齐全,或需要直接排查 Midscene 层时,才运行 `npm run test:android`。
68
+ 模型环境变量齐全时,pytest wrapper 必须调用 `npm run test:android`;不能调用时,把缺失桥接记录为 author/heal 缺口。
43
69
 
44
70
  ## 必需证据
45
71
 
@@ -12,20 +12,27 @@
12
12
  - fixture/reset:
13
13
  - 状态: pending
14
14
 
15
- ### 环境
15
+ ### 自然语言场景
16
16
 
17
- - ADB 状态:
18
- - 模型环境状态:
19
- - App 版本/build:
20
- - 设备/App 元数据:
21
-
22
- ### 步骤
17
+ - 前置状态:
18
+ - AI 记忆变量:
19
+ - 自愈说明: 权限弹窗、首次引导、键盘遮挡、浮层、滚动查找
23
20
 
24
- 1.
21
+ | 步序 | Agent 动作指令 | 视觉断言 |
22
+ | --- | --- | --- |
23
+ | 1 | | |
25
24
 
26
25
  ### 期望结果
27
26
 
28
- -
27
+ -
28
+
29
+ ### Runner/Evidence 准备
30
+
31
+ - 工具路线: opentest-android-app | android-midscene-pytest | pytest wrapper | @midscene/android
32
+ - ADB 状态:
33
+ - 模型环境状态:
34
+ - App 版本/build:
35
+ - 设备/App 元数据:
29
36
 
30
37
  ### 回读契约
31
38
 
@@ -27,7 +27,7 @@ description: "OpenTest 阶段 4:执行自然语言验收、MCP 验收或真实
27
27
  1. 读取矩阵、fixtures 和 `docs/opentest/acceptance/`。
28
28
  2. 根据矩阵里的执行面选择验收工具。
29
29
  3. `web-browser` 使用 `opentest-web-browser`:优先 Playwright MCP,失败时降级 Playwright CLI;稳定回归证据用 `@playwright/test`;视觉补充才用 Midscene。
30
- 4. `android-app` 使用 `opentest-android-app` 和 `android-midscene-pytest`;入口是 `python -m pytest tests_py -v`,收集 pytest、ADB 冒烟、Midscene HTML、截图、logcat、设备/App 元数据和可用的 `midscene_run` 日志。缺前置条件时标为 blocked。
30
+ 4. `android-app` 通过 `opentest-android-app`/`android-midscene-pytest` 执行自然语言场景;`python -m pytest`、ADB 冒烟、logcat `midscene_run` 只属于 runner/evidence。视觉行必须有 Midscene HTML 报告,或记录 blocked/heal evidence
31
31
  5. `desktop-gui` 使用 `opentest-desktop-gui`:优先项目 GUI 自动化,视觉桌面/原生/RDP 流程用 `@midscene/computer`,并收集截图或录屏、GUI 操作日志、窗口/App 元数据和确定性回读。缺 display/RDP、App 启动、目标窗口标识、模型凭据或稳定结果面时标为 blocked。
32
32
  6. `api` 使用 `opentest-api`:优先项目 API 命令;否则用 `pytest` + `httpx`/`requests`、schema 校验、fixtures、写后读和 cleanup/teardown 证据。
33
33
  7. CRUD/数据变更执行 workflow 引用中的完整链路。
@@ -17,8 +17,9 @@ description: "OpenTest 的 Android App 执行面适配器。用于通过 android
17
17
  1. 已安装 `android-midscene-pytest` 时,用它作为详细 Android 执行 skill。
18
18
  2. 稳定 Android 资产放入 `test-asset-layout.md` 的固定目录:`tests/android/tests_py/`、`tests/android/midscene/`,以及 `scripts/opentest-run-android.ps1` 或现有 Android harness 命令。
19
19
  3. 面向用户的执行入口应通过 pytest,通常是现有 harness 中的 `python -m pytest tests_py -v` 或仓库 Android 测试入口。
20
- 4. 只有模型环境变量齐全或排查 Midscene 层时,才运行 `npm run test:android`。
21
- 5. ADB、模拟器/真机、APK 路径、package name、模型凭据、fixture 数据或稳定结果面时,记录 `blocked`。
20
+ 4. visual/e2e 行必须有最小 Midscene harness(`package.json`、`npm run test:android` 和 `tests/android/midscene/`);缺失时转入 author/heal。
21
+ 5. 只有模型环境变量齐全或排查 Midscene 层时,才运行 `npm run test:android`。
22
+ 6. 缺 ADB、模拟器/真机、APK 路径、package name、模型凭据、fixture 数据或稳定结果面时,记录 `blocked`。
22
23
 
23
24
  ## 证据契约
24
25
 
@@ -21,7 +21,9 @@ description: "OpenTest 阶段 2:根据矩阵补齐测试资产、fixtures 和
21
21
  1. 读取 `.opentest.yaml` 的 `matrix` 和 `fixtures`。
22
22
  2. 保留每条矩阵行的需求来源和期望行为。不要围绕当前实现命名、组件内部结构或已有测试文件重写验收用例。
23
23
  3. 资产必须放入 `test-asset-layout.md` 的固定目录;没有项目框架时默认使用 pytest + `tests/`,不得把必需框架证据降级为 `none`。实现缺失只表示证据 pending。
24
- 4. 创建/更新 fixtures、seed、teardown、用户、角色、实体、文件/图片和断言界面。
25
- 5. CRUD/数据变更必须补全链路:新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 -> 确认消失 -> 清理。
26
- 6. 记录 gap/blocker 的原因和风险。
27
- 7. 写入 `.opentest.yaml` `fixtures`、`acceptance`,再运行 `bash "$OPENTEST_GUARD" author --apply`。
24
+ 4. GUI 执行面要写给 Agent/Midscene 的自然语言 GUI 场景,命令只放在 runner/evidence 准备或报告里。
25
+ 5. Android visual/e2e 行必须创建最小 Midscene harness:`package.json`、`npm run test:android`、`tests/android/midscene/`,以及 pytest 桥接/报告归档。
26
+ 6. 创建/更新 fixtures、seed、teardown、用户、角色、实体、文件/图片和断言界面。
27
+ 7. CRUD/数据变更必须补全链路:新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 -> 确认消失 -> 清理。
28
+ 8. 记录 gap/blocker 的原因和风险。
29
+ 9. 写入 `.opentest.yaml` 的 `fixtures`、`acceptance`,再运行 `bash "$OPENTEST_GUARD" author --apply`。
@@ -30,10 +30,11 @@ description: "OpenTest 阶段 3:按 targeted、fast、full、ci-like 或 pre-p
30
30
  ## 步骤
31
31
 
32
32
  1. 读取 `run_mode`、矩阵、fixtures、必需证据和固定资产目录。
33
- 2. 根据矩阵执行面和验收模式选择命令/工具:`web-browser` 走 MCP/CLI 或 `npx playwright test`,`android-app` 走 `opentest-android-app` 或 `python -m pytest tests_py -v`;只有模型环境变量齐全或排查 Midscene 层时才跑 `npm run test:android`;`desktop-gui` 走 `opentest-desktop-gui`,`api` 走 `opentest-api` 或 `python -m pytest tests/api -v`。
34
- 3. 优先使用项目命令;没有代码级命令时用 `python -m pytest`。
35
- 4. 覆盖率优先用 `python -m pytest --cov=. --cov-report=term-missing`。
36
- 5. 除非矩阵写明不适用,否则必须有冒烟证据。
37
- 6. `pre-push` 运行或记录 format/check、lint、type、unit、targeted integration、smoke、`git diff --check`。
38
- 7. 写入 `run_report`,必要时写入 `coverage_report`、`smoke_report`、`pre_push_report`。
39
- 8. 运行 `bash "$OPENTEST_GUARD" run --apply`。
33
+ 2. 根据矩阵执行面和验收模式选择命令/工具:`web-browser` 走 MCP/CLI 或 `npx playwright test`,`android-app` 走 `opentest-android-app` 或 `python -m pytest tests_py -v`;`desktop-gui` 走 `opentest-desktop-gui`,`api` 走 `opentest-api` 或 `python -m pytest tests/api -v`。
34
+ 3. Android 视觉行在模型环境变量就绪时,pytest wrapper 必须调用 `npm run test:android`;桥接/harness 缺失时停止并转入 author/heal。
35
+ 4. 优先使用项目命令;没有代码级命令时用 `python -m pytest`。
36
+ 5. 覆盖率优先用 `python -m pytest --cov=. --cov-report=term-missing`。
37
+ 6. 除非矩阵写明不适用,否则必须有冒烟证据。
38
+ 7. `pre-push` 运行或记录 format/check、lint、type、unit、targeted integration、smoke、`git diff --check`。
39
+ 8. 写入 `run_report`,必要时写入 `coverage_report`、`smoke_report`、`pre_push_report`。
40
+ 9. 运行 `bash "$OPENTEST_GUARD" run --apply`。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pzy560117/opentest",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "OpenTest quality evidence lifecycle skills for Codex",
5
5
  "keywords": [
6
6
  "opentest",
@@ -359,6 +359,8 @@ function assertAndroidAppContracts() {
359
359
  const chineseTemplate = readRequiredText('assets/skills-zh/opentest/templates/android-app-acceptance-template.md', '[ANDROID] missing Chinese Android app template');
360
360
  const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
361
361
  const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
362
+ const englishAuthor = readFileSync('assets/skills/opentest-author/SKILL.md', 'utf8');
363
+ const chineseAuthor = readFileSync('assets/skills-zh/opentest-author/SKILL.md', 'utf8');
362
364
  const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
363
365
  const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
364
366
  const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
@@ -374,6 +376,26 @@ function assertAndroidAppContracts() {
374
376
  assert(chineseReference.includes('适配边界') && chineseReference.includes('tests/android/midscene/') && chineseReference.includes('不得只凭静态截图'), '[ANDROID] Chinese reference must define adapter boundary, layout, and no-static-screenshot rule');
375
377
  assert(englishTemplate.includes('tool route: opentest-android-app | android-midscene-pytest') && englishTemplate.includes('ADB smoke'), '[ANDROID] English template must include route and ADB evidence');
376
378
  assert(chineseTemplate.includes('工具路线: opentest-android-app | android-midscene-pytest') && chineseTemplate.includes('ADB 冒烟'), '[ANDROID] Chinese template must include route and ADB evidence');
379
+ assert(englishReference.includes('Natural-language GUI scenario') && englishReference.includes('Do not put `adb`, `python -m pytest`, `npm run`, `aapt`, or `dumpsys` commands in GUI action steps'), '[ANDROID] English reference must separate natural-language GUI scenarios from runner/evidence commands');
380
+ assert(chineseReference.includes('自然语言 GUI 场景') && chineseReference.includes('不要把 `adb`、`python -m pytest`、`npm run`、`aapt` 或 `dumpsys` 命令写进 GUI 操作步骤'), '[ANDROID] Chinese reference must separate natural-language GUI scenarios from runner/evidence commands');
381
+ assert(englishReference.includes('Minimum Midscene harness') && englishReference.includes('package.json') && englishReference.includes('tests/android/midscene/*.test.ts') && englishReference.includes('npm run test:android'), '[ANDROID] English reference must require a minimum Midscene harness');
382
+ assert(chineseReference.includes('最小 Midscene harness') && chineseReference.includes('package.json') && chineseReference.includes('tests/android/midscene/*.test.ts') && chineseReference.includes('npm run test:android'), '[ANDROID] Chinese reference must require a minimum Midscene harness');
383
+ assert(englishReference.includes('pytest wrapper must call `npm run test:android`') && englishReference.includes('author/heal gap'), '[ANDROID] English reference must make missing harness a heal/author gap instead of permanent skip');
384
+ assert(chineseReference.includes('pytest wrapper 必须调用 `npm run test:android`') && chineseReference.includes('author/heal 缺口'), '[ANDROID] Chinese reference must make missing harness a heal/author gap instead of permanent skip');
385
+ assert(englishReference.includes('unknown key variables such as `SSS_API_KEY`') && englishReference.includes('provider') && englishReference.includes('base URL') && englishReference.includes('permission to map'), '[ANDROID] English reference must ask for unknown model key mapping details');
386
+ assert(chineseReference.includes('未知 key 变量(如 `SSS_API_KEY`)') && chineseReference.includes('provider') && chineseReference.includes('base URL') && chineseReference.includes('映射许可'), '[ANDROID] Chinese reference must ask for unknown model key mapping details');
387
+ assert(englishTemplate.includes('### Natural-Language Scenario') && englishTemplate.includes('Agent action instruction') && englishTemplate.includes('Visual assertion'), '[ANDROID] English Android template must make Midscene scenarios natural-language first');
388
+ assert(chineseTemplate.includes('### 自然语言场景') && chineseTemplate.includes('Agent 动作指令') && chineseTemplate.includes('视觉断言'), '[ANDROID] Chinese Android template must make Midscene scenarios natural-language first');
389
+ assert(englishSkill.includes('minimum Midscene harness') && englishSkill.includes('author/heal'), '[ANDROID] English Android skill must route missing Midscene harness to author/heal');
390
+ assert(chineseSkill.includes('最小 Midscene harness') && chineseSkill.includes('author/heal'), '[ANDROID] Chinese Android skill must route missing Midscene harness to author/heal');
391
+ assert(englishAuthor.includes('natural-language GUI scenario') && englishAuthor.includes('runner/evidence'), '[ANDROID] English author skill must keep GUI cases separate from runner/evidence commands');
392
+ assert(chineseAuthor.includes('自然语言 GUI 场景') && chineseAuthor.includes('runner/evidence'), '[ANDROID] Chinese author skill must keep GUI cases separate from runner/evidence commands');
393
+ assert(englishAuthor.includes('minimum Midscene harness') && englishAuthor.includes('npm run test:android'), '[ANDROID] English author skill must create minimum Midscene harness for Android visual rows');
394
+ assert(chineseAuthor.includes('最小 Midscene harness') && chineseAuthor.includes('npm run test:android'), '[ANDROID] Chinese author skill must create minimum Midscene harness for Android visual rows');
395
+ assert(englishRun.includes('pytest wrapper must call `npm run test:android`') && englishRun.includes('author/heal'), '[ANDROID] English run skill must call Midscene when ready and heal missing harness');
396
+ assert(chineseRun.includes('pytest wrapper 必须调用 `npm run test:android`') && chineseRun.includes('author/heal'), '[ANDROID] Chinese run skill must call Midscene when ready and heal missing harness');
397
+ assert(englishAccept.includes('execute the natural-language scenario') && englishAccept.includes('runner/evidence'), '[ANDROID] English accept skill must execute natural-language scenarios through runner/evidence separation');
398
+ assert(chineseAccept.includes('执行自然语言场景') && chineseAccept.includes('runner/evidence'), '[ANDROID] Chinese accept skill must execute natural-language scenarios through runner/evidence separation');
377
399
 
378
400
  for (const content of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
379
401
  assert(content.includes('opentest/references/android-app-testing.md'), '[ANDROID] plan/run/accept skills must read Android app reference');