@pzy560117/opentest 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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.11",
2
+ "version": "0.1.12",
3
3
  "languages": [
4
4
  {
5
5
  "id": "en",
@@ -60,6 +60,7 @@
60
60
  "localized": [
61
61
  "opentest/SKILL.md",
62
62
  "opentest/references/acceptance-evidence.md",
63
+ "opentest/references/android-app-testing.md",
63
64
  "opentest/references/api-testing.md",
64
65
  "opentest/references/codex-harness-coverage-heuristics.md",
65
66
  "opentest/references/command-routing.md",
@@ -73,6 +74,7 @@
73
74
  "opentest/references/test-surfaces.md",
74
75
  "opentest/references/web-browser-testing.md",
75
76
  "opentest/templates/acceptance-template.md",
77
+ "opentest/templates/android-app-acceptance-template.md",
76
78
  "opentest/templates/api-acceptance-template.md",
77
79
  "opentest/templates/archive-layout.md",
78
80
  "opentest/templates/desktop-gui-acceptance-template.md",
@@ -82,6 +84,7 @@
82
84
  "opentest/templates/report-template.md",
83
85
  "opentest/templates/web-acceptance-template.md",
84
86
  "opentest-accept/SKILL.md",
87
+ "opentest-android-app/SKILL.md",
85
88
  "opentest-api/SKILL.md",
86
89
  "opentest-archive/SKILL.md",
87
90
  "opentest-author/SKILL.md",
@@ -0,0 +1,78 @@
1
+ # Android App Testing
2
+
3
+ Use this reference for `android-app` execution-surface rows.
4
+
5
+ ## Adapter Boundary
6
+
7
+ `opentest-android-app` is the OpenTest execution-surface adapter. It keeps Android app tests visible in installed OpenTest skills and routes detailed execution to `android-midscene-pytest` when available.
8
+
9
+ Do not duplicate the full Android Midscene SOP here. Use this reference to decide the OpenTest matrix, layout, evidence, and blocked rules.
10
+
11
+ ## Default Layout
12
+
13
+ Durable Android assets follow `opentest/references/test-asset-layout.md`:
14
+
15
+ ```text
16
+ tests/android/
17
+ tests_py/
18
+ midscene/
19
+
20
+ scripts/
21
+ opentest-run-android.ps1
22
+ ```
23
+
24
+ If a repository already has an Android harness, use the closest existing paths but keep the same logical slots: pytest wrapper, Midscene scripts, device preparation, and run entry.
25
+
26
+ The canonical Midscene slot is `tests/android/midscene/`.
27
+
28
+ ## Default Route
29
+
30
+ ```text
31
+ opentest-android-app
32
+ -> android-midscene-pytest
33
+ -> pytest wrapper
34
+ -> npm/Vitest wrapper
35
+ -> @midscene/android
36
+ -> ADB + Android emulator/device
37
+ -> screenshots + logcat + Midscene HTML report
38
+ ```
39
+
40
+ 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
+
42
+ Run `npm run test:android` only when Midscene model environment variables are complete or when debugging Midscene directly.
43
+
44
+ ## Required Evidence
45
+
46
+ `android-app` rows require:
47
+
48
+ - pytest report or command output
49
+ - ADB smoke result
50
+ - APK path, package name, emulator/device identity
51
+ - screenshot after key steps
52
+ - logcat or targeted Android logs
53
+ - Midscene HTML report when visual automation runs
54
+ - available `midscene_run/log/ai-call.log`, `agent.log`, `android-device.log`, and `midscene_run/report/*.html`
55
+ - read-after-write or persisted-state proof when the app writes data
56
+
57
+ ## Blocking Rules
58
+
59
+ Record `blocked` when any required prerequisite is missing:
60
+
61
+ - ADB
62
+ - emulator or real device
63
+ - APK path
64
+ - package name or launch activity
65
+ - Midscene model credentials when visual automation is required
66
+ - fixture data, reset path, or stable result surface
67
+
68
+ Do not mark Android app acceptance as PASS from a static screenshot alone.
69
+
70
+ ## Matrix Requirements
71
+
72
+ `android-app` rows must include:
73
+
74
+ - `Execution surface`: `android-app`
75
+ - `Acceptance mode`: `n/a`
76
+ - `Evidence layer`: `visual-acceptance`, `e2e`, `integration`, or `smoke`
77
+ - `Framework/command`: `opentest-android-app`, `android-midscene-pytest`, `python -m pytest tests_py -v`, or `scripts/opentest-run-android.ps1`
78
+ - `Required evidence`: pytest, ADB smoke, Midscene HTML report when used, screenshots, logcat, device/app metadata, `midscene_run` logs, and blocked prerequisites when unavailable
@@ -13,6 +13,7 @@ This reference extracts short rules from the local Codex Harness knowledge base,
13
13
  - `tdd-workflow`
14
14
  - `e2e-runner`
15
15
  - `browser-e2e-testing`
16
+ - `opentest-android-app`
16
17
  - `android-midscene-pytest`
17
18
  - `opentest-desktop-gui`
18
19
  - `opentest-api`
@@ -38,7 +39,7 @@ Choose the execution surface separately from the evidence layer:
38
39
  | Surface | Default route |
39
40
  | --- | --- |
40
41
  | `web-browser` | Chrome DevTools MCP, Playwright CLI, or browser acceptance |
41
- | `android-app` | `android-midscene-pytest` when available; `python -m pytest tests_py -v` drives Midscene Android through ADB |
42
+ | `android-app` | `opentest-android-app`; routes to `android-midscene-pytest` when available, with `python -m pytest tests_py -v` driving Midscene Android through ADB |
42
43
  | `desktop-gui` | `opentest-desktop-gui`; project GUI automation first, `@midscene/computer` for visual/native/RDP GUI flows, or scripted manual GUI acceptance when automation is unavailable |
43
44
  | `api` | `opentest-api`; project API/integration command first, otherwise `pytest` with `httpx`/`requests`, schema checks, fixtures, read-after-write, and cleanup/teardown |
44
45
 
@@ -27,10 +27,12 @@ Primary execution surfaces are:
27
27
  - `desktop-gui`: native desktop GUI, Electron, Tauri, or similar app UI
28
28
  - `api`: HTTP API, RPC, backend workflow, contract, or service endpoint
29
29
 
30
- Do not use unit, component, integration, contract, smoke, or security review as the execution surface. Those are evidence layers or run gates. If an Android GUI requirement is present, route acceptance through the `android-midscene-pytest` skill when available and require pytest/Midscene/screenshot/logcat evidence. If native desktop GUI behavior is present, route acceptance through `opentest-desktop-gui` and require project GUI automation or `@midscene/computer` evidence plus screenshots, GUI action logs, window/app metadata, and deterministic read-back. If API behavior is present, route acceptance through `opentest-api` and require contract, status code, payload/schema, auth/permission, read-after-write, and cleanup/teardown evidence when applicable.
30
+ Do not use unit, component, integration, contract, smoke, or security review as the execution surface. Those are evidence layers or run gates. If an Android GUI requirement is present, route acceptance through `opentest-android-app`, which uses `android-midscene-pytest` when available, and require pytest/Midscene/screenshot/logcat evidence. If native desktop GUI behavior is present, route acceptance through `opentest-desktop-gui` and require project GUI automation or `@midscene/computer` evidence plus screenshots, GUI action logs, window/app metadata, and deterministic read-back. If API behavior is present, route acceptance through `opentest-api` and require contract, status code, payload/schema, auth/permission, read-after-write, and cleanup/teardown evidence when applicable.
31
31
 
32
32
  For `web-browser`, choose an acceptance mode from `opentest/references/web-browser-testing.md`. MCP and Playwright CLI are immediate acceptance routes; durable regression requires a committed repeatable test such as `@playwright/test`.
33
33
 
34
+ For `android-app`, use `opentest/references/android-app-testing.md`. Durable Android assets stay in `tests/android/tests_py/`, `tests/android/midscene/`, and `scripts/opentest-run-android.ps1` or an existing Android harness.
35
+
34
36
  For `desktop-gui`, use `opentest/references/desktop-gui-testing.md`. Electron/Tauri DOM-verifiable flows can stay in `web-browser`; native shell, tray, file picker, menu, OS dialog, installer, updater, RDP, and multi-window behavior stay in `desktop-gui`.
35
37
 
36
38
  For `api`, use `opentest/references/api-testing.md`. Project API/integration commands are preferred; without them, use `pytest` with `httpx` or `requests`, schema checks, fixtures, and deterministic read-back.
@@ -11,7 +11,7 @@ Keep the primary execution surface to one of these four values:
11
11
  | Surface | Use when | Default acceptance path | Required artifacts |
12
12
  | --- | --- | --- | --- |
13
13
  | `web-browser` | Browser-rendered web pages, web apps, admin consoles, SaaS, dashboards | Use `opentest-web-browser`: Playwright MCP first, Playwright CLI fallback, `@playwright/test` for durable regression, Midscene only for visual assist | screenshots, snapshots, post-submit assertions, console/network notes, trace/report when durable |
14
- | `android-app` | Android APK or Android app GUI on emulator/device | Use the `android-midscene-pytest` skill when available: pytest orchestrates, `@midscene/android` executes visual automation, ADB/emulator controls device | pytest report, Midscene HTML report, screenshots, logcat, device/app metadata |
14
+ | `android-app` | Android APK or Android app GUI on emulator/device | Use `opentest-android-app`, which routes to `android-midscene-pytest` when available: pytest orchestrates, `@midscene/android` executes visual automation, ADB/emulator controls device | pytest report, ADB smoke, Midscene HTML report, screenshots, logcat, device/app metadata, `midscene_run` logs |
15
15
  | `desktop-gui` | Native desktop GUI or Electron/Tauri/Windows/macOS/Linux app UI | Use `opentest-desktop-gui`: project GUI automation first; `@midscene/computer` for visual desktop automation, weak selectors, native controls, multi-window flows, or RDP; scripted manual GUI acceptance only when automation is unavailable | screenshots or recording, GUI action log, window/app metadata, deterministic read-back, failure capture |
16
16
  | `api` | HTTP API, RPC, backend workflow, contract, service endpoint | Use `opentest-api`: project API/integration command first; otherwise `pytest` with `httpx` or `requests`, schema checks, fixtures, and read-after-write evidence | request/response records, status codes, payload/schema assertions, auth/permission results, data consistency, cleanup/teardown, logs |
17
17
 
@@ -30,7 +30,7 @@ Examples:
30
30
 
31
31
  ## Android App Surface
32
32
 
33
- For Android GUI work, route through `android-midscene-pytest` when installed:
33
+ For `android-app`, read `opentest/references/android-app-testing.md` or use `opentest-android-app`. It routes through `android-midscene-pytest` when installed:
34
34
 
35
35
  ```text
36
36
  python -m pytest tests_py -v
@@ -0,0 +1,46 @@
1
+ # Android App Acceptance
2
+
3
+ ## ACC-Android-001
4
+
5
+ - execution surface: android-app
6
+ - acceptance mode: n/a
7
+ - tool route: opentest-android-app | android-midscene-pytest | pytest wrapper | @midscene/android
8
+ - evidence layer: visual-acceptance | e2e | integration | smoke
9
+ - APK path:
10
+ - package name:
11
+ - emulator/device:
12
+ - fixture/reset:
13
+ - status: pending
14
+
15
+ ### Environment
16
+
17
+ - ADB status:
18
+ - model env status:
19
+ - app version/build:
20
+ - device/app metadata:
21
+
22
+ ### Steps
23
+
24
+ 1.
25
+
26
+ ### Expected Outcome
27
+
28
+ -
29
+
30
+ ### Read-Back Contract
31
+
32
+ - app result surface:
33
+ - persisted state:
34
+ - refresh/reopen check:
35
+ - cleanup assertion:
36
+
37
+ ### Evidence
38
+
39
+ - status:
40
+ - pytest report:
41
+ - ADB smoke:
42
+ - screenshots:
43
+ - logcat:
44
+ - Midscene HTML report:
45
+ - midscene_run logs:
46
+ - blockers:
@@ -5,7 +5,7 @@
5
5
  | ACC-001 | REQ-001 / user story | create succeeds in web UI | web-browser | instant-acceptance | create | valid fixture entity | entity is created and visible in list/detail | high | browser-acceptance + integration | Playwright MCP / Playwright CLI + project command | create evidence, UI/API/DB assertion, fixture used | none | pending |
6
6
  | ACC-002 | REQ-WEB-REG-001 / regression need | web CRUD has durable regression | web-browser | durable-regression | read/list/detail + end-to-end CRUD | committed E2E test | create -> list -> detail -> update -> read back -> delete is repeatable | high | e2e | `npx playwright test` or project E2E command | test file, trace/report, stable locator assertions | none | pending |
7
7
  | ACC-003 | REQ-WEB-VIS-001 / visual risk | visual web state is verified | web-browser | visual-ai-assist | visual behavior | weak selector or canvas UI | Midscene helps locate UI and deterministic read-back proves result | medium | visual-acceptance | Midscene + Playwright route | Midscene report, screenshot, read/assert result | none | pending |
8
- | ACC-004 | REQ-ANDROID-001 / mobile flow | create succeeds in Android app | android-app | n/a | create | APK installed on emulator/device | task is created and visible after app refresh | high | visual-acceptance + e2e | `android-midscene-pytest` / `python -m pytest tests_py -v` | pytest report, ADB smoke, Midscene HTML report, screenshot, logcat, `midscene_run` logs | missing ADB/APK/device/package/model env if unavailable | pending |
8
+ | ACC-004 | REQ-ANDROID-001 / mobile flow | create succeeds in Android app | android-app | n/a | create | APK installed on emulator/device | task is created and visible after app refresh | high | visual-acceptance + e2e | `opentest-android-app` / `android-midscene-pytest` / `python -m pytest tests_py -v` | pytest report, ADB smoke, Midscene HTML report, screenshot, logcat, device/app metadata, `midscene_run` logs | missing ADB/APK/device/package/model env/result surface if unavailable | pending |
9
9
  | ACC-005 | REQ-DESKTOP-001 / settings workflow | desktop setting saves | desktop-gui | n/a | update | desktop app window is open | setting persists after save and reopen | high | gui-acceptance + integration | `opentest-desktop-gui` / project GUI automation / `@midscene/computer` | screenshot or recording, GUI action log, app/window metadata, deterministic read-back, Midscene/computer report when used | missing display/RDP/app launch/window identity/model env/result surface if unavailable | pending |
10
10
  | ACC-006 | REQ-API-001 / contract | API create succeeds | api | n/a | create | valid request payload | response status and payload confirm created entity | high | contract + integration | `opentest-api` / project API command / `python -m pytest tests/api -v` | request/response record, status code, payload/schema assertion, read-after-write, data consistency, cleanup/teardown | missing base URL/auth/fixture/seed/teardown/dependency/schema/result surface if unavailable | pending |
11
11
  | ACC-007 | Risk: invalid and unauthorized input | failure and boundary paths are handled | api | n/a | failure/boundary | invalid, empty, duplicate, unauthorized, expired, forbidden, or stale fixture data | clear error contract without corrupting data | high | contract + security-review | `opentest-api` / project command / `python -m pytest tests/api -v` | validation, auth/permission, duplicate/idempotency, stale-state, error schema, sensitive-field evidence | none | pending |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: opentest-accept
3
- description: "OpenTest phase 4: execute natural language, MCP, or real workflow acceptance and write back evidence."
3
+ description: "OpenTest phase 4: execute acceptance and write back evidence."
4
4
  ---
5
5
 
6
6
  # OpenTest Accept
@@ -12,10 +12,12 @@ Write PASS, FAIL, or blocked evidence to cases and matrix.
12
12
  - `opentest/references/acceptance-evidence.md`
13
13
  - `opentest/references/complete-testing-workflow.md`
14
14
  - `opentest/references/test-surfaces.md`
15
+ - `opentest/references/android-app-testing.md`
15
16
  - `opentest/references/web-browser-testing.md`
16
17
  - `opentest/references/desktop-gui-testing.md`
17
18
  - `opentest/references/api-testing.md`
18
19
  - `opentest/templates/acceptance-template.md`
20
+ - `opentest/templates/android-app-acceptance-template.md`
19
21
  - `opentest/templates/desktop-gui-acceptance-template.md`
20
22
  - `opentest/templates/api-acceptance-template.md`
21
23
 
@@ -24,7 +26,7 @@ Write PASS, FAIL, or blocked evidence to cases and matrix.
24
26
  1. Read the matrix, fixtures, and `docs/opentest/acceptance/`.
25
27
  2. Select the acceptance tool from the matrix execution surface.
26
28
  3. For `web-browser`, use `opentest-web-browser`: Playwright MCP/CLI, `@playwright/test` for durable regression, Midscene only for visual assist.
27
- 4. For `android-app`, use `android-midscene-pytest`: `python -m pytest tests_py -v`, ADB smoke, Midscene HTML, logcat, and `midscene_run`; block missing prerequisites.
29
+ 4. For `android-app`, use `opentest-android-app` and `android-midscene-pytest`: `python -m pytest tests_py -v`, ADB smoke, Midscene HTML, logcat, and `midscene_run`; block missing prerequisites.
28
30
  5. For `desktop-gui`, use `opentest-desktop-gui`: project GUI automation or `@midscene/computer`, screenshot/recording, metadata, and read-back.
29
31
  6. For `api`, use `opentest-api`: project API command or `pytest` with `httpx`/`requests`, schema checks, fixtures, read-after-write, and cleanup/teardown.
30
32
  7. For CRUD/data changes, execute the full chain from the workflow reference.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: opentest-android-app
3
+ description: "OpenTest Android app execution surface adapter. Use when planning, authoring, running, or accepting Android APK/app GUI workflows through android-midscene-pytest, ADB, emulator/device setup, screenshots, logcat, and Midscene reports."
4
+ ---
5
+
6
+ # OpenTest Android App
7
+
8
+ Use this adapter for `android-app` matrix rows.
9
+
10
+ ## Required references
11
+
12
+ - `opentest/references/android-app-testing.md`
13
+ - `opentest/templates/android-app-acceptance-template.md`
14
+
15
+ ## Route
16
+
17
+ 1. Use `android-midscene-pytest` as the detailed Android execution skill when available.
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
+ 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.
22
+
23
+ ## Evidence Contract
24
+
25
+ PASS requires pytest result, ADB smoke, Midscene HTML report when visual automation runs, screenshots, logcat, device/app metadata, and any available `midscene_run` logs. Static screenshots alone are not Android app acceptance.
@@ -14,6 +14,7 @@ Create plan, matrix, and fixtures before implementation.
14
14
  - `opentest/references/complete-testing-workflow.md`
15
15
  - `opentest/references/test-asset-layout.md`
16
16
  - `opentest/references/test-surfaces.md`
17
+ - `opentest/references/android-app-testing.md`
17
18
  - `opentest/references/web-browser-testing.md`
18
19
  - `opentest/references/desktop-gui-testing.md`
19
20
  - `opentest/references/api-testing.md`
@@ -23,7 +24,7 @@ Create plan, matrix, and fixtures before implementation.
23
24
  1. Read rules, requirements/diff, commands, and detection output.
24
25
  2. Treat requirements and risks as sources; inspect current code only for project facts.
25
26
  3. Apply CRUD baseline and test data rules for data-writing/API/form/file/stateful changes.
26
- 4. Classify execution surface and evidence layer separately: `web-browser`, `android-app`, `desktop-gui`, or `api`; use web modes, `opentest-desktop-gui`, and `opentest-api` where applicable.
27
+ 4. Classify execution surface and evidence layer separately: `web-browser`, `android-app`, `desktop-gui`, or `api`; use `opentest-android-app`, web modes, `opentest-desktop-gui`, and `opentest-api` where applicable.
27
28
  5. Produce a requirement-first matrix with source, behavior, surface, mode, evidence, command, gap/blocker, status, and fixed layout.
28
29
  6. Write `.opentest.yaml` fields: `plan`, `matrix`, `fixtures`.
29
30
  7. Update handoff if present, then run `bash "$OPENTEST_GUARD" plan --apply`.
@@ -13,6 +13,7 @@ Run matrix-driven commands and write reports under `docs/opentest/runs/`.
13
13
  - `opentest/references/complete-testing-workflow.md`
14
14
  - `opentest/references/test-asset-layout.md`
15
15
  - `opentest/references/test-surfaces.md`
16
+ - `opentest/references/android-app-testing.md`
16
17
  - `opentest/references/web-browser-testing.md`
17
18
  - `opentest/references/desktop-gui-testing.md`
18
19
  - `opentest/references/api-testing.md`
@@ -28,7 +29,7 @@ Run matrix-driven commands and write reports under `docs/opentest/runs/`.
28
29
  ## Steps
29
30
 
30
31
  1. Read `run_mode`, matrix, fixtures, required evidence, and fixed asset layout.
31
- 2. Choose by matrix execution surface: MCP/CLI or `npx playwright test` for `web-browser`; `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`.
32
+ 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`.
32
33
  3. Prefer explicit project commands; otherwise use `python -m pytest` for code-level tests.
33
34
  4. For coverage, prefer `python -m pytest --cov=. --cov-report=term-missing`.
34
35
  5. Smoke evidence is required unless the matrix says not applicable.
@@ -0,0 +1,78 @@
1
+ # Android App 测试
2
+
3
+ 用于 `android-app` 执行面的矩阵行。
4
+
5
+ ## 适配边界
6
+
7
+ `opentest-android-app` 是 OpenTest 的执行面适配器。它让 Android App 测试在安装后的 OpenTest skills 中可见,并在可用时把详细执行路由到 `android-midscene-pytest`。
8
+
9
+ 这里不复制完整 Android Midscene SOP。本文只定义 OpenTest 矩阵、目录、证据和阻塞规则。
10
+
11
+ ## 默认目录
12
+
13
+ 稳定 Android 资产遵循 `opentest/references/test-asset-layout.md`:
14
+
15
+ ```text
16
+ tests/android/
17
+ tests_py/
18
+ midscene/
19
+
20
+ scripts/
21
+ opentest-run-android.ps1
22
+ ```
23
+
24
+ 如果仓库已有 Android harness,优先使用最接近的现有路径,但逻辑槽位必须保持一致:pytest wrapper、Midscene 脚本、设备准备和运行入口。
25
+
26
+ 标准 Midscene 槽位是 `tests/android/midscene/`。
27
+
28
+ ## 默认路线
29
+
30
+ ```text
31
+ opentest-android-app
32
+ -> android-midscene-pytest
33
+ -> pytest wrapper
34
+ -> npm/Vitest wrapper
35
+ -> @midscene/android
36
+ -> ADB + Android emulator/device
37
+ -> screenshots + logcat + Midscene HTML report
38
+ ```
39
+
40
+ 面向用户的入口是 pytest。优先使用现有 Android harness 中的 `python -m pytest tests_py -v`,或仓库采用固定目录时的 `scripts/opentest-run-android.ps1`。
41
+
42
+ 只有 Midscene 模型环境变量齐全,或需要直接排查 Midscene 层时,才运行 `npm run test:android`。
43
+
44
+ ## 必需证据
45
+
46
+ `android-app` 行需要:
47
+
48
+ - pytest 报告或命令输出
49
+ - ADB 冒烟结果
50
+ - APK 路径、package name、模拟器/真机标识
51
+ - 关键步骤后的截图
52
+ - logcat 或定向 Android 日志
53
+ - 执行视觉自动化时的 Midscene HTML 报告
54
+ - 可用的 `midscene_run/log/ai-call.log`、`agent.log`、`android-device.log` 和 `midscene_run/report/*.html`
55
+ - App 写数据时的写后读或持久化状态证明
56
+
57
+ ## 阻塞规则
58
+
59
+ 缺少任一必需前置条件时记录 `blocked`:
60
+
61
+ - ADB
62
+ - 模拟器或真机
63
+ - APK 路径
64
+ - package name 或 launch activity
65
+ - 需要视觉自动化时的 Midscene 模型凭据
66
+ - fixture 数据、reset 路径或稳定结果面
67
+
68
+ 不得只凭静态截图把 Android App 验收标为 PASS。
69
+
70
+ ## 矩阵要求
71
+
72
+ `android-app` 行必须包含:
73
+
74
+ - `执行面`:`android-app`
75
+ - `验收模式`:`n/a`
76
+ - `证据层级`:`visual-acceptance`、`e2e`、`integration` 或 `smoke`
77
+ - `框架/命令`:`opentest-android-app`、`android-midscene-pytest`、`python -m pytest tests_py -v` 或 `scripts/opentest-run-android.ps1`
78
+ - `必需证据`:pytest、ADB 冒烟、使用时的 Midscene HTML 报告、截图、logcat、设备/App 元数据、`midscene_run` 日志,以及不可用时的 blocked 前置条件
@@ -13,6 +13,7 @@ OpenTest 应根据变更类型、风险和项目事实选择适用覆盖面。
13
13
  - `tdd-workflow`
14
14
  - `e2e-runner`
15
15
  - `browser-e2e-testing`
16
+ - `opentest-android-app`
16
17
  - `android-midscene-pytest`
17
18
  - `opentest-desktop-gui`
18
19
  - `opentest-api`
@@ -38,7 +39,7 @@ OpenTest 应根据变更类型、风险和项目事实选择适用覆盖面。
38
39
  | 执行面 | 默认路由 |
39
40
  | --- | --- |
40
41
  | `web-browser` | Chrome DevTools MCP、Playwright CLI 或浏览器验收 |
41
- | `android-app` | 已安装时使用 `android-midscene-pytest`;`python -m pytest tests_py -v` 通过 ADB 驱动 Midscene Android |
42
+ | `android-app` | `opentest-android-app`;已安装时路由到 `android-midscene-pytest`,由 `python -m pytest tests_py -v` 通过 ADB 驱动 Midscene Android |
42
43
  | `desktop-gui` | `opentest-desktop-gui`;优先项目 GUI 自动化,视觉/原生/RDP GUI 流程用 `@midscene/computer`,无自动化时才用脚本化人工 GUI 验收 |
43
44
  | `api` | `opentest-api`;优先项目 API/integration 命令,否则用 `pytest` + `httpx`/`requests`、schema 校验、fixtures、写后读和 cleanup/teardown |
44
45
 
@@ -27,10 +27,12 @@ unit、component、integration、contract、E2E、smoke、browser acceptance 都
27
27
  - `desktop-gui`:原生桌面 GUI、Electron、Tauri 或类似 App UI
28
28
  - `api`:HTTP API、RPC、后端工作流、契约或服务端点
29
29
 
30
- 不得把 unit、component、integration、contract、smoke 或 security review 当成执行面;它们是证据层级或运行门禁。如果存在 Android GUI 需求,已安装 `android-midscene-pytest` 时用它执行验收,并要求 pytest/Midscene/截图/logcat 证据。如果存在原生桌面 GUI 行为,用 `opentest-desktop-gui` 执行验收,并要求项目 GUI 自动化或 `@midscene/computer` 证据,加上截图、GUI 操作日志、窗口/App 元数据和确定性回读。如果存在 API 行为,用 `opentest-api` 执行验收,并按适用性要求契约、状态码、payload/schema、鉴权/权限、写后读和 cleanup/teardown 证据。
30
+ 不得把 unit、component、integration、contract、smoke 或 security review 当成执行面;它们是证据层级或运行门禁。如果存在 Android GUI 需求,用 `opentest-android-app` 执行验收,并在可用时路由到 `android-midscene-pytest`,要求 pytest/Midscene/截图/logcat 证据。如果存在原生桌面 GUI 行为,用 `opentest-desktop-gui` 执行验收,并要求项目 GUI 自动化或 `@midscene/computer` 证据,加上截图、GUI 操作日志、窗口/App 元数据和确定性回读。如果存在 API 行为,用 `opentest-api` 执行验收,并按适用性要求契约、状态码、payload/schema、鉴权/权限、写后读和 cleanup/teardown 证据。
31
31
 
32
32
  `web-browser` 必须按 `opentest/references/web-browser-testing.md` 选择验收模式。MCP 和 Playwright CLI 是现场验收路径;稳定回归必须有已提交、可重复运行的测试,例如 `@playwright/test`。
33
33
 
34
+ `android-app` 使用 `opentest/references/android-app-testing.md`。稳定 Android 资产放在 `tests/android/tests_py/`、`tests/android/midscene/` 和 `scripts/opentest-run-android.ps1`,或现有 Android harness 的等价位置。
35
+
34
36
  `desktop-gui` 使用 `opentest/references/desktop-gui-testing.md`。Electron/Tauri 的 DOM 可验证流程可以保留在 `web-browser`;原生外壳、托盘、文件选择器、菜单、系统弹窗、安装器、更新器、RDP 和多窗口行为保留在 `desktop-gui`。
35
37
 
36
38
  `api` 使用 `opentest/references/api-testing.md`。优先项目 API/integration 命令;没有项目命令时,用 `pytest` + `httpx` 或 `requests`、schema 校验、fixtures 和确定性回读。
@@ -11,7 +11,7 @@ OpenTest 同时按执行面和证据层级分类验收:
11
11
  | 执行面 | 适用场景 | 默认验收路径 | 必需产物 |
12
12
  | --- | --- | --- | --- |
13
13
  | `web-browser` | 浏览器渲染的 Web 页面、Web App、后台、SaaS、仪表盘 | 使用 `opentest-web-browser`:优先 Playwright MCP,失败时降级 Playwright CLI;稳定回归用 `@playwright/test`;视觉补充才用 Midscene | 截图、snapshot、提交后断言、console/network 记录、稳定回归的 trace/report |
14
- | `android-app` | Android APK 或模拟器/真机上的 Android App GUI | `android-midscene-pytest` skill 时使用它:pytest 编排,`@midscene/android` 执行视觉自动化,ADB/模拟器控制设备 | pytest 报告、Midscene HTML 报告、截图、logcat、设备/App 元数据 |
14
+ | `android-app` | Android APK 或模拟器/真机上的 Android App GUI | 使用 `opentest-android-app`,并在可用时路由到 `android-midscene-pytest`:pytest 编排,`@midscene/android` 执行视觉自动化,ADB/模拟器控制设备 | pytest 报告、ADB 冒烟、Midscene HTML 报告、截图、logcat、设备/App 元数据、`midscene_run` 日志 |
15
15
  | `desktop-gui` | 原生桌面 GUI 或 Electron/Tauri/Windows/macOS/Linux App UI | 使用 `opentest-desktop-gui`:优先项目 GUI 自动化;视觉桌面自动化、弱选择器、原生控件、多窗口流程或 RDP 用 `@midscene/computer`;没有自动化时才用脚本化人工 GUI 验收 | 截图或录屏、GUI 操作日志、窗口/App 元数据、确定性回读、失败截图 |
16
16
  | `api` | HTTP API、RPC、后端工作流、契约、服务端点 | 使用 `opentest-api`:优先项目 API/integration 命令;否则用 `pytest` + `httpx` 或 `requests`、schema 校验、fixtures 和写后读证据 | 请求/响应记录、状态码、payload/schema 断言、鉴权/权限结果、数据一致性、cleanup/teardown、日志 |
17
17
 
@@ -30,7 +30,7 @@ OpenTest 同时按执行面和证据层级分类验收:
30
30
 
31
31
  ## Android App 执行面
32
32
 
33
- Android GUI 工作如果已安装 `android-midscene-pytest`,默认路由到它:
33
+ `android-app` 行读取 `opentest/references/android-app-testing.md`,或调用 `opentest-android-app`。它会在已安装时路由到 `android-midscene-pytest`:
34
34
 
35
35
  ```text
36
36
  python -m pytest tests_py -v
@@ -0,0 +1,46 @@
1
+ # Android App 验收
2
+
3
+ ## ACC-Android-001
4
+
5
+ - 执行面: android-app
6
+ - 验收模式: n/a
7
+ - 工具路线: opentest-android-app | android-midscene-pytest | pytest wrapper | @midscene/android
8
+ - 证据层级: visual-acceptance | e2e | integration | smoke
9
+ - APK 路径:
10
+ - package name:
11
+ - 模拟器/真机:
12
+ - fixture/reset:
13
+ - 状态: pending
14
+
15
+ ### 环境
16
+
17
+ - ADB 状态:
18
+ - 模型环境状态:
19
+ - App 版本/build:
20
+ - 设备/App 元数据:
21
+
22
+ ### 步骤
23
+
24
+ 1.
25
+
26
+ ### 期望结果
27
+
28
+ -
29
+
30
+ ### 回读契约
31
+
32
+ - App 结果面:
33
+ - 持久化状态:
34
+ - 刷新/重开检查:
35
+ - cleanup 断言:
36
+
37
+ ### 证据
38
+
39
+ - 状态:
40
+ - pytest 报告:
41
+ - ADB 冒烟:
42
+ - 截图:
43
+ - logcat:
44
+ - Midscene HTML 报告:
45
+ - midscene_run 日志:
46
+ - 阻塞项:
@@ -5,7 +5,7 @@
5
5
  | ACC-001 | REQ-001 / 用户故事 | Web UI 新增成功 | web-browser | instant-acceptance | 新增 | 有效 fixture 实体 | 创建成功,并能在列表/详情中看到 | high | browser-acceptance + integration | Playwright MCP / Playwright CLI + 项目命令 | 新增证据、UI/API/DB 断言、使用的测试数据 | 无 | pending |
6
6
  | ACC-002 | REQ-WEB-REG-001 / 回归需求 | Web CRUD 有稳定回归 | web-browser | durable-regression | 查询/列表/详情 + 端到端 CRUD | 已提交 E2E 测试 | 新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 可重复验证 | high | e2e | `npx playwright test` 或项目 E2E 命令 | 测试文件、trace/report、稳定 locator 断言 | 无 | pending |
7
7
  | ACC-003 | REQ-WEB-VIS-001 / 视觉风险 | Web 视觉状态可验证 | web-browser | visual-ai-assist | 视觉行为 | 弱选择器或 canvas UI | Midscene 辅助定位 UI,确定性回读证明结果 | medium | visual-acceptance | Midscene + Playwright 路由 | Midscene 报告、截图、回读断言结果 | 无 | pending |
8
- | ACC-004 | REQ-ANDROID-001 / 移动端流程 | Android App 新增成功 | android-app | n/a | 新增 | APK 已安装到模拟器/真机 | 任务创建成功,刷新后仍可见 | high | visual-acceptance + e2e | `android-midscene-pytest` / `python -m pytest tests_py -v` | pytest 报告、ADB 冒烟、Midscene HTML 报告、截图、logcat、`midscene_run` 日志 | 缺 ADB/APK/设备/package/模型环境变量时阻塞 | pending |
8
+ | ACC-004 | REQ-ANDROID-001 / 移动端流程 | Android App 新增成功 | android-app | n/a | 新增 | APK 已安装到模拟器/真机 | 任务创建成功,刷新后仍可见 | high | visual-acceptance + e2e | `opentest-android-app` / `android-midscene-pytest` / `python -m pytest tests_py -v` | pytest 报告、ADB 冒烟、Midscene HTML 报告、截图、logcat、设备/App 元数据、`midscene_run` 日志 | 缺 ADB/APK/设备/package/模型环境变量/结果面时阻塞 | pending |
9
9
  | ACC-005 | REQ-DESKTOP-001 / 设置流程 | 桌面设置保存成功 | desktop-gui | n/a | 修改 | 桌面应用窗口已打开 | 设置保存并在重开后仍生效 | high | gui-acceptance + integration | `opentest-desktop-gui` / 项目 GUI 自动化 / `@midscene/computer` | 截图或录屏、GUI 操作日志、App/窗口元数据、确定性回读、使用 Midscene/computer 时的报告 | 缺 display/RDP/App 启动/窗口标识/模型环境变量/结果面时阻塞 | pending |
10
10
  | ACC-006 | REQ-API-001 / 契约 | API 新增成功 | api | n/a | 新增 | 合法请求 payload | 响应状态码和 payload 证明实体已创建 | high | contract + integration | `opentest-api` / 项目 API 命令 / `python -m pytest tests/api -v` | 请求/响应记录、状态码、payload/schema 断言、写后读、数据一致性、cleanup/teardown | 缺 base URL/auth/fixture/seed/teardown/依赖/schema/结果面时阻塞 | pending |
11
11
  | ACC-007 | 风险:非法和无权限输入 | 失败/边界路径可控 | api | n/a | 失败/边界 | 非法、空、重复、未登录、无权限、过期或 stale fixture 数据 | 给出清晰错误契约且不污染数据 | high | contract + security-review | `opentest-api` / 项目命令 / `python -m pytest tests/api -v` | 校验、鉴权/权限、重复/幂等、stale-state、错误 schema、敏感字段证据 | 无 | pending |
@@ -12,10 +12,12 @@ description: "OpenTest 阶段 4:执行自然语言验收、MCP 验收或真实
12
12
  - `opentest/references/acceptance-evidence.md`
13
13
  - `opentest/references/complete-testing-workflow.md`
14
14
  - `opentest/references/test-surfaces.md`
15
+ - `opentest/references/android-app-testing.md`
15
16
  - `opentest/references/web-browser-testing.md`
16
17
  - `opentest/references/desktop-gui-testing.md`
17
18
  - `opentest/references/api-testing.md`
18
19
  - `opentest/templates/acceptance-template.md`
20
+ - `opentest/templates/android-app-acceptance-template.md`
19
21
  - `opentest/templates/desktop-gui-acceptance-template.md`
20
22
  - `opentest/templates/api-acceptance-template.md`
21
23
 
@@ -24,7 +26,7 @@ description: "OpenTest 阶段 4:执行自然语言验收、MCP 验收或真实
24
26
  1. 读取矩阵、fixtures 和 `docs/opentest/acceptance/`。
25
27
  2. 根据矩阵里的执行面选择验收工具。
26
28
  3. `web-browser` 使用 `opentest-web-browser`:优先 Playwright MCP,失败时降级 Playwright CLI;稳定回归证据用 `@playwright/test`;视觉补充才用 Midscene。
27
- 4. `android-app` 已安装 `android-midscene-pytest` 时使用它;入口是 `python -m pytest tests_py -v`,收集 pytest、ADB 冒烟、Midscene HTML、截图、logcat、设备/App 元数据和可用的 `midscene_run` 日志。缺 ADB、模拟器/真机、APK、package 或模型凭据时标为 blocked。
29
+ 4. `android-app` 使用 `opentest-android-app` 和 `android-midscene-pytest`;入口是 `python -m pytest tests_py -v`,收集 pytest、ADB 冒烟、Midscene HTML、截图、logcat、设备/App 元数据和可用的 `midscene_run` 日志。缺前置条件时标为 blocked。
28
30
  5. `desktop-gui` 使用 `opentest-desktop-gui`:优先项目 GUI 自动化,视觉桌面/原生/RDP 流程用 `@midscene/computer`,并收集截图或录屏、GUI 操作日志、窗口/App 元数据和确定性回读。缺 display/RDP、App 启动、目标窗口标识、模型凭据或稳定结果面时标为 blocked。
29
31
  6. `api` 使用 `opentest-api`:优先项目 API 命令;否则用 `pytest` + `httpx`/`requests`、schema 校验、fixtures、写后读和 cleanup/teardown 证据。
30
32
  7. CRUD/数据变更执行 workflow 引用中的完整链路。
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: opentest-android-app
3
+ description: "OpenTest 的 Android App 执行面适配器。用于通过 android-midscene-pytest、ADB、模拟器/真机、截图、logcat 和 Midscene 报告规划、编写、运行与验收 Android APK/App GUI 工作流。"
4
+ ---
5
+
6
+ # OpenTest Android App
7
+
8
+ 用于矩阵中的 `android-app` 执行面。
9
+
10
+ ## 必读引用
11
+
12
+ - `opentest/references/android-app-testing.md`
13
+ - `opentest/templates/android-app-acceptance-template.md`
14
+
15
+ ## 路由
16
+
17
+ 1. 已安装 `android-midscene-pytest` 时,用它作为详细 Android 执行 skill。
18
+ 2. 稳定 Android 资产放入 `test-asset-layout.md` 的固定目录:`tests/android/tests_py/`、`tests/android/midscene/`,以及 `scripts/opentest-run-android.ps1` 或现有 Android harness 命令。
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`。
22
+
23
+ ## 证据契约
24
+
25
+ PASS 必须包含 pytest 结果、ADB 冒烟、执行视觉自动化时的 Midscene HTML 报告、截图、logcat、设备/App 元数据,以及可用的 `midscene_run` 日志。静态截图本身不等于 Android App 验收。
@@ -14,6 +14,7 @@ description: "OpenTest 阶段 1:分析变更、风险和项目事实,生成
14
14
  - `opentest/references/complete-testing-workflow.md`
15
15
  - `opentest/references/test-asset-layout.md`
16
16
  - `opentest/references/test-surfaces.md`
17
+ - `opentest/references/android-app-testing.md`
17
18
  - `opentest/references/web-browser-testing.md`
18
19
  - `opentest/references/desktop-gui-testing.md`
19
20
  - `opentest/references/api-testing.md`
@@ -23,7 +24,7 @@ description: "OpenTest 阶段 1:分析变更、风险和项目事实,生成
23
24
  1. 读取规则、需求/设计/请求/diff、现有命令和 detect 输出。
24
25
  2. 把需求、流程、业务规则和风险当成验收来源;读取当前代码只用于发现项目事实,例如命令、路由、框架、fixtures 和 helper。
25
26
  3. 数据写入、API、表单、文件或有状态流程默认套用 CRUD 基线和测试数据要求。
26
- 4. 分开判定执行面和证据层级。执行面只能是 `web-browser`、`android-app`、`desktop-gui` 或 `api`;Web 行必须写验收模式,原生桌面行用 `opentest-desktop-gui`,API 行用 `opentest-api`。
27
+ 4. 分开判定执行面和证据层级。执行面只能是 `web-browser`、`android-app`、`desktop-gui` 或 `api`;Android 行用 `opentest-android-app`,Web 行必须写验收模式,原生桌面行用 `opentest-desktop-gui`,API 行用 `opentest-api`。
27
28
  5. 生成需求先行矩阵,包含来源、行为、执行面、验收模式、证据层级、命令/工具、证据、缺口/阻塞、状态和固定资产目录。
28
29
  6. 写入 `.opentest.yaml` 的 `plan`、`matrix`、`fixtures`。
29
30
  7. 如存在 handoff,同步 plan/matrix/fixtures 路径,然后运行 `bash "$OPENTEST_GUARD" plan --apply`。
@@ -13,6 +13,7 @@ description: "OpenTest 阶段 3:按 targeted、fast、full、ci-like 或 pre-p
13
13
  - `opentest/references/complete-testing-workflow.md`
14
14
  - `opentest/references/test-asset-layout.md`
15
15
  - `opentest/references/test-surfaces.md`
16
+ - `opentest/references/android-app-testing.md`
16
17
  - `opentest/references/web-browser-testing.md`
17
18
  - `opentest/references/desktop-gui-testing.md`
18
19
  - `opentest/references/api-testing.md`
@@ -28,7 +29,7 @@ description: "OpenTest 阶段 3:按 targeted、fast、full、ci-like 或 pre-p
28
29
  ## 步骤
29
30
 
30
31
  1. 读取 `run_mode`、矩阵、fixtures、必需证据和固定资产目录。
31
- 2. 根据矩阵执行面和验收模式选择命令/工具:`web-browser` 走 MCP/CLI 或 `npx playwright test`,`android-app` 走 `python -m pytest tests_py -v`;只有模型环境变量齐全或排查 Midscene 层时才跑 `npm run test:android`;`desktop-gui` 走 `opentest-desktop-gui`、项目 GUI 自动化或 `@midscene/computer`,`api` 走 `opentest-api`、项目 API 命令或 `python -m pytest tests/api -v`。
32
+ 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`。
32
33
  3. 优先使用项目命令;没有代码级命令时用 `python -m pytest`。
33
34
  4. 覆盖率优先用 `python -m pytest --cov=. --cov-report=term-missing`。
34
35
  5. 除非矩阵写明不适用,否则必须有冒烟证据。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pzy560117/opentest",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "OpenTest quality evidence lifecycle skills for Codex",
5
5
  "keywords": [
6
6
  "opentest",
@@ -263,18 +263,24 @@ function assertTestSurfaceContracts() {
263
263
  assert(chineseSurfaces.includes('Midscene YAML runner') && chineseSurfaces.includes('MIDSCENE_MCP_ANDROID_MODE=true') && chineseSurfaces.includes('midscene-python'), '[SURFACE] Chinese Android route must document YAML, MCP, and midscene-python boundaries');
264
264
  assert(englishSurfaces.includes('npm run test:android') && englishSurfaces.includes('midscene_run/log/ai-call.log') && englishSurfaces.includes('midscene_run/report/*.html'), '[SURFACE] English Android route must document layered run and failure artifacts');
265
265
  assert(chineseSurfaces.includes('npm run test:android') && chineseSurfaces.includes('midscene_run/log/ai-call.log') && chineseSurfaces.includes('midscene_run/report/*.html'), '[SURFACE] Chinese Android route must document layered run and failure artifacts');
266
+ assert(englishSurfaces.includes('opentest-android-app') && englishSurfaces.includes('android-app-testing.md'), '[SURFACE] English Android route must expose opentest-android-app adapter');
267
+ assert(chineseSurfaces.includes('opentest-android-app') && chineseSurfaces.includes('android-app-testing.md'), '[SURFACE] Chinese Android route must expose opentest-android-app adapter');
266
268
  assert(englishSurfaces.includes('opentest-desktop-gui') && englishSurfaces.includes('@midscene/computer') && englishSurfaces.includes('deterministic read/assert changed result'), '[SURFACE] English desktop route must document opentest-desktop-gui and deterministic read-back');
267
269
  assert(chineseSurfaces.includes('opentest-desktop-gui') && chineseSurfaces.includes('@midscene/computer') && chineseSurfaces.includes('确定性 read/assert changed result'), '[SURFACE] Chinese desktop route must document opentest-desktop-gui and deterministic read-back');
268
270
  assert(englishSurfaces.includes('opentest-api') && englishSurfaces.includes('httpx') && englishSurfaces.includes('read-after-write'), '[SURFACE] English API route must document opentest-api and read-after-write');
269
271
  assert(chineseSurfaces.includes('opentest-api') && chineseSurfaces.includes('httpx') && chineseSurfaces.includes('写后读'), '[SURFACE] Chinese API route must document opentest-api and read-after-write');
270
272
  assert(englishWorkflow.includes('Execution Surfaces') && englishWorkflow.includes('android-midscene-pytest'), '[SURFACE] English workflow must include execution surface rules');
271
273
  assert(chineseWorkflow.includes('执行面') && chineseWorkflow.includes('android-midscene-pytest'), '[SURFACE] Chinese workflow must include execution surface rules');
274
+ assert(englishWorkflow.includes('opentest-android-app') && englishWorkflow.includes('android-app-testing.md'), '[SURFACE] English workflow must include Android app adapter route');
275
+ assert(chineseWorkflow.includes('opentest-android-app') && chineseWorkflow.includes('android-app-testing.md'), '[SURFACE] Chinese workflow must include Android app adapter route');
272
276
  assert(englishWorkflow.includes('opentest-desktop-gui') && englishWorkflow.includes('@midscene/computer'), '[SURFACE] English workflow must include desktop GUI route');
273
277
  assert(chineseWorkflow.includes('opentest-desktop-gui') && chineseWorkflow.includes('@midscene/computer'), '[SURFACE] Chinese workflow must include desktop GUI route');
274
278
  assert(englishWorkflow.includes('opentest-api') && englishWorkflow.includes('httpx'), '[SURFACE] English workflow must include API route');
275
279
  assert(chineseWorkflow.includes('opentest-api') && chineseWorkflow.includes('httpx'), '[SURFACE] Chinese workflow must include API route');
276
280
  assert(englishHeuristics.includes('Execution Surface Selection') && englishHeuristics.includes('android-midscene-pytest'), '[SURFACE] English heuristics must include surface selection');
277
281
  assert(chineseHeuristics.includes('执行面选择') && chineseHeuristics.includes('android-midscene-pytest'), '[SURFACE] Chinese heuristics must include surface selection');
282
+ assert(englishHeuristics.includes('opentest-android-app'), '[SURFACE] English heuristics must include Android app adapter');
283
+ assert(chineseHeuristics.includes('opentest-android-app'), '[SURFACE] Chinese heuristics must include Android app adapter');
278
284
  assert(englishHeuristics.includes('opentest-desktop-gui') && englishHeuristics.includes('@midscene/computer'), '[SURFACE] English heuristics must include desktop GUI route');
279
285
  assert(chineseHeuristics.includes('opentest-desktop-gui') && chineseHeuristics.includes('@midscene/computer'), '[SURFACE] Chinese heuristics must include desktop GUI route');
280
286
  assert(englishHeuristics.includes('opentest-api') && englishHeuristics.includes('httpx'), '[SURFACE] English heuristics must include API route');
@@ -292,6 +298,8 @@ function assertTestSurfaceContracts() {
292
298
  assert(chineseRun.includes('npm run test:android') && chineseRun.includes('模型环境变量'), '[SURFACE] Chinese run must gate npm run test:android behind model env/debugging');
293
299
  assert(englishAccept.includes('android-midscene-pytest') && englishAccept.includes('ADB smoke') && englishAccept.includes('midscene_run'), '[SURFACE] English accept must route Android through android-midscene-pytest');
294
300
  assert(chineseAccept.includes('android-midscene-pytest') && chineseAccept.includes('ADB 冒烟') && chineseAccept.includes('midscene_run'), '[SURFACE] Chinese accept must route Android through android-midscene-pytest');
301
+ assert(englishAccept.includes('opentest-android-app'), '[SURFACE] English accept must route Android through opentest-android-app');
302
+ assert(chineseAccept.includes('opentest-android-app'), '[SURFACE] Chinese accept must route Android through opentest-android-app');
295
303
  assert(englishAccept.includes('opentest-desktop-gui') && englishAccept.includes('@midscene/computer'), '[SURFACE] English accept must route desktop GUI through opentest-desktop-gui');
296
304
  assert(chineseAccept.includes('opentest-desktop-gui') && chineseAccept.includes('@midscene/computer'), '[SURFACE] Chinese accept must route desktop GUI through opentest-desktop-gui');
297
305
  assert(englishAccept.includes('opentest-api') && englishAccept.includes('httpx') && englishAccept.includes('cleanup/teardown'), '[SURFACE] English accept must route API through opentest-api');
@@ -299,6 +307,8 @@ function assertTestSurfaceContracts() {
299
307
 
300
308
  assert(englishMatrix.includes('Execution surface') && englishMatrix.includes('Evidence layer') && englishMatrix.includes('Midscene HTML report') && englishMatrix.includes('python -m pytest tests_py -v') && englishMatrix.includes('ADB smoke') && englishMatrix.includes('midscene_run'), '[SURFACE] English matrix template must include execution surface and Android artifacts');
301
309
  assert(chineseMatrix.includes('执行面') && chineseMatrix.includes('证据层级') && chineseMatrix.includes('Midscene HTML 报告') && chineseMatrix.includes('python -m pytest tests_py -v') && chineseMatrix.includes('ADB 冒烟') && chineseMatrix.includes('midscene_run'), '[SURFACE] Chinese matrix template must include execution surface and Android artifacts');
310
+ assert(englishMatrix.includes('opentest-android-app'), '[SURFACE] English matrix template must include Android app adapter');
311
+ assert(chineseMatrix.includes('opentest-android-app'), '[SURFACE] Chinese matrix template must include Android app adapter');
302
312
  assert(englishMatrix.includes('opentest-desktop-gui') && englishMatrix.includes('@midscene/computer') && englishMatrix.includes('deterministic read-back'), '[SURFACE] English matrix template must include desktop GUI artifacts');
303
313
  assert(chineseMatrix.includes('opentest-desktop-gui') && chineseMatrix.includes('@midscene/computer') && chineseMatrix.includes('确定性回读'), '[SURFACE] Chinese matrix template must include desktop GUI artifacts');
304
314
  assert(englishMatrix.includes('opentest-api') && englishMatrix.includes('python -m pytest tests/api -v') && englishMatrix.includes('payload/schema assertion') && englishMatrix.includes('cleanup/teardown'), '[SURFACE] English matrix template must include API artifacts');
@@ -309,6 +319,37 @@ function assertTestSurfaceContracts() {
309
319
  assert(chineseAcceptance.includes('执行面: web-browser | android-app | desktop-gui | api') && chineseAcceptance.includes('证据层级'), '[SURFACE] Chinese acceptance template must include surface and evidence layer fields');
310
320
  }
311
321
 
322
+ function assertAndroidAppContracts() {
323
+ const manifestText = readFileSync('assets/manifest.json', 'utf8');
324
+ const englishSkill = readRequiredText('assets/skills/opentest-android-app/SKILL.md', '[ANDROID] missing English Android app skill');
325
+ const chineseSkill = readRequiredText('assets/skills-zh/opentest-android-app/SKILL.md', '[ANDROID] missing Chinese Android app skill');
326
+ const englishReference = readRequiredText('assets/skills/opentest/references/android-app-testing.md', '[ANDROID] missing English Android app reference');
327
+ const chineseReference = readRequiredText('assets/skills-zh/opentest/references/android-app-testing.md', '[ANDROID] missing Chinese Android app reference');
328
+ const englishTemplate = readRequiredText('assets/skills/opentest/templates/android-app-acceptance-template.md', '[ANDROID] missing English Android app template');
329
+ const chineseTemplate = readRequiredText('assets/skills-zh/opentest/templates/android-app-acceptance-template.md', '[ANDROID] missing Chinese Android app template');
330
+ const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
331
+ const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
332
+ const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
333
+ const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
334
+ const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
335
+ const chineseAccept = readFileSync('assets/skills-zh/opentest-accept/SKILL.md', 'utf8');
336
+
337
+ assert(manifestText.includes('opentest-android-app/SKILL.md'), '[ANDROID] manifest must ship opentest-android-app skill');
338
+ assert(manifestText.includes('opentest/references/android-app-testing.md'), '[ANDROID] manifest must ship Android app reference');
339
+ assert(manifestText.includes('opentest/templates/android-app-acceptance-template.md'), '[ANDROID] manifest must ship Android app acceptance template');
340
+
341
+ assert(englishSkill.includes('android-midscene-pytest') && englishSkill.includes('tests/android/tests_py/') && englishSkill.includes('npm run test:android'), '[ANDROID] English Android skill must route layout and Midscene');
342
+ assert(chineseSkill.includes('android-midscene-pytest') && chineseSkill.includes('tests/android/tests_py/') && chineseSkill.includes('npm run test:android'), '[ANDROID] Chinese Android skill must route layout and Midscene');
343
+ assert(englishReference.includes('Adapter Boundary') && englishReference.includes('tests/android/midscene/') && englishReference.includes('Do not mark Android app acceptance as PASS from a static screenshot alone'), '[ANDROID] English reference must define adapter boundary, layout, and no-static-screenshot rule');
344
+ assert(chineseReference.includes('适配边界') && chineseReference.includes('tests/android/midscene/') && chineseReference.includes('不得只凭静态截图'), '[ANDROID] Chinese reference must define adapter boundary, layout, and no-static-screenshot rule');
345
+ assert(englishTemplate.includes('tool route: opentest-android-app | android-midscene-pytest') && englishTemplate.includes('ADB smoke'), '[ANDROID] English template must include route and ADB evidence');
346
+ assert(chineseTemplate.includes('工具路线: opentest-android-app | android-midscene-pytest') && chineseTemplate.includes('ADB 冒烟'), '[ANDROID] Chinese template must include route and ADB evidence');
347
+
348
+ for (const content of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
349
+ assert(content.includes('opentest/references/android-app-testing.md'), '[ANDROID] plan/run/accept skills must read Android app reference');
350
+ }
351
+ }
352
+
312
353
  function assertWebBrowserContracts() {
313
354
  const manifestText = readFileSync('assets/manifest.json', 'utf8');
314
355
  const englishSkill = readRequiredText('assets/skills/opentest-web-browser/SKILL.md', '[WEB] missing English web-browser skill');
@@ -879,6 +920,7 @@ assertPrepublishGateCoversManifestAssets();
879
920
  assertDefaultPytestContracts();
880
921
  assertRequirementFirstAcceptanceContracts();
881
922
  assertTestSurfaceContracts();
923
+ assertAndroidAppContracts();
882
924
  assertWebBrowserContracts();
883
925
  assertDesktopGuiContracts();
884
926
  assertApiContracts();