@pzy560117/opentest 0.1.6 → 0.1.7

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.6",
2
+ "version": "0.1.7",
3
3
  "languages": [
4
4
  {
5
5
  "id": "en",
@@ -68,6 +68,7 @@
68
68
  "opentest/references/quality-gate.md",
69
69
  "opentest/templates/acceptance-template.md",
70
70
  "opentest/templates/archive-layout.md",
71
+ "opentest/templates/fixtures-template.md",
71
72
  "opentest/templates/matrix-template.md",
72
73
  "opentest/templates/plan-template.md",
73
74
  "opentest/templates/report-template.md",
@@ -39,6 +39,8 @@ summary() {
39
39
  if [ -f pom.xml ]; then printf 'maven_project: present\n'; else printf 'maven_project: missing\n'; fi
40
40
  if [ -f Cargo.toml ]; then printf 'cargo_project: present\n'; else printf 'cargo_project: missing\n'; fi
41
41
  if [ -d tests ]; then printf 'tests_dir: present\n'; else printf 'tests_dir: missing\n'; fi
42
+ if [ -d docs/opentest/fixtures ]; then printf 'fixtures_dir: present\n'; else printf 'fixtures_dir: missing\n'; fi
43
+ if [ -f docs/opentest/fixtures/seed.md ] || [ -f docs/opentest/fixtures/seed.json ]; then printf 'seed_data: present\n'; else printf 'seed_data: missing\n'; fi
42
44
  if [ -d docs/opentest ]; then printf 'opentest_docs: present\n'; else printf 'opentest_docs: missing\n'; fi
43
45
  if [ -d docs/opentest/acceptance ]; then printf 'acceptance_docs: present\n'; else printf 'acceptance_docs: missing\n'; fi
44
46
 
@@ -69,7 +69,7 @@ require_state_file() {
69
69
 
70
70
  validate_known_field() {
71
71
  case "$1" in
72
- workflow|phase|plan|matrix|acceptance|run_mode|run_report|test_framework|coverage_report|verification_result|verification_report|archived|created_at|updated_at)
72
+ workflow|phase|plan|matrix|fixtures|acceptance|run_mode|run_report|smoke_report|pre_push_report|test_framework|coverage_report|verification_result|verification_report|archived|created_at|updated_at)
73
73
  return 0
74
74
  ;;
75
75
  *)
@@ -110,9 +110,12 @@ workflow: standard
110
110
  phase: plan
111
111
  plan: null
112
112
  matrix: null
113
+ fixtures: null
113
114
  acceptance: null
114
115
  run_mode: targeted
115
116
  run_report: null
117
+ smoke_report: null
118
+ pre_push_report: null
116
119
  test_framework: pytest
117
120
  coverage_report: null
118
121
  verification_result: pending
@@ -144,7 +147,7 @@ cmd_set() {
144
147
  validate_enum "$value" plan author run accept verify heal archive
145
148
  ;;
146
149
  run_mode)
147
- validate_enum "$value" targeted fast full ci-like
150
+ validate_enum "$value" targeted fast full ci-like pre-push
148
151
  ;;
149
152
  verification_result)
150
153
  validate_enum "$value" pending pass fail risk-accepted
@@ -246,7 +249,7 @@ cmd_check() {
246
249
 
247
250
  validate_enum "$workflow" standard
248
251
  validate_enum "$phase" plan author run accept verify heal archive
249
- validate_enum "$run_mode" targeted fast full ci-like
252
+ validate_enum "$run_mode" targeted fast full ci-like pre-push
250
253
  validate_enum "$verification_result" pending pass fail risk-accepted
251
254
  validate_enum "$archived" true false
252
255
 
@@ -30,3 +30,22 @@
30
30
  - status:
31
31
  - notes:
32
32
  - artifacts:
33
+
34
+ ## Full CRUD Flow
35
+
36
+ Use this default full-chain case when the change touches create, read, update, delete, data writes, files, permissions, or cross-page flows.
37
+
38
+ ```text
39
+ create -> list -> detail -> update -> read back -> delete -> confirm absence -> teardown
40
+ ```
41
+
42
+ - fixture:
43
+ - actor/role:
44
+ - create assertion:
45
+ - list assertion:
46
+ - detail assertion:
47
+ - update assertion:
48
+ - read-back assertion:
49
+ - delete/cancel assertion:
50
+ - post-delete assertion:
51
+ - cleanup assertion:
@@ -0,0 +1,52 @@
1
+ # OpenTest Test Data Fixtures
2
+
3
+ ## Purpose
4
+
5
+ Record the exact test data needed to prove every matrix item. Keep fixtures deterministic, isolated, and safe to rerun.
6
+
7
+ ## users
8
+
9
+ | id | role | permissions | purpose |
10
+ | --- | --- | --- | --- |
11
+ | user-admin | admin | create/read/update/delete | CRUD happy path |
12
+ | user-readonly | viewer | read only | permission denial |
13
+
14
+ ## roles
15
+
16
+ - admin:
17
+ - viewer:
18
+ - unauthorized:
19
+
20
+ ## Entities
21
+
22
+ | id | state | fields | used by ACC IDs |
23
+ | --- | --- | --- | --- |
24
+ | entity-create-valid | valid new record | | ACC-001 |
25
+ | entity-existing | persisted record | | ACC-002, ACC-003, ACC-004 |
26
+ | entity-invalid | invalid/boundary data | | ACC-005 |
27
+
28
+ ## files/images
29
+
30
+ | path | type | purpose | cleanup |
31
+ | --- | --- | --- | --- |
32
+ | docs/opentest/fixtures/files/sample-image.png | image | upload / preview / file validation | remove after test |
33
+
34
+ ## Seed
35
+
36
+ - command:
37
+ - data source:
38
+ - idempotency rule:
39
+
40
+ ## teardown
41
+
42
+ - command:
43
+ - cleanup scope:
44
+ - rollback notes:
45
+
46
+ ## Assertions
47
+
48
+ - UI:
49
+ - API:
50
+ - DB/storage:
51
+ - files:
52
+ - logs:
@@ -2,5 +2,12 @@
2
2
 
3
3
  | ID | Intent | Coverage dimension | Trigger/Input | Expected behavior | Risk | Evidence layer | Framework/command | Required evidence | Gap/blocker | Status |
4
4
  | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
5
- | ACC-001 | Happy path succeeds | main path | | | low | smoke | project command or `python -m pytest` | targeted review | none | pending |
6
- | ACC-002 | Failure or boundary path | failure/boundary | | | medium | acceptance | natural-language acceptance or `python -m pytest` | UI/API acceptance | none | pending |
5
+ | ACC-001 | create succeeds | create | valid fixture entity | entity is created and visible in list/detail | high | integration + acceptance | `python -m pytest` + real workflow | create evidence, UI/API/DB assertion, fixture used | none | pending |
6
+ | ACC-002 | read/list/detail succeeds | read/list/detail | seeded entity | list, search/filter, and detail show correct data | high | integration + acceptance | `python -m pytest` + real workflow | read/list/detail evidence and data consistency check | none | pending |
7
+ | ACC-003 | update succeeds | update | edited fixture entity | updated values persist after read back | high | integration + acceptance | `python -m pytest` + real workflow | update evidence and read-back assertion | none | pending |
8
+ | ACC-004 | delete succeeds safely | delete | existing fixture entity | confirm/cancel behavior works; deleted item disappears after confirmation | high | integration + acceptance | `python -m pytest` + real workflow | delete evidence, cancel evidence, post-delete read check | none | pending |
9
+ | ACC-005 | failure and boundary paths are handled | failure/boundary | invalid, empty, duplicate, unauthorized, or stale fixture data | clear feedback without corrupting data | high | unit/integration/acceptance | `python -m pytest` + acceptance | validation, permission, duplicate, stale-state evidence | none | pending |
10
+ | ACC-006 | data consistency holds | data consistency | create/update/delete flow | UI, API, database/storage, files, and logs agree | high | integration | project command or `python -m pytest` | consistency evidence across surfaces | none | pending |
11
+ | ACC-007 | end-to-end CRUD flow works | end-to-end CRUD | create -> list -> detail -> update -> read back -> delete | full user workflow completes and leaves clean state | high | E2E/acceptance | browser/API workflow | full-chain steps, screenshots/logs, cleanup evidence | none | pending |
12
+ | ACC-008 | smoke gate passes | smoke | app starts and core entry points open | core route/API/CRUD happy path does not crash | high | smoke | project smoke command or targeted workflow | smoke_report path | none | pending |
13
+ | ACC-009 | pre-push gate passes | pre-push | staged change before push | format/lint/type/unit/integration/smoke/diff checks pass or block push | high | pre-push | project command sequence | pre_push_report path | none | pending |
@@ -21,6 +21,24 @@
21
21
  | ID | evidence layer | required evidence | result | gap/risk |
22
22
  | --- | --- | --- | --- | --- |
23
23
 
24
+ ## Test Data
25
+
26
+ - fixtures:
27
+ - seed:
28
+ - teardown:
29
+ - data cleanup result:
30
+
31
+ ## Smoke
32
+
33
+ - smoke_report:
34
+ - result:
35
+
36
+ ## Pre-Push
37
+
38
+ - pre_push_report:
39
+ - command sequence:
40
+ - result:
41
+
24
42
  ## Quality Gate
25
43
 
26
44
  - blocking:
@@ -16,12 +16,14 @@ This phase turns the matrix into executable evidence. Write tests for behavior t
16
16
  1. Read `matrix` from `.opentest.yaml`.
17
17
  2. For unit/component/integration/contract evidence, create or update test files using the project's existing test framework.
18
18
  3. Default to pytest when code-level tests are required and the project has no explicit framework rule or existing framework. Prefer `tests/` and a command that can run with `python -m pytest`.
19
- 4. For E2E, smoke, browser acceptance, real APIs, or cross-page flows, write natural language acceptance cases under `docs/opentest/acceptance/`.
20
- 5. For frontend feedback cases, specify the feedback location and shape, such as field-level errors, form-level errors, toast, modal, inline status, or page error state.
21
- 6. Record reasons and risk for evidence that is not applicable or cannot currently be created.
22
- 7. Write the `.opentest.yaml` `acceptance` field.
23
- 8. If the project uses Loop Handoff, update `docs/loop-handoff/latest.md` with test assets, natural language acceptance cases, gaps/risks, and next step.
24
- 9. Run `bash "$OPENTEST_GUARD" author --apply`.
19
+ 4. Create or update `docs/opentest/fixtures/` from the fixtures template, including users, roles, entities, files/images, seed, teardown, and assertion surfaces.
20
+ 5. For E2E, smoke, browser acceptance, real APIs, or cross-page flows, write natural language acceptance cases under `docs/opentest/acceptance/`.
21
+ 6. For CRUD or data-writing changes, include a full workflow case: create -> list -> detail -> update -> read back -> delete -> confirm absence -> teardown.
22
+ 7. For frontend feedback cases, specify the feedback location and shape, such as field-level errors, form-level errors, toast, modal, inline status, or page error state.
23
+ 8. Record reasons and risk for evidence that is not applicable or cannot currently be created.
24
+ 9. Write the `.opentest.yaml` `fixtures` and `acceptance` fields.
25
+ 10. If the project uses Loop Handoff, update `docs/loop-handoff/latest.md` with fixtures, seed/teardown, test assets, natural language acceptance cases, gaps/risks, and next step.
26
+ 11. Run `bash "$OPENTEST_GUARD" author --apply`.
25
27
 
26
28
  ## Existing Skill Routing
27
29
 
@@ -16,12 +16,14 @@ This phase is the entry point for OpenTest-driven development. Before implementa
16
16
  1. Read project rules, requirements, design, diff, existing test commands, and `opentest/references/codex-harness-coverage-heuristics.md`.
17
17
  2. If the change involves frontend UI, forms, navigation, CRUD, status feedback, or motion, first read the project's `docs/frontend/DESIGN.md` and any available `harness-frontend-design` / `product-ui-defaults` rules.
18
18
  3. Classify the change type, risk level, applicable coverage dimensions, and whether code-level evidence should use an existing project framework or the default `pytest` framework.
19
- 4. Mine implicit scenarios: empty input, invalid input, network failure, missing permissions, duplicate submission, long content, empty data, error mapping, mobile behavior, accessibility, cross-page return paths, and state restoration.
20
- 5. Produce a narrow matrix with at least `ID`, `intent`, `coverage dimension`, `trigger/input`, `expected behavior`, `risk`, `evidence layer`, `framework/command`, `required evidence`, `gap/blocker`, and `status`.
21
- 6. Mark applicable but uncovered evidence as `gap`, and record a concrete blocker or recovery path instead of leaving coverage unknown.
22
- 7. Write the `.opentest.yaml` `plan` and `matrix` fields.
23
- 8. If the project uses Loop Handoff, update `docs/loop-handoff/latest.md` with the plan path, matrix path, current phase, and next step.
24
- 9. Run `bash "$OPENTEST_GUARD" plan --apply`.
19
+ 4. Define the test data plan: users, roles, permissions, entities, files/images, seed command, teardown command, and UI/API/DB/file/log assertions.
20
+ 5. Mine implicit scenarios: empty input, invalid input, network failure, missing permissions, duplicate submission, long content, empty data, error mapping, mobile behavior, accessibility, cross-page return paths, and state restoration.
21
+ 6. Apply the CRUD baseline for create, read/list/detail/search/filter, update/read-back, delete/cancel/post-delete, data consistency, and end-to-end CRUD flow whenever the change touches persisted data, APIs, forms, files, or stateful workflows.
22
+ 7. Produce a narrow matrix with at least `ID`, `intent`, `coverage dimension`, `trigger/input`, `expected behavior`, `risk`, `evidence layer`, `framework/command`, `required evidence`, `gap/blocker`, and `status`.
23
+ 8. Mark applicable but uncovered evidence as `gap`, and record a concrete blocker or recovery path instead of leaving coverage unknown.
24
+ 9. Write the `.opentest.yaml` `plan`, `matrix`, and `fixtures` fields.
25
+ 10. If the project uses Loop Handoff, update `docs/loop-handoff/latest.md` with the plan path, matrix path, fixtures path, current phase, and next step.
26
+ 11. Run `bash "$OPENTEST_GUARD" plan --apply`.
25
27
 
26
28
  ## Constraints
27
29
 
@@ -30,3 +32,5 @@ Do not expand the full Codex Harness checklist into fixed required items. Keep a
30
32
  Do not force all evidence into unit tests. The matrix must state which behavior is proven by unit, component, integration, contract, E2E, smoke, browser acceptance, or security review evidence.
31
33
 
32
34
  Coverage completeness means every applicable product behavior, failure path, boundary, and risk surface has either required evidence or an explicit gap/blocker. It does not mean every task must run every possible test type.
35
+
36
+ CRUD baseline and test data are default requirements for data-writing changes. If any CRUD leg is not applicable, the matrix must state why.
@@ -15,17 +15,20 @@ Run existing project verification commands and write a run report.
15
15
  - `fast`: run fast feedback commands, such as type, lint, and unit.
16
16
  - `full`: run the project's full test command set.
17
17
  - `ci-like`: reproduce CI verification order as closely as practical.
18
+ - `pre-push`: run the push gate sequence before publishing or pushing.
18
19
 
19
20
  Evidence layers are decided by the matrix. Do not run only unit tests just because `npm test` exists. If the matrix requires integration, contract, E2E, smoke, or security checks, run the matching project command or record missing command / blocked.
20
21
 
21
22
  If `.opentest.yaml` has `test_framework: pytest`, or code-level test evidence is required and no project framework is declared, use `python -m pytest` as the default test command. When the matrix requires coverage evidence, prefer `python -m pytest --cov=. --cov-report=term-missing` and write the coverage output path to `.opentest.yaml` `coverage_report`. If pytest or pytest-cov is unavailable, record `missing command` with the install/remediation step instead of passing the gate.
22
23
 
24
+ Smoke evidence is required for ordinary feature changes unless explicitly not applicable in the matrix. A pre-push run should include the project equivalent of format/check, lint, type, unit, integration-targeted, smoke, and `git diff --check`. Missing commands must be recorded as missing or not applicable.
25
+
23
26
  ## Steps
24
27
 
25
28
  1. Read `run_mode` and the matrix from `.opentest.yaml`.
26
29
  2. Prefer explicit project commands, and select targeted, fast, full, or ci-like mode based on matrix evidence layers.
27
30
  3. If no explicit command exists for code-level tests, run or document the default pytest command.
28
- 4. Record command, exit code, summary, coverage output, and log path under `docs/opentest/runs/`.
29
- 5. Write the `.opentest.yaml` `run_report` field, and write `coverage_report` when coverage evidence was required or produced.
31
+ 4. Record command, exit code, summary, coverage output, smoke output, pre-push output, and log path under `docs/opentest/runs/`.
32
+ 5. Write the `.opentest.yaml` `run_report` field, and write `coverage_report`, `smoke_report`, or `pre_push_report` when the matching evidence was required or produced.
30
33
  6. If the project uses Loop Handoff, update `docs/loop-handoff/latest.md` with verification already run, verification not run, failures/blockers, run report path, and next step.
31
34
  7. Run `bash "$OPENTEST_GUARD" run --apply`.
@@ -20,6 +20,9 @@ The verification report must also review the matrix and confirm:
20
20
 
21
21
  - Every required evidence item has a pass, fail, blocked, or risk-accepted conclusion.
22
22
  - Coverage completeness is checked: every applicable coverage dimension in the matrix has required evidence, a run/acceptance result, or an explicit gap/blocker with recovery path.
23
+ - Test data is traceable: fixture, seed, teardown, and cleanup evidence exist for data-writing or CRUD changes.
24
+ - Smoke evidence is required unless the matrix explicitly marks smoke as not applicable.
25
+ - pre-push evidence is required before push/publish unless the user explicitly skips it and the report records the risk.
23
26
  - High-risk behavior does not pass merely because tooling, a test framework, or seed data is missing.
24
27
  - If code-level coverage was required and `test_framework: pytest` is active, the report must include the `python -m pytest` command result and the `coverage_report` path, or fail/block with a reason.
25
28
  - Blocked evidence includes a blocker reason and recovery path.
@@ -30,3 +30,22 @@
30
30
  - status:
31
31
  - 备注:
32
32
  - 产物:
33
+
34
+ ## 完整 CRUD 链路
35
+
36
+ 当变更涉及新增、查询、修改、删除、数据写入、文件、权限或跨页面流程时,默认补这个全链路用例。
37
+
38
+ ```text
39
+ 新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 -> 确认消失 -> 清理
40
+ ```
41
+
42
+ - fixture:
43
+ - 执行角色:
44
+ - 新增断言:
45
+ - 列表断言:
46
+ - 详情断言:
47
+ - 修改断言:
48
+ - 回读断言:
49
+ - 删除/取消断言:
50
+ - 删除后断言:
51
+ - 清理断言:
@@ -0,0 +1,52 @@
1
+ # OpenTest 测试数据 Fixtures
2
+
3
+ ## 目的
4
+
5
+ 记录每个矩阵项需要的测试数据。测试数据必须确定、隔离、可重复执行。
6
+
7
+ ## 用户
8
+
9
+ | id | 角色 | 权限 | 用途 |
10
+ | --- | --- | --- | --- |
11
+ | user-admin | admin | 新增/查询/修改/删除 | CRUD 主路径 |
12
+ | user-readonly | viewer | 只读 | 权限拒绝 |
13
+
14
+ ## 角色
15
+
16
+ - admin:
17
+ - viewer:
18
+ - unauthorized:
19
+
20
+ ## 实体
21
+
22
+ | id | 状态 | 字段 | 对应 ACC |
23
+ | --- | --- | --- | --- |
24
+ | entity-create-valid | 有效新记录 | | ACC-001 |
25
+ | entity-existing | 已存在记录 | | ACC-002, ACC-003, ACC-004 |
26
+ | entity-invalid | 非法/边界数据 | | ACC-005 |
27
+
28
+ ## 文件/图片
29
+
30
+ | 路径 | 类型 | 用途 | 清理 |
31
+ | --- | --- | --- | --- |
32
+ | docs/opentest/fixtures/files/sample-image.png | 图片 | 上传/预览/文件校验 | 测试后删除 |
33
+
34
+ ## Seed
35
+
36
+ - 命令:
37
+ - 数据来源:
38
+ - 幂等规则:
39
+
40
+ ## Teardown
41
+
42
+ - 命令:
43
+ - 清理范围:
44
+ - 回滚说明:
45
+
46
+ ## 断言
47
+
48
+ - UI:
49
+ - API:
50
+ - DB/存储:
51
+ - 文件:
52
+ - 日志:
@@ -2,5 +2,12 @@
2
2
 
3
3
  | ID | 意图 | 覆盖维度 | 触发/输入 | 期望行为 | 风险 | 证据层级 | 框架/命令 | 必需证据 | 缺口/阻塞 | 状态 |
4
4
  | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
5
- | ACC-001 | 主路径成功 | 主路径 | | | low | smoke | 项目命令或 `python -m pytest` | targeted review | 无 | pending |
6
- | ACC-002 | 失败/边界路径 | 失败/边界 | | | medium | acceptance | 自然语言验收或 `python -m pytest` | UI/API 验收 | 无 | pending |
5
+ | ACC-001 | 新增成功 | 新增 | 有效 fixture 实体 | 创建成功,并能在列表/详情中看到 | high | integration + acceptance | `python -m pytest` + 真实工作流 | 新增证据、UI/API/DB 断言、使用的测试数据 | 无 | pending |
6
+ | ACC-002 | 查询/列表/详情成功 | 查询/列表/详情 | 已 seed 的实体 | 列表、搜索/筛选、详情显示正确数据 | high | integration + acceptance | `python -m pytest` + 真实工作流 | 查询/列表/详情证据和数据一致性检查 | 无 | pending |
7
+ | ACC-003 | 修改成功 | 修改 | 编辑 fixture 实体 | 保存后回读仍是新值 | high | integration + acceptance | `python -m pytest` + 真实工作流 | 修改证据和回读断言 | 无 | pending |
8
+ | ACC-004 | 删除安全成功 | 删除 | 已存在 fixture 实体 | 删除确认/取消正确;确认删除后不可见 | high | integration + acceptance | `python -m pytest` + 真实工作流 | 删除证据、取消证据、删除后回读检查 | 无 | pending |
9
+ | ACC-005 | 失败/边界路径可控 | 失败/边界 | 非法、空、重复、无权限或过期 fixture 数据 | 给出清晰反馈且不污染数据 | high | unit/integration/acceptance | `python -m pytest` + 验收 | 校验、权限、重复提交、过期状态证据 | 无 | pending |
10
+ | ACC-006 | 数据一致性成立 | 数据一致性 | 新增/修改/删除闭环 | UI、API、数据库/存储、文件和日志一致 | high | integration | 项目命令或 `python -m pytest` | 跨界面一致性证据 | 无 | pending |
11
+ | ACC-007 | 端到端 CRUD 链路可用 | 端到端 CRUD | 新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 | 完整用户链路通过并留下干净状态 | high | E2E/acceptance | 浏览器/API 工作流 | 全链路步骤、截图/日志、清理证据 | 无 | pending |
12
+ | ACC-008 | 冒烟质量门通过 | 冒烟 | 应用启动且核心入口可访问 | 核心路由/API/CRUD 主路径不崩 | high | smoke | 项目冒烟命令或 targeted workflow | smoke_report 路径 | 无 | pending |
13
+ | ACC-009 | pre-push 质量门通过 | pre-push | push 前 staged change | format/lint/type/unit/integration/smoke/diff 检查通过,否则阻止 push | high | pre-push | 项目命令序列 | pre_push_report 路径 | 无 | pending |
@@ -21,6 +21,24 @@
21
21
  | ID | 证据层级 | 必需证据 | result | 缺口/风险 |
22
22
  | --- | --- | --- | --- | --- |
23
23
 
24
+ ## 测试数据
25
+
26
+ - fixtures:
27
+ - seed:
28
+ - teardown:
29
+ - 数据清理结果:
30
+
31
+ ## 冒烟
32
+
33
+ - smoke_report:
34
+ - result:
35
+
36
+ ## Pre-Push
37
+
38
+ - pre_push_report:
39
+ - 命令序列:
40
+ - result:
41
+
24
42
  ## 质量门
25
43
 
26
44
  - 阻塞项:
@@ -16,12 +16,14 @@ description: "OpenTest 阶段 2:根据矩阵补齐测试资产和自然语言
16
16
  1. 读取 `.opentest.yaml` 中的 `matrix`。
17
17
  2. 对 unit/component/integration/contract 证据,按项目已有测试框架创建或更新测试文件。
18
18
  3. 当矩阵要求代码级测试、且项目没有明确框架规则或既有框架时,默认使用 pytest;优先放在 `tests/`,并确保可用 `python -m pytest` 运行。
19
- 4. E2E、smoke、browser acceptance、真实 API 或跨页面流程,写入 `docs/opentest/acceptance/` 自然语言验收用例。
20
- 5. 对前端反馈类用例,写清反馈位置和形态,例如字段下方错误、表单顶部错误、轻提示、模态框、行内状态或页面错误态。
21
- 6. 对不适用或当前无法补齐的证据,记录原因和风险。
22
- 7. 写入 `.opentest.yaml` 的 `acceptance` 字段。
23
- 8. 更新 `docs/loop-handoff/latest.md`(如果项目使用 Loop Handoff),记录测试资产、自然语言验收用例、gap/risk 和下一步。
24
- 9. 运行 `bash "$OPENTEST_GUARD" author --apply`。
19
+ 4. 根据 fixtures 模板创建或更新 `docs/opentest/fixtures/`,包括用户、角色、实体、文件/图片、seed、teardown 和断言界面。
20
+ 5. 对 E2E、smoke、browser acceptance、真实 API 或跨页面流程,写入 `docs/opentest/acceptance/` 自然语言验收用例。
21
+ 6. 对 CRUD 或数据写入类变更,补完整工作流用例:新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除 -> 确认消失 -> 清理。
22
+ 7. 对前端反馈类用例,写清反馈位置和形态,例如字段下方错误、表单顶部错误、轻提示、模态框、行内状态或页面错误态。
23
+ 8. 对不适用或当前无法补齐的证据,记录原因和风险。
24
+ 9. 写入 `.opentest.yaml` `fixtures` 和 `acceptance` 字段。
25
+ 10. 更新 `docs/loop-handoff/latest.md`(如果项目使用 Loop Handoff),记录 fixtures、seed/teardown、测试资产、自然语言验收用例、gap/risk 和下一步。
26
+ 11. 运行 `bash "$OPENTEST_GUARD" author --apply`。
25
27
 
26
28
  ## 现有技能路由
27
29
 
@@ -16,12 +16,14 @@ description: "OpenTest 阶段 1:分析变更、风险和项目事实,生成
16
16
  1. 读取项目规则、需求、设计、diff、现有测试命令和 `opentest/references/codex-harness-coverage-heuristics.md`。
17
17
  2. 如果存在前端、表单、导航、CRUD、状态反馈或动效,优先读取项目内 `docs/frontend/DESIGN.md` 和可用的 `harness-frontend-design` / `product-ui-defaults` 规则。
18
18
  3. 判断变更类型、风险等级、适用覆盖维度,以及代码级证据应使用项目已有框架还是默认 `pytest` 框架。
19
- 4. 做隐性场景挖掘:空输入、非法输入、网络失败、权限不足、重复提交、长内容、空数据、错误映射、移动端、可访问性、跨页面返回和状态恢复。
20
- 5. 生成窄矩阵,至少包含 `ID`、`意图`、`覆盖维度`、`触发/输入`、`期望行为`、`风险`、`证据层级`、`框架/命令`、`必需证据`、`缺口/阻塞`、`状态`。
21
- 6. 对适用但未覆盖的证据面标记 `gap`,并写清具体阻塞或恢复路径,不把覆盖状态留成 unknown
22
- 7. 写入 `.opentest.yaml` 的 `plan` 和 `matrix` 字段。
23
- 8. 更新 `docs/loop-handoff/latest.md`(如果项目使用 Loop Handoff),记录 plan、matrix 路径、当前阶段和下一步。
24
- 9. 运行 `bash "$OPENTEST_GUARD" plan --apply`。
19
+ 4. 定义测试数据计划:用户、角色、权限、实体、文件/图片、seed 命令、teardown 命令,以及 UI/API/DB/文件/日志断言。
20
+ 5. 做隐性场景挖掘:空输入、非法输入、网络失败、权限不足、重复提交、长内容、空数据、错误映射、移动端、可访问性、跨页面返回和状态恢复。
21
+ 6. 对涉及持久化数据、API、表单、文件或有状态工作流的变更,默认套用 CRUD 基线:新增、查询/列表/详情/搜索/筛选、修改/回读、删除/取消/删除后检查、数据一致性、端到端 CRUD
22
+ 7. 生成窄矩阵,至少包含 `ID`、`意图`、`覆盖维度`、`触发/输入`、`期望行为`、`风险`、`证据层级`、`框架/命令`、`必需证据`、`缺口/阻塞`、`状态`。
23
+ 8. 对适用但未覆盖的证据面标记 `gap`,并写清具体阻塞或恢复路径,不把覆盖状态留成 unknown。
24
+ 9. 写入 `.opentest.yaml` `plan`、`matrix` 和 `fixtures` 字段。
25
+ 10. 更新 `docs/loop-handoff/latest.md`(如果项目使用 Loop Handoff),记录 plan、matrix、fixtures 路径、当前阶段和下一步。
26
+ 11. 运行 `bash "$OPENTEST_GUARD" plan --apply`。
25
27
 
26
28
  ## 约束
27
29
 
@@ -30,3 +32,5 @@ description: "OpenTest 阶段 1:分析变更、风险和项目事实,生成
30
32
  不要把所有证据都写成 unit test。矩阵要明确哪些用 unit/component/integration/contract/E2E/smoke/browser acceptance/security review 证明。
31
33
 
32
34
  覆盖完整性指每个适用的产品行为、失败路径、边界和风险面都有必需证据,或有明确的 gap/blocker;不是要求每次任务都跑所有测试类型。
35
+
36
+ CRUD 基线和测试数据是数据写入类变更的默认要求。若某个 CRUD 环节不适用,必须在矩阵中写明原因。
@@ -15,17 +15,20 @@ description: "OpenTest 阶段 3:按 targeted、fast、full 或 ci-like 模式
15
15
  - `fast`:运行快速反馈命令,例如 type、lint、unit。
16
16
  - `full`:运行项目完整测试命令。
17
17
  - `ci-like`:尽量复现 CI 验证顺序。
18
+ - `pre-push`:push 或发布前运行推送质量门序列。
18
19
 
19
20
  证据层级由矩阵决定。不要因为存在 `npm test` 就只跑 unit test;如果矩阵要求 integration、contract、E2E、smoke 或安全检查,必须运行对应项目命令,或记录 missing command / blocked。
20
21
 
21
22
  如果 `.opentest.yaml` 中 `test_framework: pytest`,或矩阵要求代码级测试但项目没有声明测试框架,默认测试命令使用 `python -m pytest`。当矩阵要求覆盖率证据时,优先使用 `python -m pytest --cov=. --cov-report=term-missing`,并把覆盖率输出路径写入 `.opentest.yaml` 的 `coverage_report`。如果缺少 pytest 或 pytest-cov,记录 `missing command` 和安装/恢复步骤,不允许直接通过质量门。
22
23
 
24
+ 普通功能变更默认必须有冒烟证据,除非矩阵明确写明不适用。pre-push 运行应包含项目等价的 format/check、lint、type、unit、targeted integration、smoke 和 `git diff --check`;缺少命令时必须记录 missing 或 not applicable。
25
+
23
26
  ## 步骤
24
27
 
25
28
  1. 读取 `.opentest.yaml` 的 `run_mode` 和矩阵。
26
29
  2. 优先使用项目显式命令,按矩阵中的证据层级选择 targeted、fast、full 或 ci-like。
27
30
  3. 如果代码级测试没有显式命令,运行或记录默认 pytest 命令。
28
- 4. 记录命令、退出码、摘要、覆盖率输出和日志路径到 `docs/opentest/runs/`。
29
- 5. 写入 `.opentest.yaml` 的 `run_report` 字段;当要求或产生覆盖率证据时,也写入 `coverage_report`。
31
+ 4. 记录命令、退出码、摘要、覆盖率输出、冒烟输出、pre-push 输出和日志路径到 `docs/opentest/runs/`。
32
+ 5. 写入 `.opentest.yaml` 的 `run_report` 字段;当要求或产生对应证据时,也写入 `coverage_report`、`smoke_report` 或 `pre_push_report`。
30
33
  6. 更新 `docs/loop-handoff/latest.md`(如果项目使用 Loop Handoff),记录已运行验证、未运行验证、失败/阻塞、run report 路径和下一步。
31
34
  7. 运行 `bash "$OPENTEST_GUARD" run --apply`。
@@ -20,6 +20,9 @@ description: "OpenTest 阶段 5:应用质量门并生成验证报告。"
20
20
 
21
21
  - 每个 required evidence 都有 pass、fail、blocked 或 risk-accepted 结论。
22
22
  - 覆盖完整性已检查:矩阵中的每个适用覆盖维度都有必需证据、运行/验收结果,或带恢复路径的明确 gap/blocker。
23
+ - 测试数据可追踪:数据写入或 CRUD 变更必须有 fixture、seed、teardown 和清理证据。
24
+ - 必须有冒烟证据,除非矩阵明确标记 smoke 不适用。
25
+ - push/publish 前必须有 pre-push 证据;除非用户明确跳过,并在报告里记录风险。
23
26
  - 高风险行为不能因为没有工具、没有测试框架或没有 seed data 就直接通过。
24
27
  - 如果要求代码级覆盖率且 `test_framework: pytest` 生效,报告必须包含 `python -m pytest` 命令结果和 `coverage_report` 路径;否则必须 fail/block 并写明原因。
25
28
  - blocked evidence 必须包含阻塞原因和后续恢复路径。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pzy560117/opentest",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "OpenTest quality evidence lifecycle skills for Codex",
5
5
  "keywords": [
6
6
  "opentest",
@@ -32,6 +32,15 @@ function assert(condition, message) {
32
32
  }
33
33
  }
34
34
 
35
+ function readRequiredText(filePath, message) {
36
+ try {
37
+ return readFileSync(filePath, 'utf8');
38
+ } catch {
39
+ assert(false, message);
40
+ return '';
41
+ }
42
+ }
43
+
35
44
  function pathSegments(file) {
36
45
  return file.split(/[\\/]+/).filter(Boolean);
37
46
  }
@@ -183,6 +192,56 @@ function assertDefaultPytestContracts() {
183
192
  assert(chineseMatrix.includes('覆盖维度') && chineseMatrix.includes('框架/命令') && chineseMatrix.includes('缺口/阻塞'), '[COVERAGE] Chinese matrix template must include coverage, command, and gap columns');
184
193
  }
185
194
 
195
+ function assertCompleteTestingWorkflowContracts() {
196
+ const stateScript = readFileSync('assets/skills/opentest/scripts/opentest-state.sh', 'utf8');
197
+ const detectScript = readFileSync('assets/skills/opentest/scripts/opentest-detect.sh', 'utf8');
198
+ const manifestText = readFileSync('assets/manifest.json', 'utf8');
199
+ const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
200
+ const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
201
+ const englishAuthor = readFileSync('assets/skills/opentest-author/SKILL.md', 'utf8');
202
+ const chineseAuthor = readFileSync('assets/skills-zh/opentest-author/SKILL.md', 'utf8');
203
+ const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
204
+ const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
205
+ const englishVerify = readFileSync('assets/skills/opentest-verify/SKILL.md', 'utf8');
206
+ const chineseVerify = readFileSync('assets/skills-zh/opentest-verify/SKILL.md', 'utf8');
207
+ const englishMatrix = readFileSync('assets/skills/opentest/templates/matrix-template.md', 'utf8');
208
+ const chineseMatrix = readFileSync('assets/skills-zh/opentest/templates/matrix-template.md', 'utf8');
209
+ const englishFixture = readRequiredText('assets/skills/opentest/templates/fixtures-template.md', '[FIXTURES] missing English fixture template');
210
+ const chineseFixture = readRequiredText('assets/skills-zh/opentest/templates/fixtures-template.md', '[FIXTURES] missing Chinese fixture template');
211
+ const englishAcceptance = readFileSync('assets/skills/opentest/templates/acceptance-template.md', 'utf8');
212
+ const chineseAcceptance = readFileSync('assets/skills-zh/opentest/templates/acceptance-template.md', 'utf8');
213
+
214
+ assert(manifestText.includes('opentest/templates/fixtures-template.md'), '[FIXTURES] manifest must ship fixture templates');
215
+ assert(stateScript.includes('fixtures: null'), '[FIXTURES] state init must track fixtures');
216
+ assert(stateScript.includes('smoke_report: null'), '[SMOKE] state init must track smoke_report');
217
+ assert(stateScript.includes('pre_push_report: null'), '[PREPUSH] state init must track pre_push_report');
218
+ assert(stateScript.includes('fixtures|'), '[FIXTURES] state script must allow fixtures field updates');
219
+ assert(stateScript.includes('targeted fast full ci-like pre-push'), '[PREPUSH] state script must allow pre-push run mode');
220
+ assert(detectScript.includes('fixtures_dir:'), '[FIXTURES] detect summary must report fixtures_dir');
221
+ assert(detectScript.includes('seed_data:'), '[FIXTURES] detect summary must report seed_data');
222
+
223
+ for (const keyword of ['create', 'read/list/detail', 'update', 'delete', 'data consistency', 'smoke', 'pre-push', 'end-to-end CRUD']) {
224
+ assert(englishMatrix.includes(keyword), `[MATRIX] English matrix missing ${keyword}`);
225
+ }
226
+ for (const keyword of ['新增', '查询/列表/详情', '修改', '删除', '数据一致性', '冒烟', 'pre-push', '端到端 CRUD']) {
227
+ assert(chineseMatrix.includes(keyword), `[MATRIX] Chinese matrix missing ${keyword}`);
228
+ }
229
+
230
+ assert(englishFixture.includes('users') && englishFixture.includes('roles') && englishFixture.includes('files/images') && englishFixture.includes('teardown'), '[FIXTURES] English fixture template must cover users, roles, files/images, and teardown');
231
+ assert(chineseFixture.includes('用户') && chineseFixture.includes('角色') && chineseFixture.includes('文件/图片') && chineseFixture.includes('清理'), '[FIXTURES] Chinese fixture template must cover users, roles, files/images, and teardown');
232
+ assert(englishAcceptance.includes('create -> list -> detail -> update -> read back -> delete'), '[ACCEPTANCE] English acceptance template must include full CRUD flow');
233
+ assert(chineseAcceptance.includes('新增 -> 列表 -> 详情 -> 修改 -> 回读 -> 删除'), '[ACCEPTANCE] Chinese acceptance template must include full CRUD flow');
234
+
235
+ assert(englishPlan.includes('CRUD baseline') && englishPlan.includes('test data'), '[PLAN] English plan skill must require CRUD baseline and test data planning');
236
+ assert(chinesePlan.includes('CRUD 基线') && chinesePlan.includes('测试数据'), '[PLAN] Chinese plan skill must require CRUD baseline and test data planning');
237
+ assert(englishAuthor.includes('fixtures') && englishAuthor.includes('seed') && englishAuthor.includes('teardown'), '[AUTHOR] English author skill must require fixtures, seed, and teardown assets');
238
+ assert(chineseAuthor.includes('fixtures') && chineseAuthor.includes('seed') && chineseAuthor.includes('teardown'), '[AUTHOR] Chinese author skill must require fixtures, seed, and teardown assets');
239
+ assert(englishRun.includes('pre-push') && englishRun.includes('smoke_report') && englishRun.includes('pre_push_report'), '[RUN] English run skill must cover pre-push, smoke_report, and pre_push_report');
240
+ assert(chineseRun.includes('pre-push') && chineseRun.includes('smoke_report') && chineseRun.includes('pre_push_report'), '[RUN] Chinese run skill must cover pre-push, smoke_report, and pre_push_report');
241
+ assert(englishVerify.includes('Smoke evidence is required') && englishVerify.includes('pre-push evidence is required') && englishVerify.includes('fixture'), '[VERIFY] English verify skill must gate smoke, pre-push, and fixtures');
242
+ assert(chineseVerify.includes('必须有冒烟证据') && chineseVerify.includes('必须有 pre-push 证据') && chineseVerify.includes('测试数据'), '[VERIFY] Chinese verify skill must gate smoke, pre-push, and test data');
243
+ }
244
+
186
245
  async function assertPrepublishRejectsPublishSecretTextFiles() {
187
246
  const fixtureDir = path.join('assets', 'opentest-smoke-secret-fixtures');
188
247
  const fixtures = [
@@ -487,6 +546,7 @@ runManifestPathRelativitySelfCheck();
487
546
  assertManifestStructure();
488
547
  assertPrepublishGateCoversManifestAssets();
489
548
  assertDefaultPytestContracts();
549
+ assertCompleteTestingWorkflowContracts();
490
550
  assertOpenTestSearchRootsCoverPlatforms();
491
551
  assertLanguageAssetContracts();
492
552
  await assertPrepublishRejectsPublishSecretTextFiles();