tuner-testkit 5.2.0__tar.gz → 5.3.0__tar.gz

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.
Files changed (285) hide show
  1. {tuner_testkit-5.2.0/tuner_testkit.egg-info → tuner_testkit-5.3.0}/PKG-INFO +2 -2
  2. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/README.md +1 -1
  3. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/pyproject.toml +1 -1
  4. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/__init__.py +1 -1
  5. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +4 -3
  6. tuner_testkit-5.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/testcases.mdc +29 -0
  7. tuner_testkit-5.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-testcases/SKILL.md +124 -0
  8. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +4 -2
  9. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
  10. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +4 -1
  11. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/metadata-conventions.md +2 -1
  12. tuner_testkit-5.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/testcase-syntax.md +120 -0
  13. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/scaffold.py +1 -0
  14. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/scan.py +11 -1
  15. tuner_testkit-5.3.0/tuner_testkit/testcases/__init__.py +5 -0
  16. tuner_testkit-5.3.0/tuner_testkit/testcases/__main__.py +25 -0
  17. tuner_testkit-5.3.0/tuner_testkit/testcases/tests/test_validate.py +76 -0
  18. tuner_testkit-5.3.0/tuner_testkit/testcases/validate.py +141 -0
  19. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0/tuner_testkit.egg-info}/PKG-INFO +2 -2
  20. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit.egg-info/SOURCES.txt +5 -0
  21. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/LICENSE +0 -0
  22. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/setup.cfg +0 -0
  23. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/__init__.py +0 -0
  24. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/__main__.py +0 -0
  25. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/__init__.py +0 -0
  26. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/api.py +0 -0
  27. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/db.py +0 -0
  28. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/generators.py +0 -0
  29. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/ids.py +0 -0
  30. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/_internal/wait.py +0 -0
  31. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/base.py +0 -0
  32. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/context.py +0 -0
  33. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/action_words/registry.py +0 -0
  34. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/__init__.py +0 -0
  35. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/app.py +0 -0
  36. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/errors.py +0 -0
  37. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/router.py +0 -0
  38. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/spec.py +0 -0
  39. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_mock/store.py +0 -0
  40. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/__init__.py +0 -0
  41. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/auth.py +0 -0
  42. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/__init__.py +0 -0
  43. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/capture.py +0 -0
  44. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/codegen.py +0 -0
  45. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/freeze.py +0 -0
  46. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/mocks.py +0 -0
  47. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/normalize.py +0 -0
  48. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
  49. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
  50. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_test/__init__.py +0 -0
  51. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_test/client.py +0 -0
  52. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_test/errors.py +0 -0
  53. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_test/jsonpath.py +0 -0
  54. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/api_test/model.py +0 -0
  55. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/__init__.py +0 -0
  56. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/_shared/__init__.py +0 -0
  57. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/_shared/changelog.py +0 -0
  58. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
  59. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
  60. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/addon.py +0 -0
  61. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/cli.py +0 -0
  62. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
  63. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
  64. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
  65. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/__init__.py +0 -0
  66. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/__main__.py +0 -0
  67. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/build.py +0 -0
  68. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/cli.py +0 -0
  69. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +0 -0
  70. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-self-learning.md +0 -0
  71. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +0 -0
  72. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
  73. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
  74. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/agent-task-log.mdc +0 -0
  75. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
  76. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
  77. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +0 -0
  78. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -0
  79. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
  80. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +0 -0
  81. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +0 -0
  82. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +0 -0
  83. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
  84. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
  85. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
  86. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
  87. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/work-task.mdc +0 -0
  88. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +0 -0
  89. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +0 -0
  90. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
  91. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +0 -0
  92. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +0 -0
  93. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-test-design/SKILL.md +0 -0
  94. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
  95. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +0 -0
  96. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
  97. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +0 -0
  98. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +0 -0
  99. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/generate-test-report/SKILL.md +0 -0
  100. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +0 -0
  101. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +0 -0
  102. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +0 -0
  103. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
  104. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
  105. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +0 -0
  106. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-test-execution/SKILL.md +0 -0
  107. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
  108. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/agent-task-log.md +0 -0
  109. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +0 -0
  110. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
  111. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/artifacts-layout.md +0 -0
  112. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -0
  113. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
  114. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
  115. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +0 -0
  116. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +0 -0
  117. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
  118. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +0 -0
  119. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/test-design-syntax.md +0 -0
  120. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/work-task.md +0 -0
  121. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
  122. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
  123. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-commit +0 -0
  124. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
  125. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/secret_scan.py +0 -0
  126. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +0 -0
  127. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/paths.py +0 -0
  128. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/source.py +0 -0
  129. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/targets.py +0 -0
  130. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/tests/test_cli.py +0 -0
  131. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dna/tests/test_targets.py +0 -0
  132. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/dump_ddl.py +0 -0
  133. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/__init__.py +0 -0
  134. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/__main__.py +0 -0
  135. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/cli.py +0 -0
  136. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/persist.py +0 -0
  137. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/tests/__init__.py +0 -0
  138. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/tests/test_cli.py +0 -0
  139. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/evidence/tests/test_persist.py +0 -0
  140. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/index_ai/__init__.py +0 -0
  141. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/index_ai/__main__.py +0 -0
  142. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/index_ai/registry.py +0 -0
  143. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/__init__.py +0 -0
  144. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/__main__.py +0 -0
  145. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/manifest.py +0 -0
  146. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/INDEX.project.md +0 -0
  147. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
  148. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
  149. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/config/env.py +0 -0
  150. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/data/sut-accounts.example.yaml +0 -0
  151. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/gitignore +0 -0
  152. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
  153. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
  154. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
  155. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
  156. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
  157. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
  158. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
  159. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
  160. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
  161. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
  162. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
  163. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_environment.py +0 -0
  164. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/given.py +0 -0
  165. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/then.py +0 -0
  166. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/when.py +0 -0
  167. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_environment.py +0 -0
  168. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/given.py +0 -0
  169. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/then.py +0 -0
  170. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/when.py +0 -0
  171. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/tests/pytest/conftest.py +0 -0
  172. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/workbench.cmd +0 -0
  173. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/stubs/workbench.sh +0 -0
  174. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/tests/test_git_hooks.py +0 -0
  175. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +0 -0
  176. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/mock_server/__init__.py +0 -0
  177. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/mock_server/__main__.py +0 -0
  178. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/mock_server/cli.py +0 -0
  179. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/mock_server/seed.py +0 -0
  180. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/mock_server/tool.py +0 -0
  181. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
  182. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
  183. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/capture.py +0 -0
  184. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/cli.py +0 -0
  185. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
  186. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
  187. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/inject.py +0 -0
  188. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/session.py +0 -0
  189. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/tests/__init__.py +0 -0
  190. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
  191. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
  192. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
  193. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/recorder/__init__.py +0 -0
  194. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/recorder/__main__.py +0 -0
  195. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/recorder/cli.py +0 -0
  196. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
  197. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
  198. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/__init__.py +0 -0
  199. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/__main__.py +0 -0
  200. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/cli.py +0 -0
  201. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/store.py +0 -0
  202. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/tests/test_store.py +0 -0
  203. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/apps/task/validate.py +0 -0
  204. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/artifacts.py +0 -0
  205. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/__init__.py +0 -0
  206. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/build.py +0 -0
  207. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/directory.py +0 -0
  208. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/front_matter.py +0 -0
  209. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/tests/test_build.py +0 -0
  210. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/tests/test_directory.py +0 -0
  211. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/catalog/tests/test_front_matter.py +0 -0
  212. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/config.py +0 -0
  213. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/db/__init__.py +0 -0
  214. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/db/client.py +0 -0
  215. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/db/connection.py +0 -0
  216. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/excel/__init__.py +0 -0
  217. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/excel/workbook.py +0 -0
  218. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/__init__.py +0 -0
  219. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/__main__.py +0 -0
  220. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/catalog.py +0 -0
  221. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/china.py +0 -0
  222. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/cli.py +0 -0
  223. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/core.py +0 -0
  224. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/medical.py +0 -0
  225. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/fake/wrappers.py +0 -0
  226. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/__init__.py +0 -0
  227. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/context.py +0 -0
  228. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/core.py +0 -0
  229. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/helpers.py +0 -0
  230. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/hooks.py +0 -0
  231. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/logging/scenario_file.py +0 -0
  232. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/__init__.py +0 -0
  233. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/__main__.py +0 -0
  234. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/base.py +0 -0
  235. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/driver.py +0 -0
  236. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/errors.py +0 -0
  237. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/harvest.py +0 -0
  238. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/health.py +0 -0
  239. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/locator.py +0 -0
  240. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/model.py +0 -0
  241. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/registry.py +0 -0
  242. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/session.py +0 -0
  243. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/steps.py +0 -0
  244. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/page_test/testing.py +0 -0
  245. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/project.py +0 -0
  246. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/tools/__init__.py +0 -0
  247. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/tools/manifest.py +0 -0
  248. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/tools/runner.py +0 -0
  249. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/tools/tests/test_manifest.py +0 -0
  250. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/tools/tests/test_runner.py +0 -0
  251. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/__init__.py +0 -0
  252. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/__main__.py +0 -0
  253. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/app.py +0 -0
  254. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/cli.py +0 -0
  255. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/kinds/__init__.py +0 -0
  256. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/kinds/app_generic.py +0 -0
  257. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/kinds/word_db_seed.py +0 -0
  258. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/kinds/word_generic.py +0 -0
  259. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/static/app.css +0 -0
  260. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/_params_form.html +0 -0
  261. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/ai.html +0 -0
  262. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/ai_detail.html +0 -0
  263. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/base.html +0 -0
  264. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/env.html +0 -0
  265. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/history.html +0 -0
  266. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/home.html +0 -0
  267. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/knowledge.html +0 -0
  268. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/run.html +0 -0
  269. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/tool.html +0 -0
  270. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/tools.html +0 -0
  271. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/word.html +0 -0
  272. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/word_db_seed.html +0 -0
  273. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/templates/words.html +0 -0
  274. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workbench/tests/test_app.py +0 -0
  275. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/__init__.py +0 -0
  276. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/__main__.py +0 -0
  277. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/cli.py +0 -0
  278. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/index_render.py +0 -0
  279. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/meta.py +0 -0
  280. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/tests/test_index_render.py +0 -0
  281. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit/workspace/tests/test_meta.py +0 -0
  282. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit.egg-info/dependency_links.txt +0 -0
  283. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit.egg-info/entry_points.txt +0 -0
  284. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit.egg-info/requires.txt +0 -0
  285. {tuner_testkit-5.2.0 → tuner_testkit-5.3.0}/tuner_testkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tuner-testkit
