atdd 0.1.0__py3-none-any.whl
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.
- atdd/__init__.py +0 -0
- atdd/cli.py +404 -0
- atdd/coach/__init__.py +0 -0
- atdd/coach/commands/__init__.py +0 -0
- atdd/coach/commands/add_persistence_metadata.py +215 -0
- atdd/coach/commands/analyze_migrations.py +188 -0
- atdd/coach/commands/consumers.py +720 -0
- atdd/coach/commands/infer_governance_status.py +149 -0
- atdd/coach/commands/initializer.py +177 -0
- atdd/coach/commands/interface.py +1078 -0
- atdd/coach/commands/inventory.py +565 -0
- atdd/coach/commands/migration.py +240 -0
- atdd/coach/commands/registry.py +1560 -0
- atdd/coach/commands/session.py +430 -0
- atdd/coach/commands/sync.py +405 -0
- atdd/coach/commands/test_interface.py +399 -0
- atdd/coach/commands/test_runner.py +141 -0
- atdd/coach/commands/tests/__init__.py +1 -0
- atdd/coach/commands/tests/test_telemetry_array_validation.py +235 -0
- atdd/coach/commands/traceability.py +4264 -0
- atdd/coach/conventions/session.convention.yaml +754 -0
- atdd/coach/overlays/__init__.py +2 -0
- atdd/coach/overlays/claude.md +2 -0
- atdd/coach/schemas/config.schema.json +34 -0
- atdd/coach/schemas/manifest.schema.json +101 -0
- atdd/coach/templates/ATDD.md +282 -0
- atdd/coach/templates/SESSION-TEMPLATE.md +327 -0
- atdd/coach/utils/__init__.py +0 -0
- atdd/coach/utils/graph/__init__.py +0 -0
- atdd/coach/utils/graph/urn.py +875 -0
- atdd/coach/validators/__init__.py +0 -0
- atdd/coach/validators/shared_fixtures.py +365 -0
- atdd/coach/validators/test_enrich_wagon_registry.py +167 -0
- atdd/coach/validators/test_registry.py +575 -0
- atdd/coach/validators/test_session_validation.py +1183 -0
- atdd/coach/validators/test_traceability.py +448 -0
- atdd/coach/validators/test_update_feature_paths.py +108 -0
- atdd/coach/validators/test_validate_contract_consumers.py +297 -0
- atdd/coder/__init__.py +1 -0
- atdd/coder/conventions/adapter.recipe.yaml +88 -0
- atdd/coder/conventions/backend.convention.yaml +460 -0
- atdd/coder/conventions/boundaries.convention.yaml +666 -0
- atdd/coder/conventions/commons.convention.yaml +460 -0
- atdd/coder/conventions/complexity.recipe.yaml +109 -0
- atdd/coder/conventions/component-naming.convention.yaml +178 -0
- atdd/coder/conventions/design.convention.yaml +327 -0
- atdd/coder/conventions/design.recipe.yaml +273 -0
- atdd/coder/conventions/dto.convention.yaml +660 -0
- atdd/coder/conventions/frontend.convention.yaml +542 -0
- atdd/coder/conventions/green.convention.yaml +1012 -0
- atdd/coder/conventions/presentation.convention.yaml +587 -0
- atdd/coder/conventions/refactor.convention.yaml +535 -0
- atdd/coder/conventions/technology.convention.yaml +206 -0
- atdd/coder/conventions/tests/__init__.py +0 -0
- atdd/coder/conventions/tests/test_adapter_recipe.py +302 -0
- atdd/coder/conventions/tests/test_complexity_recipe.py +289 -0
- atdd/coder/conventions/tests/test_component_taxonomy.py +278 -0
- atdd/coder/conventions/tests/test_component_urn_naming.py +165 -0
- atdd/coder/conventions/tests/test_thinness_recipe.py +286 -0
- atdd/coder/conventions/thinness.recipe.yaml +82 -0
- atdd/coder/conventions/train.convention.yaml +325 -0
- atdd/coder/conventions/verification.protocol.yaml +53 -0
- atdd/coder/schemas/design_system.schema.json +361 -0
- atdd/coder/validators/__init__.py +0 -0
- atdd/coder/validators/test_commons_structure.py +485 -0
- atdd/coder/validators/test_complexity.py +416 -0
- atdd/coder/validators/test_cross_language_consistency.py +431 -0
- atdd/coder/validators/test_design_system_compliance.py +413 -0
- atdd/coder/validators/test_dto_testing_patterns.py +268 -0
- atdd/coder/validators/test_green_cross_stack_layers.py +168 -0
- atdd/coder/validators/test_green_layer_dependencies.py +148 -0
- atdd/coder/validators/test_green_python_layer_structure.py +103 -0
- atdd/coder/validators/test_green_supabase_layer_structure.py +103 -0
- atdd/coder/validators/test_import_boundaries.py +396 -0
- atdd/coder/validators/test_init_file_urns.py +593 -0
- atdd/coder/validators/test_preact_layer_boundaries.py +221 -0
- atdd/coder/validators/test_presentation_convention.py +260 -0
- atdd/coder/validators/test_python_architecture.py +674 -0
- atdd/coder/validators/test_quality_metrics.py +420 -0
- atdd/coder/validators/test_station_master_pattern.py +244 -0
- atdd/coder/validators/test_train_infrastructure.py +454 -0
- atdd/coder/validators/test_train_urns.py +293 -0
- atdd/coder/validators/test_typescript_architecture.py +616 -0
- atdd/coder/validators/test_usecase_structure.py +421 -0
- atdd/coder/validators/test_wagon_boundaries.py +586 -0
- atdd/conftest.py +126 -0
- atdd/planner/__init__.py +1 -0
- atdd/planner/conventions/acceptance.convention.yaml +538 -0
- atdd/planner/conventions/appendix.convention.yaml +187 -0
- atdd/planner/conventions/artifact-naming.convention.yaml +852 -0
- atdd/planner/conventions/component.convention.yaml +670 -0
- atdd/planner/conventions/criteria.convention.yaml +141 -0
- atdd/planner/conventions/feature.convention.yaml +371 -0
- atdd/planner/conventions/interface.convention.yaml +382 -0
- atdd/planner/conventions/steps.convention.yaml +141 -0
- atdd/planner/conventions/train.convention.yaml +552 -0
- atdd/planner/conventions/wagon.convention.yaml +275 -0
- atdd/planner/conventions/wmbt.convention.yaml +258 -0
- atdd/planner/schemas/acceptance.schema.json +336 -0
- atdd/planner/schemas/appendix.schema.json +78 -0
- atdd/planner/schemas/component.schema.json +114 -0
- atdd/planner/schemas/feature.schema.json +197 -0
- atdd/planner/schemas/train.schema.json +192 -0
- atdd/planner/schemas/wagon.schema.json +281 -0
- atdd/planner/schemas/wmbt.schema.json +59 -0
- atdd/planner/validators/__init__.py +0 -0
- atdd/planner/validators/conftest.py +5 -0
- atdd/planner/validators/test_draft_wagon_registry.py +374 -0
- atdd/planner/validators/test_plan_cross_refs.py +240 -0
- atdd/planner/validators/test_plan_uniqueness.py +224 -0
- atdd/planner/validators/test_plan_urn_resolution.py +268 -0
- atdd/planner/validators/test_plan_wagons.py +174 -0
- atdd/planner/validators/test_train_validation.py +514 -0
- atdd/planner/validators/test_wagon_urn_chain.py +648 -0
- atdd/planner/validators/test_wmbt_consistency.py +327 -0
- atdd/planner/validators/test_wmbt_vocabulary.py +632 -0
- atdd/tester/__init__.py +1 -0
- atdd/tester/conventions/artifact.convention.yaml +257 -0
- atdd/tester/conventions/contract.convention.yaml +1009 -0
- atdd/tester/conventions/filename.convention.yaml +555 -0
- atdd/tester/conventions/migration.convention.yaml +509 -0
- atdd/tester/conventions/red.convention.yaml +797 -0
- atdd/tester/conventions/routing.convention.yaml +51 -0
- atdd/tester/conventions/telemetry.convention.yaml +458 -0
- atdd/tester/schemas/a11y.tmpl.json +17 -0
- atdd/tester/schemas/artifact.schema.json +189 -0
- atdd/tester/schemas/contract.schema.json +591 -0
- atdd/tester/schemas/contract.tmpl.json +95 -0
- atdd/tester/schemas/db.tmpl.json +20 -0
- atdd/tester/schemas/e2e.tmpl.json +17 -0
- atdd/tester/schemas/edge_function.tmpl.json +17 -0
- atdd/tester/schemas/event.tmpl.json +17 -0
- atdd/tester/schemas/http.tmpl.json +19 -0
- atdd/tester/schemas/job.tmpl.json +18 -0
- atdd/tester/schemas/load.tmpl.json +21 -0
- atdd/tester/schemas/metric.tmpl.json +19 -0
- atdd/tester/schemas/pack.schema.json +139 -0
- atdd/tester/schemas/realtime.tmpl.json +20 -0
- atdd/tester/schemas/rls.tmpl.json +18 -0
- atdd/tester/schemas/script.tmpl.json +16 -0
- atdd/tester/schemas/sec.tmpl.json +18 -0
- atdd/tester/schemas/storage.tmpl.json +18 -0
- atdd/tester/schemas/telemetry.schema.json +128 -0
- atdd/tester/schemas/telemetry_tracking_manifest.schema.json +143 -0
- atdd/tester/schemas/test_filename.schema.json +194 -0
- atdd/tester/schemas/test_intent.schema.json +179 -0
- atdd/tester/schemas/unit.tmpl.json +18 -0
- atdd/tester/schemas/visual.tmpl.json +18 -0
- atdd/tester/schemas/ws.tmpl.json +17 -0
- atdd/tester/utils/__init__.py +0 -0
- atdd/tester/utils/filename.py +300 -0
- atdd/tester/validators/__init__.py +0 -0
- atdd/tester/validators/cleanup_duplicate_headers.py +116 -0
- atdd/tester/validators/cleanup_duplicate_headers_v2.py +135 -0
- atdd/tester/validators/conftest.py +5 -0
- atdd/tester/validators/coverage_gap_report.py +321 -0
- atdd/tester/validators/fix_dual_ac_references.py +179 -0
- atdd/tester/validators/remove_duplicate_lines.py +93 -0
- atdd/tester/validators/test_acceptance_urn_filename_mapping.py +359 -0
- atdd/tester/validators/test_acceptance_urn_separator.py +166 -0
- atdd/tester/validators/test_artifact_naming_category.py +307 -0
- atdd/tester/validators/test_contract_schema_compliance.py +706 -0
- atdd/tester/validators/test_contracts_structure.py +200 -0
- atdd/tester/validators/test_coverage_adequacy.py +797 -0
- atdd/tester/validators/test_dual_ac_reference.py +225 -0
- atdd/tester/validators/test_fixture_validity.py +372 -0
- atdd/tester/validators/test_isolation.py +487 -0
- atdd/tester/validators/test_migration_coverage.py +204 -0
- atdd/tester/validators/test_migration_criteria.py +276 -0
- atdd/tester/validators/test_migration_generation.py +116 -0
- atdd/tester/validators/test_python_test_naming.py +410 -0
- atdd/tester/validators/test_red_layer_validation.py +95 -0
- atdd/tester/validators/test_red_python_layer_structure.py +87 -0
- atdd/tester/validators/test_red_supabase_layer_structure.py +90 -0
- atdd/tester/validators/test_telemetry_structure.py +634 -0
- atdd/tester/validators/test_typescript_test_naming.py +301 -0
- atdd/tester/validators/test_typescript_test_structure.py +84 -0
- atdd-0.1.0.dist-info/METADATA +191 -0
- atdd-0.1.0.dist-info/RECORD +183 -0
- atdd-0.1.0.dist-info/WHEEL +5 -0
- atdd-0.1.0.dist-info/entry_points.txt +2 -0
- atdd-0.1.0.dist-info/licenses/LICENSE +674 -0
- atdd-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Platform tests: TypeScript test file naming validation.
|
|
3
|
+
|
|
4
|
+
Validates that all TypeScript test files conform to Node.js/TypeScript naming conventions.
|
|
5
|
+
Tests parametrized to run once per test file for surgical diagnostics.
|
|
6
|
+
|
|
7
|
+
Migration Note:
|
|
8
|
+
Legacy format: ac-{type}-{nnn}.{purpose-slug}.test.ts (uses acceptance ID)
|
|
9
|
+
New format: {wmbt_lower}-{harness_lower}-{nnn}[-{slug-kebab}].test.ts (uses URN)
|
|
10
|
+
|
|
11
|
+
New URN-based naming documented in:
|
|
12
|
+
- .claude/conventions/tester/filename.convention.yaml
|
|
13
|
+
- atdd.tester.utils.filename module
|
|
14
|
+
- SPEC-TESTER-CONV-0070
|
|
15
|
+
|
|
16
|
+
See test_acceptance_urn_filename_mapping.py for validation of new format.
|
|
17
|
+
"""
|
|
18
|
+
import pytest
|
|
19
|
+
import re
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.platform
|
|
24
|
+
def test_typescript_test_files_use_kebab_case(typescript_test_files):
|
|
25
|
+
"""
|
|
26
|
+
SPEC-PLATFORM-TS-0001: TypeScript test files use kebab-case naming
|
|
27
|
+
|
|
28
|
+
Given: TypeScript test files in supabase/ and e2e/ directories
|
|
29
|
+
When: Checking file naming conventions
|
|
30
|
+
Then: All test files use kebab-case (lowercase with hyphens)
|
|
31
|
+
No underscores allowed in filenames (except in .test.ts suffix)
|
|
32
|
+
Pattern: {normalized_id}.{purpose_slug}.test.ts
|
|
33
|
+
|
|
34
|
+
Convention: atdd/tester/conventions/red.convention.yaml:254-285
|
|
35
|
+
"""
|
|
36
|
+
errors = []
|
|
37
|
+
|
|
38
|
+
for test_file in typescript_test_files:
|
|
39
|
+
filename = test_file.name
|
|
40
|
+
|
|
41
|
+
# Remove .test.ts suffix
|
|
42
|
+
base_name = filename.replace('.test.ts', '')
|
|
43
|
+
|
|
44
|
+
# Check for invalid characters (underscores)
|
|
45
|
+
if '_' in base_name:
|
|
46
|
+
errors.append(
|
|
47
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
48
|
+
f" Contains underscores. Expected kebab-case format.\n"
|
|
49
|
+
f" Example: ac-http-006.primitive-endpoint.test.ts"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Check for uppercase letters
|
|
53
|
+
if base_name != base_name.lower():
|
|
54
|
+
errors.append(
|
|
55
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
56
|
+
f" Contains uppercase letters. Expected all lowercase.\n"
|
|
57
|
+
f" Example: ac-db-015.user-records-persist.test.ts"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if errors:
|
|
61
|
+
pytest.fail(
|
|
62
|
+
"\n\n🔴 TypeScript test files violate Node.js naming conventions:\n\n" +
|
|
63
|
+
"\n".join(errors) +
|
|
64
|
+
"\n\n📘 See: atdd/tester/conventions/red.convention.yaml:254-285"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@pytest.mark.platform
|
|
69
|
+
def test_typescript_test_files_match_acceptance_pattern(typescript_test_files):
|
|
70
|
+
"""
|
|
71
|
+
SPEC-PLATFORM-TS-0002: TypeScript test files follow acceptance-derived naming
|
|
72
|
+
|
|
73
|
+
Given: TypeScript test files in supabase/ and e2e/ directories
|
|
74
|
+
When: Checking naming pattern
|
|
75
|
+
Then: Files match pattern: {normalized_id}.{purpose_slug}.test.ts
|
|
76
|
+
normalized_id: AC-HTTP-006 → ac-http-006 (kebab-case)
|
|
77
|
+
purpose_slug: extracted from identity.purpose field (kebab-case)
|
|
78
|
+
|
|
79
|
+
Convention: atdd/tester/conventions/red.convention.yaml:254-285
|
|
80
|
+
"""
|
|
81
|
+
# Pattern: {normalized_id}.{purpose_slug}.test.ts
|
|
82
|
+
# normalized_id: ac-http-006, ac-db-015, etc.
|
|
83
|
+
# purpose_slug: primitive-endpoint, user-records-persist, etc.
|
|
84
|
+
|
|
85
|
+
valid_pattern = re.compile(r'^ac-[a-z]+-\d{3}\.[a-z][a-z0-9-]*\.test\.ts$')
|
|
86
|
+
errors = []
|
|
87
|
+
|
|
88
|
+
for test_file in typescript_test_files:
|
|
89
|
+
filename = test_file.name
|
|
90
|
+
|
|
91
|
+
if not valid_pattern.match(filename):
|
|
92
|
+
errors.append(
|
|
93
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
94
|
+
f" Pattern mismatch. Expected: ac-{{type}}-{{nnn}}.{{purpose}}.test.ts\n"
|
|
95
|
+
f" Example: ac-http-006.primitive-endpoint.test.ts"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if errors:
|
|
99
|
+
pytest.fail(
|
|
100
|
+
"\n\n🔴 TypeScript test files don't match expected pattern:\n\n" +
|
|
101
|
+
"\n".join(errors) +
|
|
102
|
+
"\n\n📘 Pattern: ac-{type}-{nnn}.{purpose}.test.ts\n" +
|
|
103
|
+
"📘 See: atdd/tester/conventions/red.convention.yaml:254-285"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@pytest.mark.platform
|
|
108
|
+
def test_typescript_test_files_have_urn_comment(typescript_test_files):
|
|
109
|
+
"""
|
|
110
|
+
SPEC-PLATFORM-TS-0003: TypeScript test files contain URN comment
|
|
111
|
+
|
|
112
|
+
Given: TypeScript test files in supabase/ and e2e/ directories
|
|
113
|
+
When: Reading file contents
|
|
114
|
+
Then: First line contains URN comment in format:
|
|
115
|
+
// urn: acc:{wagon}.{wmbt}.{acceptance_id}
|
|
116
|
+
|
|
117
|
+
Example: // urn: acc:maintain-ux.P002.AC-HTTP-006
|
|
118
|
+
"""
|
|
119
|
+
errors = []
|
|
120
|
+
|
|
121
|
+
for test_file in typescript_test_files:
|
|
122
|
+
with open(test_file, 'r') as f:
|
|
123
|
+
first_line = f.readline().strip()
|
|
124
|
+
|
|
125
|
+
# Check for URN comment pattern
|
|
126
|
+
urn_pattern = re.compile(r'^// urn: acc:[a-z][a-z0-9-]+\.[A-Z]\d{3}\.AC-[A-Z]+-\d{3}$')
|
|
127
|
+
|
|
128
|
+
if not urn_pattern.match(first_line):
|
|
129
|
+
errors.append(
|
|
130
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
131
|
+
f" Missing or invalid URN comment in first line.\n"
|
|
132
|
+
f" Found: {first_line[:80]}\n"
|
|
133
|
+
f" Expected: // urn: acc:{{wagon}}.{{wmbt}}.{{acceptance_id}}"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
if errors:
|
|
137
|
+
pytest.fail(
|
|
138
|
+
"\n\n🔴 TypeScript test files missing URN comments:\n\n" +
|
|
139
|
+
"\n".join(errors) +
|
|
140
|
+
"\n\n📘 First line must be: // urn: acc:{wagon}.{wmbt}.{acceptance_id}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@pytest.mark.platform
|
|
145
|
+
def test_typescript_test_files_organized_by_wagon(typescript_test_files):
|
|
146
|
+
"""
|
|
147
|
+
SPEC-PLATFORM-TS-0004: TypeScript test files organized by wagon
|
|
148
|
+
|
|
149
|
+
Given: TypeScript test files in supabase/ and e2e/ directories
|
|
150
|
+
When: Checking directory structure
|
|
151
|
+
Then: Backend tests: supabase/functions/{wagon}/test/{test_file}.test.ts
|
|
152
|
+
E2E tests: e2e/{wagon}/{test_file}.test.ts
|
|
153
|
+
|
|
154
|
+
Example: supabase/functions/maintain-ux/test/ac-http-006.primitive-endpoint.test.ts
|
|
155
|
+
"""
|
|
156
|
+
errors = []
|
|
157
|
+
|
|
158
|
+
for test_file in typescript_test_files:
|
|
159
|
+
parts = test_file.parts
|
|
160
|
+
|
|
161
|
+
# Check if it's a supabase backend test
|
|
162
|
+
if 'supabase' in parts and 'functions' in parts:
|
|
163
|
+
try:
|
|
164
|
+
supabase_idx = parts.index('supabase')
|
|
165
|
+
functions_idx = parts.index('functions')
|
|
166
|
+
|
|
167
|
+
# Expected: supabase/functions/{wagon}/test/{file}.test.ts
|
|
168
|
+
if functions_idx != supabase_idx + 1:
|
|
169
|
+
errors.append(
|
|
170
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
171
|
+
f" Invalid structure. Expected: supabase/functions/{{wagon}}/test/{{file}}.test.ts"
|
|
172
|
+
)
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
remaining = parts[functions_idx + 1:]
|
|
176
|
+
# Should have: wagon/test/file.test.ts
|
|
177
|
+
if len(remaining) < 3 or remaining[1] != 'test':
|
|
178
|
+
errors.append(
|
|
179
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
180
|
+
f" Not in test/ subdirectory.\n"
|
|
181
|
+
f" Expected: supabase/functions/{{wagon}}/test/{{file}}.test.ts"
|
|
182
|
+
)
|
|
183
|
+
except (ValueError, IndexError):
|
|
184
|
+
errors.append(
|
|
185
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
186
|
+
f" Invalid supabase structure"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Check if it's an e2e test
|
|
190
|
+
elif 'e2e' in parts:
|
|
191
|
+
try:
|
|
192
|
+
e2e_idx = parts.index('e2e')
|
|
193
|
+
remaining = parts[e2e_idx + 1:]
|
|
194
|
+
|
|
195
|
+
# Should have at least: wagon/file.test.ts
|
|
196
|
+
if len(remaining) < 2:
|
|
197
|
+
errors.append(
|
|
198
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
199
|
+
f" Not organized by wagon.\n"
|
|
200
|
+
f" Expected: e2e/{{wagon}}/{{file}}.test.ts"
|
|
201
|
+
)
|
|
202
|
+
except (ValueError, IndexError):
|
|
203
|
+
errors.append(
|
|
204
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
205
|
+
f" Invalid e2e structure"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if errors:
|
|
209
|
+
pytest.fail(
|
|
210
|
+
"\n\n🔴 TypeScript test files not properly organized:\n\n" +
|
|
211
|
+
"\n".join(errors) +
|
|
212
|
+
"\n\n📘 Backend: supabase/functions/{wagon}/test/{file}.test.ts\n" +
|
|
213
|
+
"📘 E2E: e2e/{wagon}/{file}.test.ts"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@pytest.mark.platform
|
|
218
|
+
def test_typescript_test_filename_matches_urn_acceptance_id(typescript_test_files):
|
|
219
|
+
"""
|
|
220
|
+
SPEC-PLATFORM-TS-0005: Test filename normalized_id matches URN acceptance_id
|
|
221
|
+
|
|
222
|
+
Given: TypeScript test files with URN comments
|
|
223
|
+
When: Comparing filename normalized_id to URN acceptance_id
|
|
224
|
+
Then: normalized_id matches acceptance_id (converted to kebab-case)
|
|
225
|
+
Example: ac-http-006 matches AC-HTTP-006
|
|
226
|
+
|
|
227
|
+
Convention: atdd/tester/conventions/red.convention.yaml:255-260
|
|
228
|
+
"""
|
|
229
|
+
errors = []
|
|
230
|
+
|
|
231
|
+
for test_file in typescript_test_files:
|
|
232
|
+
# Read URN from first line
|
|
233
|
+
with open(test_file, 'r') as f:
|
|
234
|
+
first_line = f.readline().strip()
|
|
235
|
+
|
|
236
|
+
# Extract acceptance_id from URN (e.g., AC-HTTP-006)
|
|
237
|
+
urn_match = re.search(r'// urn: acc:[a-z][a-z0-9-]+\.[A-Z]\d{3}\.(AC-[A-Z]+-\d{3})', first_line)
|
|
238
|
+
|
|
239
|
+
if not urn_match:
|
|
240
|
+
continue # Skip if URN not found (covered by other test)
|
|
241
|
+
|
|
242
|
+
acceptance_id = urn_match.group(1) # e.g., AC-HTTP-006
|
|
243
|
+
|
|
244
|
+
# Normalize acceptance_id to kebab-case
|
|
245
|
+
expected_normalized_id = acceptance_id.lower() # ac-http-006
|
|
246
|
+
|
|
247
|
+
# Extract normalized_id from filename (first part before purpose_slug)
|
|
248
|
+
filename = test_file.name
|
|
249
|
+
# Pattern: {normalized_id}.{purpose_slug}.test.ts
|
|
250
|
+
parts = filename.replace('.test.ts', '').split('.')
|
|
251
|
+
|
|
252
|
+
if len(parts) >= 1:
|
|
253
|
+
actual_normalized_id = parts[0] # ac-http-006
|
|
254
|
+
|
|
255
|
+
if actual_normalized_id != expected_normalized_id:
|
|
256
|
+
errors.append(
|
|
257
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
258
|
+
f" Filename normalized_id doesn't match URN acceptance_id.\n"
|
|
259
|
+
f" URN acceptance_id: {acceptance_id}\n"
|
|
260
|
+
f" Expected normalized: {expected_normalized_id}\n"
|
|
261
|
+
f" Actual in filename: {actual_normalized_id}"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
if errors:
|
|
265
|
+
pytest.fail(
|
|
266
|
+
"\n\n🔴 TypeScript test filenames don't match URN acceptance IDs:\n\n" +
|
|
267
|
+
"\n".join(errors) +
|
|
268
|
+
"\n\n📘 Transformation: AC-HTTP-006 → ac-http-006\n" +
|
|
269
|
+
"📘 See: atdd/tester/conventions/red.convention.yaml:255-260"
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@pytest.mark.platform
|
|
274
|
+
def test_typescript_test_files_use_correct_extension(typescript_test_files):
|
|
275
|
+
"""
|
|
276
|
+
SPEC-PLATFORM-TS-0006: TypeScript test files use .test.ts extension
|
|
277
|
+
|
|
278
|
+
Given: TypeScript test files in supabase/ and e2e/ directories
|
|
279
|
+
When: Checking file extensions
|
|
280
|
+
Then: Files use .test.ts
|
|
281
|
+
No other extensions allowed
|
|
282
|
+
|
|
283
|
+
Convention: Standard Node.js/TypeScript testing convention
|
|
284
|
+
"""
|
|
285
|
+
errors = []
|
|
286
|
+
|
|
287
|
+
for test_file in typescript_test_files:
|
|
288
|
+
filename = test_file.name
|
|
289
|
+
|
|
290
|
+
if not filename.endswith('.test.ts'):
|
|
291
|
+
errors.append(
|
|
292
|
+
f"❌ {test_file.relative_to(Path.cwd())}\n"
|
|
293
|
+
f" Invalid extension. Expected: .test.ts"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
if errors:
|
|
297
|
+
pytest.fail(
|
|
298
|
+
"\n\n🔴 TypeScript test files have invalid extensions:\n\n" +
|
|
299
|
+
"\n".join(errors) +
|
|
300
|
+
"\n\n📘 Use .test.ts"
|
|
301
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Platform tests: TypeScript test structure validation.
|
|
3
|
+
|
|
4
|
+
Focuses on URN headers and TSX usage for component tests under web/tests/.
|
|
5
|
+
"""
|
|
6
|
+
import pytest
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
URN_HEADER_PATTERN = re.compile(
|
|
11
|
+
r'^//\s*(?:URN|urn):\s*(acc:[a-z][a-z0-9-]*:[A-Z][0-9]{3}-[A-Z0-9]+-[0-9]{3}(?:-[a-z0-9-]+)?)$'
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.platform
|
|
16
|
+
def test_typescript_test_files_have_urn_header(web_typescript_test_files):
|
|
17
|
+
"""
|
|
18
|
+
SPEC-TESTER-TS-001: All TypeScript test files must have URN header.
|
|
19
|
+
"""
|
|
20
|
+
errors = []
|
|
21
|
+
|
|
22
|
+
for test_file in web_typescript_test_files:
|
|
23
|
+
lines = test_file.read_text().splitlines()
|
|
24
|
+
first_non_empty = next((line.strip() for line in lines if line.strip()), "")
|
|
25
|
+
|
|
26
|
+
if not URN_HEADER_PATTERN.match(first_non_empty):
|
|
27
|
+
errors.append(
|
|
28
|
+
f"❌ {test_file}\n"
|
|
29
|
+
f" Missing URN header in first non-empty line.\n"
|
|
30
|
+
f" Expected: // URN: acc:{{wagon}}:{{WMBT}}-{{HARNESS}}-{{NNN}}[-slug]"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if errors:
|
|
34
|
+
pytest.fail(
|
|
35
|
+
"\n\n🔴 TypeScript test files missing URN headers:\n\n" +
|
|
36
|
+
"\n".join(errors)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.platform
|
|
41
|
+
def test_component_tests_use_tsx_extension(web_typescript_test_files):
|
|
42
|
+
"""
|
|
43
|
+
SPEC-TESTER-TS-002: Component tests using JSX must use .test.tsx.
|
|
44
|
+
"""
|
|
45
|
+
errors = []
|
|
46
|
+
|
|
47
|
+
for test_file in web_typescript_test_files:
|
|
48
|
+
content = test_file.read_text()
|
|
49
|
+
has_render = "from '@testing-library/preact'" in content
|
|
50
|
+
has_jsx = bool(re.search(r'<\\w+.*?>', content))
|
|
51
|
+
|
|
52
|
+
if (has_render or has_jsx) and not test_file.name.endswith(".test.tsx"):
|
|
53
|
+
errors.append(
|
|
54
|
+
f"❌ {test_file}\n"
|
|
55
|
+
f" Component test uses JSX but is not .test.tsx"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if errors:
|
|
59
|
+
pytest.fail(
|
|
60
|
+
"\n\n🔴 Component tests must use .test.tsx:\n\n" +
|
|
61
|
+
"\n".join(errors)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.mark.platform
|
|
66
|
+
def test_preact_test_files_use_urn_filename_format(web_typescript_test_files):
|
|
67
|
+
"""
|
|
68
|
+
SPEC-TESTER-TS-003: Preact TypeScript tests use URN-based filename format.
|
|
69
|
+
"""
|
|
70
|
+
pattern = re.compile(r'^([A-Z][0-9]{3})_([A-Z0-9]+)_([0-9]{3})(?:_([a-z0-9_]+))?\.test\.ts(x)?$')
|
|
71
|
+
errors = []
|
|
72
|
+
|
|
73
|
+
for test_file in web_typescript_test_files:
|
|
74
|
+
if not pattern.match(test_file.name):
|
|
75
|
+
errors.append(
|
|
76
|
+
f"❌ {test_file}\n"
|
|
77
|
+
f" Expected: C004_UNIT_001_slug.test.ts[x]"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if errors:
|
|
81
|
+
pytest.fail(
|
|
82
|
+
"\n\n🔴 Preact TypeScript tests use invalid filenames:\n\n" +
|
|
83
|
+
"\n".join(errors)
|
|
84
|
+
)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: atdd
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ATDD Platform - Acceptance Test Driven Development toolkit
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: pyyaml
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest; extra == "dev"
|
|
12
|
+
Requires-Dist: pytest-xdist; extra == "dev"
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# ATDD
|
|
16
|
+
|
|
17
|
+
Acceptance Test Driven Development toolkit for structured planning and convention enforcement.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
### From GitHub (recommended for now)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install git+https://github.com/afokapu/atdd.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### For Development
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Clone the repo
|
|
31
|
+
git clone https://github.com/afokapu/atdd.git
|
|
32
|
+
cd atdd
|
|
33
|
+
|
|
34
|
+
# Install in editable mode with dev dependencies
|
|
35
|
+
pip install -e ".[dev]"
|
|
36
|
+
|
|
37
|
+
# Verify installation
|
|
38
|
+
atdd --help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Future: PyPI
|
|
42
|
+
|
|
43
|
+
Once published to PyPI:
|
|
44
|
+
```bash
|
|
45
|
+
pip install atdd
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Initialize ATDD in your project
|
|
52
|
+
atdd init
|
|
53
|
+
|
|
54
|
+
# Create a planning session
|
|
55
|
+
atdd session new my-feature
|
|
56
|
+
|
|
57
|
+
# List sessions
|
|
58
|
+
atdd session list
|
|
59
|
+
|
|
60
|
+
# Run validators
|
|
61
|
+
atdd --test all
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## What It Does
|
|
65
|
+
|
|
66
|
+
ATDD provides:
|
|
67
|
+
|
|
68
|
+
1. **Session Management** - Structured planning documents with templates and tracking
|
|
69
|
+
2. **Convention Enforcement** - YAML-based conventions validated via pytest
|
|
70
|
+
3. **ATDD Lifecycle** - Planner → Tester → Coder phase gates
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
### Project Initialization
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
atdd init # Create atdd-sessions/ and .atdd/ directories
|
|
78
|
+
atdd init --force # Reinitialize (overwrites existing)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Creates:
|
|
82
|
+
```
|
|
83
|
+
your-project/
|
|
84
|
+
├── atdd-sessions/
|
|
85
|
+
│ ├── SESSION-TEMPLATE.md
|
|
86
|
+
│ └── archive/
|
|
87
|
+
└── .atdd/
|
|
88
|
+
└── manifest.yaml
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Session Management
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
atdd session new <slug> # Create new session
|
|
95
|
+
atdd session new <slug> --type <type> # Specify type
|
|
96
|
+
atdd session list # List all sessions
|
|
97
|
+
atdd session archive <id> # Archive session
|
|
98
|
+
atdd session sync # Sync manifest with files
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Session types: `implementation`, `migration`, `refactor`, `analysis`, `planning`, `cleanup`, `tracking`
|
|
102
|
+
|
|
103
|
+
### Validation
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
atdd --test all # Run all validators
|
|
107
|
+
atdd --test planner # Planning artifacts only
|
|
108
|
+
atdd --test tester # Testing artifacts only
|
|
109
|
+
atdd --test coder # Implementation only
|
|
110
|
+
atdd --quick # Fast smoke test
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Other Commands
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
atdd --status # Platform status
|
|
117
|
+
atdd --inventory # Generate artifact inventory
|
|
118
|
+
atdd --help # Full help
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Project Structure
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
src/atdd/
|
|
125
|
+
├── cli.py # Entry point
|
|
126
|
+
├── coach/
|
|
127
|
+
│ ├── commands/ # CLI command implementations
|
|
128
|
+
│ ├── conventions/ # Coach conventions (YAML)
|
|
129
|
+
│ ├── schemas/ # JSON schemas
|
|
130
|
+
│ ├── templates/ # Session templates
|
|
131
|
+
│ └── validators/ # Coach validators
|
|
132
|
+
├── planner/
|
|
133
|
+
│ ├── conventions/ # Planning conventions
|
|
134
|
+
│ ├── schemas/ # Planning schemas
|
|
135
|
+
│ └── validators/ # Planning validators
|
|
136
|
+
├── tester/
|
|
137
|
+
│ ├── conventions/ # Testing conventions
|
|
138
|
+
│ ├── schemas/ # Testing schemas
|
|
139
|
+
│ └── validators/ # Testing validators
|
|
140
|
+
└── coder/
|
|
141
|
+
├── conventions/ # Coding conventions
|
|
142
|
+
├── schemas/ # Coder schemas
|
|
143
|
+
└── validators/ # Implementation validators
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
### Setup
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
git clone https://github.com/afokapu/atdd.git
|
|
152
|
+
cd atdd
|
|
153
|
+
pip install -e ".[dev]"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Run Tests
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# All tests
|
|
160
|
+
pytest
|
|
161
|
+
|
|
162
|
+
# Specific phase
|
|
163
|
+
pytest src/atdd/planner/validators/
|
|
164
|
+
|
|
165
|
+
# With coverage
|
|
166
|
+
pytest --cov=atdd --cov-report=html
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Adding Validators
|
|
170
|
+
|
|
171
|
+
1. Create `src/atdd/{phase}/validators/test_{name}.py`
|
|
172
|
+
2. Write pytest test functions
|
|
173
|
+
3. Run `atdd --test {phase}`
|
|
174
|
+
|
|
175
|
+
Validators are auto-discovered by pytest.
|
|
176
|
+
|
|
177
|
+
### Adding Conventions
|
|
178
|
+
|
|
179
|
+
1. Create `src/atdd/{phase}/conventions/{name}.convention.yaml`
|
|
180
|
+
2. Reference in validators via `Path(__file__).parent.parent / "conventions" / "..."`
|
|
181
|
+
|
|
182
|
+
## Requirements
|
|
183
|
+
|
|
184
|
+
- Python 3.10+
|
|
185
|
+
- pyyaml
|
|
186
|
+
|
|
187
|
+
Dev dependencies: pytest, pytest-xdist
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|