3
- Version: 5.2.0
3
+ Version: 5.3.0
4
4
  Summary: Shared test runtime, recorders, and DNA overlay for SUT test repos
5
5
  Author: tuner-testkit contributors
6
6
  License-Expression: MIT
@@ -221,4 +221,4 @@ uv sync --extra all
221
221
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
222
222
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
223
223
 
224
- 5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
224
+ 5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
@@ -173,4 +173,4 @@ uv sync --extra all
173
173
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
174
174
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
175
175
 
176
- 5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
176
+ 5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tuner-testkit"
3
- version = "5.2.0"
3
+ version = "5.3.0"
4
4
  description = "Shared test runtime, recorders, and DNA overlay for SUT test repos"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -2,4 +2,4 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "5.2.0"
5
+ __version__ = "5.3.0"
@@ -2,7 +2,7 @@
2
2
  description: assets/ is the knowledge base for humans and the LLM; enforce provenance metadata, raw-vs-curated boundaries, and grounding (consult INDEX before generating)
3
3
  globs: assets/**
4
4
  alwaysApply: false
5
- version: 1.1.0
5
+ version: 1.2.0
6
6
  ---
7
7
 
8
8
  # assets — 知识层硬约束
@@ -25,8 +25,9 @@ SUT 自学习见 `docs/spec/sut-self-learning.md`;design schema 见
25
25
  ## 目录与元数据
26
26
 
27
27
  - 目录分类固定:`ddl/<datasource>/`、`sql/`、`usecases/<domain>/`、
28
- `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testreport/`
29
- (新增类别前先改 spec,再改本 rule)。
28
+ `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testdesign/`、
29
+ `testcases/<模块>/`、`testreport/`
30
+ (新增类别前先改 spec,再改本 rule)。功能用例集见 `docs/spec/testcase-syntax.md`。
30
31
  - 人工/半自动区文件头必须带元数据:`domain / source / date / version / confidence`
31
32
  (Markdown 用 YAML front-matter,SQL 用顶部 `--` 注释)。
32
33
  - `explore/` 与 `design/` 还应填 `evidence`(run_id 列表)。
@@ -0,0 +1,29 @@
1
+ ---
2
+ description: Functional testcases live under assets/testcases/<module>/<feature>.md with four heading levels and stable CASE IDs
3
+ globs: assets/testcases/**
4
+ alwaysApply: false
5
+ version: 1.1.0
6
+ ---
7
+
8
+ # testcases — 功能用例集
9
+
10
+ 完整规范:`docs/spec/testcase-syntax.md`。生成或改写走 skill `maintain-testcases`。
11
+
12
+ ## 位置
13
+
14
+ - 总索引:`assets/testcases/README.md`
15
+ - 模块说明:`assets/testcases/<模块>/README.md`
16
+ - 一个功能一个文件:`assets/testcases/<模块>/<功能>.md`
17
+ - 不要写到 `usecases/`、`testdesign/` 或 `tests/features/`。
18
+
19
+ ## 功能文件
20
+
21
+ - `# 测试用例` → `## <模块>` → `### <功能>` → `#### <缩写><四位序号> 正向-|反向-<测试点>`
22
+ - 二级标题等于目录名,三级标题等于文件名。
23
+ - 每条用例必填 `- 步骤:` 与 `- 预期:`。
24
+ - ID 形如 `User-Login0001`:`id_prefix` 是功能英文缩写,后接 4 位序号。全库唯一;不改号、不复用、不重排。
25
+
26
+ ## 禁止
27
+
28
+ - 密码、token、Cookie、Authorization。账号只写 `account_id`。
29
+ - 没有出处的业务规则。出处是用户本次说明,或索引能指向的知识。
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: maintain-testcases
3
+ version: 1.1.0
4
+ description: Creates and updates the functional testcase set under assets/testcases/<module>/<feature>.md using the four-level heading template and stable feature-prefixed IDs such as User-Login0001. Use when the user asks to 编写/生成/维护测试用例, add a module or feature case file, or mentions assets/testcases or case ID. Do not use for testdesign click-paths or behave .feature files.
5
+ ---
6
+
7
+ # Maintain testcases
8
+
9
+ ## Scope
10
+
11
+ - **Write**: `assets/testcases/**` only.
12
+ - **Must follow**: `docs/spec/testcase-syntax.md`.
13
+ - **Out of scope**: `assets/testdesign/`(用 `derive-test-design`)、`tests/features/**`(用 `feature-authoring`)、pytest。
14
+
15
+ ## Before writing
16
+
17
+ 1. 读 `assets/testcases/README.md` 与目标模块的 `README.md`(没有就先按下面的模板建)。
18
+ 2. 读 `INDEX.md`;存在 `INDEX.project.md` 时一并读。只采用已有 usecase / domain-notes / explore / design,或用户本次给出的事实。
19
+ 3. 功能文件已有 `id_prefix` 就沿用,不要另起缩写。新建功能时用功能名的英文词,每词首字母大写、`-` 连接(`用户登录` → `User-Login`),写入 `id_prefix`。确认这个前缀没有被别的功能占用。
20
+ 4. 序号只在该前缀内递增:`rg -N "^#### User-Login[0-9]{4} " assets/testcases`。下一条 = 最大序号 + 1,4 位补零。该前缀还没有用例时从 `0001` 起,得到 `User-Login0001`。
21
+
22
+ ## Where a case goes
23
+
24
+ - 已有同名 `<模块>/<功能>.md`:只追加或修改四级标题,不新建第二份文件。
25
+ - 模块已存在、功能没有:新建 `assets/testcases/<模块>/<功能>.md`,并在该模块 README 的功能清单加一行。
26
+ - 模块也没有:新建目录和模块 README,再在总索引的模块表加一行,然后写功能文件。
27
+
28
+ ## Templates
29
+
30
+ 功能文件:
31
+
32
+ ```markdown
33
+ ---
34
+ kind: testcase
35
+ id: <ascii-slug>
36
+ id_prefix: <Feature-Name>
37
+ title: <功能>
38
+ module: <模块>
39
+ source: <依据路径或需求名>
40
+ version: 1.0.0
41
+ confidence: medium
42
+ ---
43
+
44
+ # 测试用例
45
+ ## <模块>
46
+ ### <功能>
47
+ #### <Feature-Name>0001 正向-<测试点>
48
+ - 步骤:<操作>
49
+ - 预期:<可观察结果>
50
+ #### <Feature-Name>0002 反向-<测试点>
51
+ - 步骤:<操作>
52
+ - 预期:<可观察结果>
53
+ ```
54
+
55
+ 总索引 `assets/testcases/README.md`:
56
+
57
+ ```markdown
58
+ ---
59
+ kind: testcase-index
60
+ title: 测试用例模块索引
61
+ version: 1.0.0
62
+ confidence: high
63
+ ---
64
+
65
+ # 测试用例模块索引
66
+
67
+ 规范:`docs/spec/testcase-syntax.md`。一个功能一个文件,用例写在四级标题下,ID 全库唯一且不重排。
68
+
69
+ ## 放置规则
70
+
71
+ - 新用例归入已有模块的功能文件;对不上时才新增模块目录。
72
+ - 目录名 = 二级标题;文件名 = 三级标题。
73
+ - 不写密码、token、Cookie。账号只写 `account_id`。
74
+
75
+ ## 模块
76
+
77
+ | 模块 | 目录 | 范围 | 状态 |
78
+ | --- | --- | --- | --- |
79
+ | <模块> | `assets/testcases/<模块>/` | <一句话> | 在用 |
80
+ ```
81
+
82
+ 模块 README:
83
+
84
+ ```markdown
85
+ ---
86
+ kind: testcase-module
87
+ id: <ascii-slug>
88
+ title: <模块>
89
+ module: <模块>
90
+ version: 1.0.0
91
+ confidence: high
92
+ ---
93
+
94
+ # <模块>
95
+
96
+ ## 范围
97
+
98
+ ## 不测
99
+
100
+ ## 功能
101
+
102
+ | 功能 | 文件 |
103
+ | --- | --- |
104
+ | <功能> | [<功能>.md](<功能>.md) |
105
+
106
+ ## 相关知识
107
+
108
+ 无
109
+ ```
110
+
111
+ ## Update rules
112
+
113
+ - 改步骤或预期:保留原 ID 和 `id_prefix`,bump 该文件 `version`。
114
+ - 废弃:标题加 `(废弃)`,补 `- 状态:废弃` 与原因。不删除该四级标题,不把 ID 让给新用例。
115
+ - 拆文件或改功能名:用例带着原 ID 搬家,并改两边 README 的链接。
116
+
117
+ ## Finish
118
+
119
+ ```bash
120
+ python -m tuner_testkit.testcases assets/testcases
121
+ uv run tuner-workspace meta stamp <改过的.md> --kind <testcase|testcase-module|testcase-index>
122
+ ```
123
+
124
+ 校验失败就改文件再跑,通过后再停。有 `INDEX.project.md` 时在其知识表登记新功能文件的路径(只读 front-matter);平台仓没有业务用例时不要往根 `INDEX.md` 填模块明细。
@@ -1,4 +1,4 @@
1
- <!-- version: 1.6.0 -->
1
+ <!-- version: 1.7.0 -->
2
2
  # AGENTS — 平台总入口(轻量 DM)
3
3
 
4
4
  > 本文件是"repo as a platform"的**稳定世界观**:只写不常变的分层结构与角色。
@@ -13,7 +13,7 @@
13
13
 
14
14
  | 层 | 目录 | 职责 | 谁运行 |
15
15
  | --- | --- | --- | --- |
16
- | 知识层 | `assets/` | 给人和 LLM 阅读、生成测试代码的基础知识(ddl / sql / usecases / domain-notes / explore / design / testdesign / testreport)。见 `docs/spec/assets-knowledge-syntax.md`。 | 只读引用 |
16
+ | 知识层 | `assets/` | 给人和 LLM 阅读、生成测试代码的基础知识(ddl / sql / usecases / domain-notes / explore / design / testdesign / testcases / testreport)。见 `docs/spec/assets-knowledge-syntax.md`。 | 只读引用 |
17
17
  | 运行库 | `tuner_testkit/`(PyPI:`tuner-testkit`) | 公共运行时与 CLI(db / logging / api_test / page_test / fake / recorders / dna)。SUT 用 `uv` 锁版本。 | `import tuner_testkit`;`tuner-recorder` 等 scripts |
18
18
  | 组件层 | `packages/` | **本仓业务资产**(api_objects / page_objects / action_words),不是 kit 运行库。 | 被 import |
19
19
  | 工具层 | `apps/` | **本仓私有**工具。公共工具在 `tuner_testkit.apps`。见 `docs/spec/apps-authoring-syntax.md`。 | `python -m apps.<name>`(仅项目工具) |
@@ -51,6 +51,7 @@ flowchart TD
51
51
  Q -->|"新建/更新项目仓"| Init["tuner-init / tuner-dna / release-template"]
52
52
  Q -->|"读/策展/索引知识"| Idx["查 INDEX.md + maintain-index skill"]
53
53
  Q -->|"发布任务 / 测试设计 / 端到端执行"| Task["work/tasks + tuner-task\ndocs/spec/work-task.md"]
54
+ Q -->|"生成或维护功能测试用例"| Cases["maintain-testcases skill\ndocs/spec/testcase-syntax.md"]
54
55
  ```
55
56
 
56
57
  - **学习被测系统** → `.cursor/agents/sut-self-learning.md`(编排 explore → freeze → design;规格 `docs/spec/sut-self-learning.md`;任务 log 见 `docs/spec/agent-task-log.md`)。
@@ -61,6 +62,7 @@ flowchart TD
61
62
  - **仓库初始化/发布** → `tuner-init scaffold`(骨架 + 依赖 `tuner-testkit` + 一次 `tuner-dna sync`)+ `release-template` skill。下游升 kit:`uv add tuner-testkit==x.y.z` 然后 `tuner-dna sync`,再提交。
62
63
  - **读/索引知识** → 先查 `INDEX.md`;若存在 `INDEX.project.md` 则一并查。索引维护用 `maintain-index` skill。
63
64
  - **发布任务** → `tuner-task create` 写入 `work/tasks/`。测试设计走 `derive-test-design`;端到端点击报告走 `run-test-execution`。缺人才能决定的通道(如后端日志)用 `tuner-task ask`,不要猜。
65
+ - **功能测试用例** → skill `maintain-testcases`,落在 `assets/testcases/<模块>/<功能>.md`(规格 `docs/spec/testcase-syntax.md`)。这不是测试设计,也不直接产出 `.feature`。
64
66
 
65
67
  ## 5. 全程硬约束(跨分支)
66
68
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "files": 62,
2
+ "files": 65,
3
3
  "paths": [
4
4
  ".cursor/rules",
5
5
  ".cursor/skills",
@@ -17,13 +17,16 @@ assets/
17
17
  ├── explore/<app>/<name>.md # 探索式测试产出的能力清单 / 站点地图(半自动)
18
18
  ├── design/<app>/<route-slug>.md # API↔DB effects 收敛知识(见 design-knowledge-syntax)
19
19
  ├── testdesign/<sut>/<slug>.md # 测试设计(见 test-design-syntax);执行反馈回写在此
20
+ ├── testcases/README.md # 功能用例集总索引(见 testcase-syntax)
21
+ ├── testcases/<模块>/README.md # 模块范围与功能清单
22
+ ├── testcases/<模块>/<功能>.md # 该功能的全部用例(四级标题 + CASE ID)
20
23
  ├── testreport/<name>.md # 测试报告类原始资产
21
24
  └── CHANGELOG.md # 自动区变更流水(供 maintain-index 读取 delta)
22
25
  ```
23
26
 
24
27
  - **自动区**(工具产出,可被覆盖重写):`ddl/`、以及每次生成会追加 `CHANGELOG.md`。
25
28
  人不手改这些文件的内容语义;要更新就重跑工具。
26
- - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testreport/`。
29
+ - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testcases/`、`testreport/`。
27
30
  - `apidoc/` **不单列**:人工导入的接口说明放 `domain-notes/` 或 `usecases/`;
28
31
  运行时冻结的契约在 `packages/api_objects/`。是否再拆目录留给下游实践决定。
29
32
 
@@ -13,7 +13,7 @@ description: 统一 front-matter / run manifest 字段家族,供 catalog、工
13
13
 
14
14
  | 字段 | 类型 | 含义 |
15
15
  | --- | --- | --- |
16
- | `kind` | string | `app` / `action_word` / `testreport` / `inbox` / `question` / `task` / `testdesign` / `explore` / `design` / `usecase` / `domain-note` |
16
+ | `kind` | string | `app` / `action_word` / `testreport` / `inbox` / `question` / `task` / `testdesign` / `testcase` / `testcase-module` / `testcase-index` / `explore` / `design` / `usecase` / `domain-note` |
17
17
  | `id` | string | 稳定标识(`tool_id` / `word_id` / 报告 slug) |
18
18
  | `title` | string | 短标题 |
19
19
  | `author` | email | 创建者,来自 `git config user.email` |
@@ -56,6 +56,7 @@ catalog 同时用 `git log --diff-filter=A --format=%ae -- <path>` 算首次提
56
56
  - `kind: task` 落在 `work/tasks/TASK-*.md`,字段见 `docs/spec/work-task.md`。
57
57
  - `kind: question` 落在 `artifacts/inbox/questions/Q-*.md`(不入库)。
58
58
  - `kind: testdesign` 落在 `assets/testdesign/<sut>/<slug>.md`,字段见 `docs/spec/test-design-syntax.md`。
59
+ - `kind: testcase` 落在 `assets/testcases/<模块>/<功能>.md`;模块说明是 `testcase-module`,总索引是 `testcase-index`。字段见 `docs/spec/testcase-syntax.md`。
59
60
 
60
61
  ### run manifest
61
62
 
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: testcase-syntax
3
+ version: 1.1.0
4
+ description: assets/testcases 的目录、四级标题、功能缩写用例 ID 与模块 README。功能用例集的唯一事实源。
5
+ ---
6
+
7
+ # 测试用例(testcase-syntax)
8
+
9
+ > 一份功能文件收齐该功能的全部用例。给人读,也给 LLM 按同一棵树增删改。
10
+ > 维护流程见 skill `maintain-testcases`。编辑约束见 `.cursor/rules/testcases.mdc`。
11
+
12
+ ## 1. 和相邻知识的分工
13
+
14
+ | 路径 | 记什么 |
15
+ | --- | --- |
16
+ | `assets/usecases/` | 导入或讲解过的业务场景,不是带稳定 ID 的用例集 |
17
+ | `assets/testdesign/` | 一次任务的范围、策略和点击路径 |
18
+ | `assets/testcases/` | 按模块 / 功能维护的用例集,每条用例一个稳定 `CASE` ID |
19
+ | `tests/features/` | 已自动化的 Gherkin。本规范不写 `.feature` |
20
+
21
+ ## 2. 目录
22
+
23
+ ```text
24
+ assets/testcases/README.md # 模块总索引:规划、模块一览、给人和 LLM 的放置规则
25
+ assets/testcases/<模块>/README.md # 该模块的范围、边界、功能清单
26
+ assets/testcases/<模块>/<功能>.md # 该功能的全部用例
27
+ ```
28
+
29
+ 例子:`assets/testcases/用户系统/用户登录.md`。
30
+
31
+ - 目录名 = 模块显示名 = 功能文件里的二级标题。
32
+ - 文件名(不含 `.md`)= 功能显示名 = 三级标题。
33
+ - 只允许这一层:模块目录里不再套子目录。
34
+ - 名称不要用 `\ / : * ? " < > |`。
35
+
36
+ ## 3. 标题层级
37
+
38
+ 功能文件正文只用这四级。一个功能的全部用例都放在四级标题下。
39
+
40
+ ```markdown
41
+ # 测试用例
42
+ ## 用户系统
43
+ ### 用户登录
44
+ #### User-Login0001 正向-正确账号密码
45
+ - 步骤:输入已注册账号与正确密码点击登录
46
+ - 预期:登录成功进入首页或个人中心
47
+ #### User-Login0002 反向-正确账号错误密码
48
+ - 步骤:输入已注册账号与错误密码点击登录
49
+ - 预期:停留在登录页并提示账号或密码错误
50
+ ```
51
+
52
+ | 级别 | 含义 | 规则 |
53
+ | --- | --- | --- |
54
+ | `#` | 中心主题 | 固定为 `测试用例` |
55
+ | `##` | 模块 | 全文件只有一个,且等于父目录名 |
56
+ | `###` | 功能 | 全文件只有一个,且等于文件名 |
57
+ | `####` | 一条用例 | 功能缩写 ID + 空格 + `正向-` 或 `反向-` + 测试点名称 |
58
+
59
+ ## 4. 用例 ID
60
+
61
+ ID 是全库唯一键,由功能缩写和该功能内的序号组成:`<缩写><四位序号>`。
62
+
63
+ - 缩写:功能名的英文词,每词首字母大写,用 `-` 连接。`用户登录` → `User-Login`。只含字母和连字符,不含数字。
64
+ - 序号:4 位数字,从 `0001` 起。`User-Login0001`、`User-Login0002`。
65
+ - 缩写写在功能文件 front-matter 的 `id_prefix`,之后不得改。同一 `id_prefix` 只能属于一个功能文件。
66
+ - 新增时只扫描这个前缀:`rg -N "^#### User-Login[0-9]{4} " assets/testcases`,取最大序号 + 1。
67
+ - 不同功能的前缀不同,所以 `User-Login0001` 与 `Reset-Password0001` 不会撞键。
68
+ - 已发出的 ID 不改、不复用、不因为删用例而重排。
69
+ - 废弃:标题末尾加 `(废弃)`,并在该条下写 `- 状态:废弃` 与原因。保留标题,不要删掉这一节。
70
+
71
+ ## 5. 每条用例的子弹
72
+
73
+ 必填,且用中文冒号:
74
+
75
+ - `- 步骤:` 测试人员或 LLM 能照做的操作
76
+ - `- 预期:` 可观察结果
77
+
78
+ 可选,仍放在同一条四级标题下:
79
+
80
+ - `- 前置:`
81
+ - `- 数据:` 用账号 `account_id` 或数据文件路径,不写密码、token、Cookie
82
+ - `- 备注:`
83
+
84
+ 没有依据的业务规则不要写进步骤或预期。依据来自用户说明,或 `INDEX.md` / `INDEX.project.md` 能指向的 usecase、domain-notes、explore、design。
85
+
86
+ ## 6. Front-matter
87
+
88
+ 功能文件:
89
+
90
+ ```yaml
91
+ ---
92
+ kind: testcase
93
+ id: user-login
94
+ id_prefix: User-Login
95
+ title: 用户登录
96
+ module: 用户系统
97
+ sut: <sut 短名,未知可省略>
98
+ source: <assets/… 或需求名>
99
+ version: 1.0.0
100
+ confidence: medium
101
+ ---
102
+ ```
103
+
104
+ 模块 README 用 `kind: testcase-module`。总索引用 `kind: testcase-index`。
105
+ 人工修改后 bump `version`。署名用 `tuner-workspace meta stamp <path> --kind testcase`(模块 README 用 `testcase-module`,总索引用 `testcase-index`)。
106
+
107
+ ## 7. 两份 README
108
+
109
+ `assets/testcases/README.md` 告诉人和 LLM:模块怎么划分、新功能该进哪个目录、当前有哪些模块。至少包含:
110
+
111
+ - 放置规则(指向本 spec)
112
+ - 模块表:模块名、目录、一句话范围、状态(`在用` / `规划中`)
113
+
114
+ `assets/testcases/<模块>/README.md` 至少包含:
115
+
116
+ - 这个模块测什么、不测什么
117
+ - 功能清单:每个 `<功能>.md` 一行链接
118
+ - 相关知识路径(没有就写「无」)
119
+
120
+ 新增或重命名功能文件时,两份 README 一起改。总索引的模块表与模块目录一致;模块 README 的功能清单与该目录下的功能文件一致。
@@ -13,6 +13,7 @@ SKELETON_DIRS: tuple[str, ...] = (
13
13
  "assets/explore",
14
14
  "assets/design",
15
15
  "assets/testreport",
16
+ "assets/testcases",
16
17
  "packages/action_words/db_seed",
17
18
  "packages/action_words/db_assert",
18
19
  "packages/action_words/api_request",
@@ -24,7 +24,17 @@ MAX_PARSE_BYTES = 256_000
24
24
  _SKIP_API_OBJECT_FILES = {"__init__.py", "conftest.py", "auth.py", "registry.py"}
25
25
  _SKIP_API_OBJECT_DIRS = {"recording", "tests"}
26
26
  _SKIP_PAGE_OBJECT_FILES = {"__init__.py", "conftest.py", "session.py", "pages.py"}
27
- ASSET_CATEGORIES: tuple[str, ...] = ("ddl", "sql", "usecases", "domain-notes", "explore", "design", "testreport")
27
+ ASSET_CATEGORIES: tuple[str, ...] = (
28
+ "ddl",
29
+ "sql",
30
+ "usecases",
31
+ "domain-notes",
32
+ "explore",
33
+ "design",
34
+ "testdesign",
35
+ "testcases",
36
+ "testreport",
37
+ )
28
38
 
29
39
 
30
40
  # ---------------------------------------------------------------------------
@@ -0,0 +1,5 @@
1
+ """Validate assets/testcases against docs/spec/testcase-syntax.md."""
2
+
3
+ from tuner_testkit.testcases.validate import validate_tree
4
+
5
+ __all__ = ["validate_tree"]
@@ -0,0 +1,25 @@
1
+ """CLI: python -m tuner_testkit.testcases [assets/testcases]."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from tuner_testkit.testcases.validate import validate_tree
9
+
10
+
11
+ def main(argv: list[str] | None = None) -> int:
12
+ args = list(sys.argv[1:] if argv is None else argv)
13
+ target = Path(args[0] if args else "assets/testcases")
14
+ errors = validate_tree(target)
15
+ if errors:
16
+ for item in errors:
17
+ print(item, file=sys.stderr)
18
+ print(f"{len(errors)} error(s)", file=sys.stderr)
19
+ return 1
20
+ print(f"ok {target}")
21
+ return 0
22
+
23
+
24
+ if __name__ == "__main__":
25
+ raise SystemExit(main())
@@ -0,0 +1,76 @@
1
+ from pathlib import Path
2
+
3
+ from tuner_testkit.testcases.validate import validate_tree
4
+
5
+ _INDEX = """---
6
+ kind: testcase-index
7
+ title: 测试用例模块索引
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # 测试用例模块索引
12
+ """
13
+
14
+ _MODULE = """---
15
+ kind: testcase-module
16
+ id: user-system
17
+ title: 用户系统
18
+ module: 用户系统
19
+ version: 1.0.0
20
+ ---
21
+
22
+ # 用户系统
23
+
24
+ ## 功能
25
+
26
+ | 功能 | 文件 |
27
+ | --- | --- |
28
+ | 用户登录 | [用户登录.md](用户登录.md) |
29
+ """
30
+
31
+ _FEATURE = """---
32
+ kind: testcase
33
+ id: user-login
34
+ id_prefix: User-Login
35
+ title: 用户登录
36
+ module: 用户系统
37
+ source: 需求
38
+ version: 1.0.0
39
+ confidence: medium
40
+ ---
41
+
42
+ # 测试用例
43
+ ## 用户系统
44
+ ### 用户登录
45
+ #### User-Login0001 正向-正确账号密码
46
+ - 步骤:输入已注册账号与正确密码点击登录
47
+ - 预期:登录成功进入首页或个人中心
48
+ #### User-Login0002 反向-正确账号错误密码
49
+ - 步骤:输入已注册账号与错误密码点击登录
50
+ - 预期:停留在登录页并提示账号或密码错误
51
+ """
52
+
53
+
54
+ def _tree(root: Path, feature: str = _FEATURE) -> None:
55
+ base = root / "assets" / "testcases"
56
+ module = base / "用户系统"
57
+ module.mkdir(parents=True)
58
+ (base / "README.md").write_text(_INDEX, encoding="utf-8")
59
+ (module / "README.md").write_text(_MODULE, encoding="utf-8")
60
+ (module / "用户登录.md").write_text(feature, encoding="utf-8")
61
+
62
+
63
+ def test_valid_tree(tmp_path: Path) -> None:
64
+ _tree(tmp_path)
65
+ assert validate_tree(tmp_path / "assets" / "testcases") == []
66
+
67
+
68
+ def test_duplicate_id_and_bad_heading(tmp_path: Path) -> None:
69
+ broken = _FEATURE.replace(
70
+ "#### User-Login0002 反向-正确账号错误密码",
71
+ "#### User-Login0001 反向-错误密码\n#### 没有编号",
72
+ )
73
+ _tree(tmp_path, broken)
74
+ errors = validate_tree(tmp_path / "assets" / "testcases")
75
+ assert any("duplicate User-Login0001" in item for item in errors)
76
+ assert any("case heading must be" in item for item in errors)