@afokapu/atdd-bun 0.4.0 → 0.6.0

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 (209) hide show
  1. package/README.md +85 -3
  2. package/conventions/coder.bun/coder.bun.complexity-cyclomatic.convention.yaml +1 -3
  3. package/conventions/coder.bun/coder.bun.complexity-length.convention.yaml +1 -2
  4. package/conventions/coder.bun/coder.bun.complexity-nesting.convention.yaml +1 -2
  5. package/conventions/coder.bun/coder.bun.dead-code-reachability.convention.yaml +1 -2
  6. package/conventions/coder.bun/coder.bun.design-token-color.convention.yaml +1 -1
  7. package/conventions/coder.bun/coder.bun.design-token-hardcoded.convention.yaml +1 -1
  8. package/conventions/coder.bun/coder.bun.dto-mapper.convention.yaml +2 -1
  9. package/conventions/coder.bun/coder.bun.dto-placement.convention.yaml +2 -1
  10. package/conventions/coder.bun/coder.bun.dto-purity.convention.yaml +2 -1
  11. package/conventions/coder.bun/coder.bun.duplication-intra-layer.convention.yaml +1 -2
  12. package/conventions/coder.bun/coder.bun.green-header-order.convention.yaml +2 -11
  13. package/conventions/coder.bun/coder.bun.green-header-purpose.convention.yaml +2 -11
  14. package/conventions/coder.bun/coder.bun.green-header-runtime.convention.yaml +2 -11
  15. package/conventions/coder.bun/coder.bun.green-header-tested-by.convention.yaml +2 -11
  16. package/conventions/coder.bun/coder.bun.green-urn-layer.convention.yaml +2 -11
  17. package/conventions/coder.bun/coder.bun.green-urn-marker.convention.yaml +2 -12
  18. package/conventions/coder.bun/coder.bun.green-urn-name-matches.convention.yaml +3 -12
  19. package/conventions/coder.bun/coder.bun.green-urn-pattern.convention.yaml +2 -11
  20. package/conventions/coder.bun/coder.bun.green-urn-side.convention.yaml +2 -11
  21. package/conventions/coder.bun/coder.bun.green-urn-wagon-feature.convention.yaml +2 -11
  22. package/conventions/coder.bun/coder.bun.layer-naming.convention.yaml +2 -1
  23. package/conventions/coder.bun/coder.bun.logging-structured.convention.yaml +2 -4
  24. package/conventions/coder.bun/coder.bun.quality-comments.convention.yaml +1 -2
  25. package/conventions/coder.bun/coder.bun.quality-mi.convention.yaml +1 -2
  26. package/conventions/coder.bun/coder.bun.responsive-breakpoints-declared.convention.yaml +31 -0
  27. package/conventions/coder.bun/coder.bun.responsive-no-fixed-width.convention.yaml +30 -0
  28. package/conventions/coder.bun/coder.bun.responsive-viewport-meta.convention.yaml +31 -0
  29. package/conventions/coder.bun/coder.bun.runtime-executes-the-declaration.convention.yaml +2 -18
  30. package/conventions/coder.bun/coder.bun.runtime-typecheck-enforced.convention.yaml +2 -15
  31. package/conventions/coder.htmx/coder.htmx.swap-no-inline-handler.convention.yaml +3 -3
  32. package/conventions/coder.htmx/coder.htmx.verb-endpoint-is-routed.convention.yaml +2 -2
  33. package/conventions/coder.htmx/coder.htmx.verb-mutation-signals-progress.convention.yaml +3 -2
  34. package/conventions/planner.docs/planner.docs.adr-registry-derived.convention.yaml +2 -12
  35. package/conventions/planner.docs/planner.docs.area-index-required.convention.yaml +2 -12
  36. package/conventions/planner.docs/planner.docs.artifact-path-shape.convention.yaml +2 -12
  37. package/conventions/planner.docs/planner.docs.asciidoc-only.convention.yaml +2 -13
  38. package/conventions/planner.docs/planner.docs.doc-id-unique.convention.yaml +2 -12
  39. package/conventions/planner.docs/planner.docs.graph-target-resolves.convention.yaml +2 -12
  40. package/conventions/planner.docs/planner.docs.identity-required.convention.yaml +2 -12
  41. package/conventions/planner.docs/planner.docs.reference-integrity.convention.yaml +2 -12
  42. package/conventions/planner.docs/planner.docs.undeclared-change.convention.yaml +2 -12
  43. package/conventions/tester.bun/tester.bun.acceptance-binding-declared.convention.yaml +2 -6
  44. package/conventions/tester.bun/tester.bun.acceptance-covers-tag-well-formed.convention.yaml +1 -5
  45. package/conventions/tester.bun/tester.bun.interlocking-train-sequence-is-exercised.convention.yaml +2 -14
  46. package/conventions/tester.bun/tester.bun.red-behavioral-assertion.convention.yaml +1 -5
  47. package/conventions/tester.bun/tester.bun.routing-runtime-family.convention.yaml +2 -1
  48. package/conventions/tester.bun/tester.bun.smoke-no-collaborator-substitution.convention.yaml +2 -7
  49. package/conventions/tester.bun/tester.bun.smoke-observable-assertion.convention.yaml +2 -7
  50. package/conventions/tester.bun/tester.bun.telemetry-emit.convention.yaml +2 -1
  51. package/conventions/tester.bun/tester.bun.test-carries-urn-identity.convention.yaml +2 -6
  52. package/conventions/tester.bun/tester.bun.test-isolation-no-live-state.convention.yaml +1 -5
  53. package/conventions/tester.bun/tester.bun.test-no-self-skip.convention.yaml +1 -5
  54. package/conventions/tester.bun/tester.bun.test-phase-declared.convention.yaml +2 -6
  55. package/conventions/tester.htmx/tester.htmx.a11y-harness.convention.yaml +32 -0
  56. package/conventions/tester.htmx/tester.htmx.covered-train-is-routed.convention.yaml +30 -0
  57. package/conventions/tester.htmx/tester.htmx.e2e-binds-declared-subject.convention.yaml +31 -0
  58. package/conventions/tester.htmx/tester.htmx.e2e-spec-naming.convention.yaml +32 -0
  59. package/conventions/tester.htmx/tester.htmx.exposed-journey-e2e-coverage.convention.yaml +31 -0
  60. package/conventions/tester.htmx/tester.htmx.fragment-asserts-returned-markup.convention.yaml +2 -6
  61. package/conventions/tester.htmx/tester.htmx.journey-binding-header.convention.yaml +32 -0
  62. package/conventions/tester.htmx/tester.htmx.journey-layer-assembly.convention.yaml +29 -0
  63. package/conventions/tester.htmx/tester.htmx.journey-no-acceptance-marker.convention.yaml +29 -0
  64. package/conventions/tester.htmx/tester.htmx.journey-urn-format.convention.yaml +32 -0
  65. package/conventions/tester.htmx/tester.htmx.presentation-smoke-coverage.convention.yaml +31 -0
  66. package/conventions/tester.htmx/tester.htmx.responsive-harness.convention.yaml +33 -0
  67. package/conventions/tester.htmx/tester.htmx.responsive-journey-coverage.convention.yaml +30 -0
  68. package/conventions/tester.htmx/tester.htmx.swap-oob-asserts-destination-id.convention.yaml +2 -1
  69. package/conventions/tester.htmx/tester.htmx.train-e2e-coverage.convention.yaml +32 -0
  70. package/conventions/tester.htmx/tester.htmx.verb-endpoint-coverage.convention.yaml +2 -1
  71. package/conventions/tester.htmx/tester.htmx.visual-harness.convention.yaml +28 -0
  72. package/conventions/traceability/traceability.plan.executable-acceptance-has-test.convention.yaml +5 -0
  73. package/conventions/traceability/traceability.source.tested-by-present.convention.yaml +5 -0
  74. package/conventions/traceability/traceability.source.tested-by-resolves.convention.yaml +5 -0
  75. package/conventions/traceability/traceability.test.binding-resolves.convention.yaml +5 -0
  76. package/detectors/atdd_topology/atdd.implementation.yaml +13 -0
  77. package/detectors/atdd_topology/detect.mjs +171 -0
  78. package/detectors/atdd_topology/fixtures/clean/atdd-bun.yaml +2 -0
  79. package/detectors/atdd_topology/fixtures/clean/e2e/interlockings/checkout/nominal.routes.test.ts +4 -0
  80. package/detectors/atdd_topology/fixtures/clean/e2e/journeys/checkout.journey.test.ts +4 -0
  81. package/detectors/atdd_topology/fixtures/clean/implementation/orders/features/place-order/domain/order.ts +4 -0
  82. package/detectors/atdd_topology/fixtures/clean/plan/_journeys/checkout.yaml +4 -0
  83. package/detectors/atdd_topology/fixtures/clean/plan/_trains/_interlockings/checkout.yaml +4 -0
  84. package/detectors/atdd_topology/fixtures/clean/plan/_trains/checkout.yaml +1 -0
  85. package/detectors/atdd_topology/fixtures/clean/plan/orders/E001.yaml +6 -0
  86. package/detectors/atdd_topology/fixtures/clean/plan/orders/_orders.yaml +5 -0
  87. package/detectors/atdd_topology/fixtures/clean/plan/orders/place-order.yaml +3 -0
  88. package/detectors/atdd_topology/fixtures/clean/tests/wagons/orders/features/place-order/unit/order.test.ts +4 -0
  89. package/detectors/atdd_topology/fixtures/dirty/plan/_journeys/checkout.yaml +3 -0
  90. package/detectors/atdd_topology/fixtures/dirty/plan/orders/E001.yaml +4 -0
  91. package/detectors/atdd_topology/fixtures/dirty/plan/orders/_orders.yaml +4 -0
  92. package/detectors/atdd_topology/fixtures/dirty/plan/orders/features/place-order.yaml +3 -0
  93. package/detectors/atdd_topology/fixtures/dirty/src/wagons/orders/features/place-order/domain/forged.ts +2 -0
  94. package/detectors/atdd_topology/fixtures/dirty/src/wagons/orders/features/place-order/domain/order.ts +2 -0
  95. package/detectors/atdd_topology/fixtures/dirty/tests/wagons/orders/features/place-order/unit/order.test.ts +4 -0
  96. package/detectors/atdd_traceability_closure/detect.mjs +5 -2
  97. package/detectors/bun_green_traceability_detector/urn_header.mjs +2 -1
  98. package/detectors/bun_interlocking_binding/checks/interlocking_runtime_executes.mjs +3 -2
  99. package/detectors/bun_interlocking_binding/detect.mjs +6 -5
  100. package/detectors/bun_interlocking_coverage/_shared/interlocking.mjs +4 -3
  101. package/detectors/bun_interlocking_coverage/checks/interlocking_train_sequence.mjs +2 -2
  102. package/detectors/bun_interlocking_infrastructure/_shared/interlocking.mjs +2 -1
  103. package/detectors/bun_interlocking_infrastructure/checks/journey_runner_boundary.mjs +3 -2
  104. package/detectors/bun_interlocking_infrastructure/checks/journey_station_routing.mjs +2 -1
  105. package/detectors/bun_interlocking_infrastructure/checks/wagon_contract_honoured.mjs +3 -2
  106. package/detectors/bun_responsive_detector/atdd.implementation.yaml +18 -0
  107. package/detectors/bun_responsive_detector/checks/_map.json +5 -0
  108. package/detectors/bun_responsive_detector/checks/_responsive.mjs +20 -0
  109. package/detectors/bun_responsive_detector/checks/responsive_breakpoints_declared.mjs +21 -0
  110. package/detectors/bun_responsive_detector/checks/responsive_no_fixed_width.mjs +13 -0
  111. package/detectors/bun_responsive_detector/checks/responsive_viewport_meta.mjs +20 -0
  112. package/detectors/bun_responsive_detector/detect.mjs +46 -0
  113. package/detectors/bun_responsive_detector/fixtures/clean/public/index.html +9 -0
  114. package/detectors/bun_responsive_detector/fixtures/clean/src/app.css +13 -0
  115. package/detectors/bun_responsive_detector/fixtures/clean/src/document.ts +7 -0
  116. package/detectors/bun_responsive_detector/fixtures/clean/src/fragment.html +1 -0
  117. package/detectors/bun_responsive_detector/fixtures/clean/src/head.ts +1 -0
  118. package/detectors/bun_responsive_detector/fixtures/clean/src/layout.tsx +8 -0
  119. package/detectors/bun_responsive_detector/fixtures/clean/src/range.css +3 -0
  120. package/detectors/bun_responsive_detector/fixtures/clean/src/viewport-expression.tsx +5 -0
  121. package/detectors/bun_responsive_detector/fixtures/dirty/public/fixed-viewport.html +5 -0
  122. package/detectors/bun_responsive_detector/fixtures/dirty/public/no-meta.html +5 -0
  123. package/detectors/bun_responsive_detector/fixtures/dirty/public/no-zoom.html +5 -0
  124. package/detectors/bun_responsive_detector/fixtures/dirty/public/scale.html +5 -0
  125. package/detectors/bun_responsive_detector/fixtures/dirty/src/app.css +4 -0
  126. package/detectors/bun_responsive_detector/fixtures/dirty/src/render.ts +2 -0
  127. package/detectors/bun_responsive_detector/fixtures/dirty/src/units.css +3 -0
  128. package/detectors/bun_responsive_detector/fixtures/dirty/src/wide.tsx +3 -0
  129. package/detectors/bun_tester_discipline_detector/checks/t_acceptance_resolves.mjs +7 -6
  130. package/detectors/htmx_e2e_detector/atdd.implementation.yaml +40 -0
  131. package/detectors/htmx_e2e_detector/checks/_e2e.mjs +98 -0
  132. package/detectors/htmx_e2e_detector/checks/_map.json +16 -0
  133. package/detectors/htmx_e2e_detector/checks/a11y_harness.mjs +21 -0
  134. package/detectors/htmx_e2e_detector/checks/covered_train_is_routed.mjs +6 -0
  135. package/detectors/htmx_e2e_detector/checks/e2e_binds_declared_subject.mjs +11 -0
  136. package/detectors/htmx_e2e_detector/checks/e2e_spec_naming.mjs +6 -0
  137. package/detectors/htmx_e2e_detector/checks/exposed_journey_e2e_coverage.mjs +7 -0
  138. package/detectors/htmx_e2e_detector/checks/journey_binding_header.mjs +13 -0
  139. package/detectors/htmx_e2e_detector/checks/journey_layer_assembly.mjs +11 -0
  140. package/detectors/htmx_e2e_detector/checks/journey_no_acceptance_marker.mjs +6 -0
  141. package/detectors/htmx_e2e_detector/checks/journey_urn_format.mjs +18 -0
  142. package/detectors/htmx_e2e_detector/checks/presentation_smoke_coverage.mjs +15 -0
  143. package/detectors/htmx_e2e_detector/checks/responsive_harness.mjs +30 -0
  144. package/detectors/htmx_e2e_detector/checks/responsive_journey_coverage.mjs +7 -0
  145. package/detectors/htmx_e2e_detector/checks/train_e2e_coverage.mjs +7 -0
  146. package/detectors/htmx_e2e_detector/checks/visual_harness.mjs +7 -0
  147. package/detectors/htmx_e2e_detector/detect.mjs +46 -0
  148. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/buy-alias.a11y.e2e.ts +12 -0
  149. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/buy-inline.responsive.e2e.ts +11 -0
  150. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/buy.a11y.e2e.ts +12 -0
  151. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/buy.responsive.e2e.ts +14 -0
  152. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/buy.visual.e2e.ts +10 -0
  153. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/checkout-buy.smoke.e2e.ts +10 -0
  154. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/crlf.e2e.ts +10 -0
  155. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/place-order.e2e.ts +10 -0
  156. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/reject-empty-cart.e2e.ts +10 -0
  157. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/support/fixtures.ts +3 -0
  158. package/detectors/htmx_e2e_detector/fixtures/clean/e2e/take-payment.e2e.ts +10 -0
  159. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_journeys/buy.yaml +19 -0
  160. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_journeys/settle.yaml +14 -0
  161. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/_interlockings/checkout.yaml +21 -0
  162. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/_interlockings/payment.yaml +16 -0
  163. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/_interlockings/settlement.yaml +16 -0
  164. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/orders/place-order.yaml +11 -0
  165. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/orders/reject-empty-cart.yaml +11 -0
  166. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/orders/settle-ledger.yaml +11 -0
  167. package/detectors/htmx_e2e_detector/fixtures/clean/plan/_trains/orders/take-payment.yaml +11 -0
  168. package/detectors/htmx_e2e_detector/fixtures/clean/playwright.config.ts +3 -0
  169. package/detectors/htmx_e2e_detector/fixtures/clean/src/wagons/checkout/presentation/cart.tsx +3 -0
  170. package/detectors/htmx_e2e_detector/fixtures/clean/tests/urn-parser.test.ts +7 -0
  171. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/acceptance.e2e.ts +6 -0
  172. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/bad-id.e2e.ts +10 -0
  173. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/bad-urn.e2e.ts +10 -0
  174. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/both.e2e.ts +6 -0
  175. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/buy.a11y.e2e.ts +10 -0
  176. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/buy.responsive.e2e.ts +11 -0
  177. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/buy.visual.e2e.ts +10 -0
  178. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/covered.e2e.ts +10 -0
  179. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/first-only.responsive.e2e.ts +13 -0
  180. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/ghost.e2e.ts +10 -0
  181. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/misnamed.spec.ts +10 -0
  182. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/no-binding.e2e.ts +4 -0
  183. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/no-layer.e2e.ts +4 -0
  184. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/no-urn.e2e.ts +4 -0
  185. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/tautology.a11y.e2e.ts +11 -0
  186. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/two-trains.e2e.ts +6 -0
  187. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/unrouted.e2e.ts +10 -0
  188. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/wrong-layer.e2e.ts +5 -0
  189. package/detectors/htmx_e2e_detector/fixtures/dirty/e2e/wrong-urn.e2e.ts +10 -0
  190. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_journeys/browse.yaml +16 -0
  191. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_journeys/buy.yaml +16 -0
  192. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_trains/_interlockings/checkout.yaml +21 -0
  193. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_trains/orders/covered.yaml +11 -0
  194. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_trains/orders/uncovered.yaml +11 -0
  195. package/detectors/htmx_e2e_detector/fixtures/dirty/plan/_trains/orders/unrouted.yaml +11 -0
  196. package/detectors/htmx_e2e_detector/fixtures/dirty/src/wagons/billing/presentation/invoice.tsx +3 -0
  197. package/integrity.json +208 -79
  198. package/lib/frontend.mjs +17 -0
  199. package/lib/scan.mjs +6 -2
  200. package/package.json +5 -1
  201. package/planner-nodes/ENFORCEMENT_SCOPE.yaml +18 -1
  202. package/relationships.yaml +4782 -4506
  203. package/src/enforce.ts +10 -7
  204. package/src/hooks.ts +2 -1
  205. package/src/index.ts +2 -0
  206. package/src/planner-kernel.ts +2 -1
  207. package/src/planner-schema-validator.ts +12 -10
  208. package/src/planner-validators.ts +16 -15
  209. package/src/topology.ts +40 -0
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bun
2
+ // FAMILY validator: htmx_e2e_detector
3
+ // Runs each member check (checks/*.mjs) VERBATIM as a subprocess and merges their
4
+ // RAW v1.1 reports into one — ONE implementation realizing a family of rule_ids
5
+ // (the Core pattern; see frontend.workspace.runtime's families).
6
+ //
7
+ // Members are spawned with `process.execPath`, which under this provider IS the
8
+ // bun binary, so a member may be authored as .mjs OR .ts with no build step.
9
+ // Files whose name begins with `_` are skipped: they are shared helpers, not
10
+ // checks. (The node-runtime families have no such convention because each of
11
+ // their checks re-implements its own walker; this provider factors the walk into
12
+ // lib/scan.mjs instead.)
13
+ import { execFileSync } from "node:child_process";
14
+ import { readFileSync, writeFileSync, mkdtempSync, readdirSync } from "node:fs";
15
+ import { tmpdir } from "node:os";
16
+ import { join, dirname } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+
19
+ const here = dirname(fileURLToPath(import.meta.url));
20
+ const reportPath = process.env.ATDD_VIOLATIONS_REPORT;
21
+ if (!reportPath) {
22
+ process.stderr.write("family: ATDD_VIOLATIONS_REPORT not set\n");
23
+ process.exit(2);
24
+ }
25
+ const checks = readdirSync(join(here, "checks"))
26
+ .filter((f) => (f.endsWith(".mjs") || f.endsWith(".ts")) && !f.startsWith("_"))
27
+ .sort();
28
+ const td = mkdtempSync(join(tmpdir(), "atdd-bun-fam-"));
29
+ const out = [];
30
+ for (const c of checks) {
31
+ const rep = join(td, c + ".json");
32
+ try {
33
+ execFileSync(process.execPath, [join(here, "checks", c)], {
34
+ env: { ...process.env, ATDD_VIOLATIONS_REPORT: rep },
35
+ stdio: ["ignore", "ignore", "inherit"],
36
+ });
37
+ } catch {
38
+ /* a member may exit non-zero; still try to read its report */
39
+ }
40
+ try {
41
+ out.push(...JSON.parse(readFileSync(rep, "utf8")).violations);
42
+ } catch {}
43
+ }
44
+ writeFileSync(reportPath, JSON.stringify({ violations: out }, null, 2), "utf8");
45
+ process.stderr.write("family htmx_e2e_detector: " + out.length + " violation(s)\n");
46
+ process.exit(0);
@@ -0,0 +1,12 @@
1
+ import { AxeBuilder as Axe } from "@axe-core/playwright";
2
+ import { expect, test } from "@playwright/test";
3
+
4
+ // Journey: journey:buy
5
+ // Layer: assembly
6
+ // URN: test:journey:buy:A11Y-002-renamed-import
7
+
8
+ test("test:journey:buy:A11Y-002-renamed-import", async ({ page }) => {
9
+ await page.goto("/");
10
+ const results = await new Axe({ page }).analyze();
11
+ expect(results.violations).toHaveLength(0);
12
+ });
@@ -0,0 +1,11 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:RESP-002-inline-widths
6
+
7
+ for (const width of [375, 768, 1280]) test(`test:journey:buy:RESP-002-inline-widths @ ${width}px`, async ({ page }) => {
8
+ await page.setViewportSize({ width, height: 900 });
9
+ await page.goto("/");
10
+ expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width);
11
+ });
@@ -0,0 +1,12 @@
1
+ import AxeBuilder from "@axe-core/playwright";
2
+ import { expect, test } from "@playwright/test";
3
+
4
+ // Journey: journey:buy
5
+ // Layer: assembly
6
+ // URN: test:journey:buy:A11Y-001-no-serious-violations
7
+
8
+ test("test:journey:buy:A11Y-001-no-serious-violations", async ({ page }) => {
9
+ await page.goto("/");
10
+ const results = await new AxeBuilder({ page }).analyze();
11
+ expect(results.violations.filter((v) => v.impact === "critical")).toEqual([]);
12
+ });
@@ -0,0 +1,14 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:RESP-001-fits-every-viewport
6
+
7
+ const VIEWPORTS = [375, 768, 1280];
8
+
9
+ for (const width of VIEWPORTS) test(`test:journey:buy:RESP-001-fits-every-viewport @ ${width}px`, async ({ page }) => {
10
+ await page.setViewportSize({ width, height: 900 });
11
+ await page.goto("/");
12
+ const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
13
+ expect(overflow).toBeLessThanOrEqual(0);
14
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:VIS-001-checkout-page
6
+
7
+ test("test:journey:buy:VIS-001-checkout-page", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page).toHaveScreenshot("checkout.png");
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:SMOKE-001-checkout-renders
6
+
7
+ test("test:journey:buy:SMOKE-001-checkout-renders", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:place-order
4
+ // Layer: assembly
5
+ // URN: test:train:orders:place-order:E2E-002-crlf
6
+
7
+ test("test:train:orders:place-order:E2E-002-crlf", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:place-order
4
+ // Layer: assembly
5
+ // URN: test:train:orders:place-order:E2E-001-place-order
6
+
7
+ test("test:train:orders:place-order:E2E-001-place-order", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:reject-empty-cart
4
+ // Layer: assembly
5
+ // URN: test:train:orders:reject-empty-cart:E2E-001-reject-empty-cart
6
+
7
+ test("test:train:orders:reject-empty-cart:E2E-001-reject-empty-cart", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,3 @@
1
+ import { test as base } from "@playwright/test";
2
+
3
+ export const test = base.extend<{ user: string }>({ user: async ({}, use) => use("buyer") });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:take-payment
4
+ // Layer: assembly
5
+ // URN: test:train:orders:take-payment:E2E-001-take-payment
6
+
7
+ test("test:train:orders:take-payment:E2E-001-take-payment", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,19 @@
1
+ schema_version: 1.0.0
2
+ journey_id: journey:buy
3
+ title: Buy a product
4
+ status: checked
5
+ entrypoint:
6
+ interlocking_id: interlocking:checkout
7
+ exposed: true
8
+ actions: [place-order]
9
+ reason: null
10
+ surfaces: [frontend]
11
+ continuations:
12
+ - from: { interlocking_id: interlocking:checkout, route_id: nominal }
13
+ artifact: orders:cart
14
+ to: { interlocking_id: interlocking:payment }
15
+ terminals:
16
+ - from: { interlocking_id: interlocking:checkout, route_id: empty-cart }
17
+ outcome: rejected
18
+ - from: { interlocking_id: interlocking:payment, route_id: charged }
19
+ outcome: paid
@@ -0,0 +1,14 @@
1
+ schema_version: 1.0.0
2
+ journey_id: journey:settle
3
+ title: Settle the day
4
+ status: checked
5
+ entrypoint:
6
+ interlocking_id: interlocking:settlement
7
+ exposed: true
8
+ actions: [settle]
9
+ reason: null
10
+ surfaces: [backend]
11
+ continuations: []
12
+ terminals:
13
+ - from: { interlocking_id: interlocking:settlement, route_id: nominal }
14
+ outcome: settled
@@ -0,0 +1,21 @@
1
+ schema_version: 1.0.0
2
+ interlocking_id: interlocking:checkout
3
+ title: checkout
4
+ theme: orders
5
+ status: checked
6
+ entrypoint:
7
+ exposed: true
8
+ actions: [place-order]
9
+ reason: null
10
+ surfaces: [frontend]
11
+ routes:
12
+ - route_id: nominal
13
+ category: nominal
14
+ priority: 1
15
+ guard_ref: guard:nominal
16
+ train_id: train:orders:place-order
17
+ - route_id: empty-cart
18
+ category: error
19
+ priority: 2
20
+ guard_ref: guard:empty-cart
21
+ train_id: train:orders:reject-empty-cart
@@ -0,0 +1,16 @@
1
+ schema_version: 1.0.0
2
+ interlocking_id: interlocking:payment
3
+ title: payment
4
+ theme: orders
5
+ status: checked
6
+ entrypoint:
7
+ exposed: false
8
+ actions: []
9
+ reason: internal-transition-only
10
+ surfaces: [backend]
11
+ routes:
12
+ - route_id: charged
13
+ category: nominal
14
+ priority: 1
15
+ guard_ref: guard:charged
16
+ train_id: train:orders:take-payment
@@ -0,0 +1,16 @@
1
+ schema_version: 1.0.0
2
+ interlocking_id: interlocking:settlement
3
+ title: settlement
4
+ theme: orders
5
+ status: checked
6
+ entrypoint:
7
+ exposed: true
8
+ actions: [settle]
9
+ reason: null
10
+ surfaces: [backend]
11
+ routes:
12
+ - route_id: nominal
13
+ category: nominal
14
+ priority: 1
15
+ guard_ref: guard:nominal
16
+ train_id: train:orders:settle-ledger
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:place-order
2
+ title: Place an order
3
+ description: Place an order.
4
+ themes: [orders]
5
+ participants: [user:buyer, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Submit the cart
9
+ from: user:buyer
10
+ to: wagon:checkout
11
+ artifact: orders:cart
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:reject-empty-cart
2
+ title: Reject an empty cart
3
+ description: Reject an empty cart.
4
+ themes: [orders]
5
+ participants: [user:buyer, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Refuse the empty cart
9
+ from: user:buyer
10
+ to: wagon:checkout
11
+ artifact: orders:rejection
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:settle-ledger
2
+ title: Settle the ledger
3
+ description: A nightly settlement between systems; no person takes part.
4
+ themes: [orders]
5
+ participants: [wagon:checkout, system:ledger]
6
+ sequence:
7
+ - step: 1
8
+ intent: Post the day's payments to the ledger
9
+ from: wagon:checkout
10
+ to: system:ledger
11
+ artifact: orders:settlement
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:take-payment
2
+ title: Take payment
3
+ description: Take payment.
4
+ themes: [orders]
5
+ participants: [system:gateway, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Charge the card
9
+ from: wagon:checkout
10
+ to: system:gateway
11
+ artifact: orders:paid
@@ -0,0 +1,3 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({ testDir: "e2e", testMatch: "**/*.e2e.ts" });
@@ -0,0 +1,3 @@
1
+ export function Cart() {
2
+ return <section class="cart">Cart</section>;
3
+ }
@@ -0,0 +1,7 @@
1
+ import { expect, test } from "bun:test";
2
+
3
+ // URN: test:checkout:cart:E001-UNIT-001
4
+
5
+ test("parses a journey test URN", () => {
6
+ expect("test:train:orders:place-order:E2E-001-a".split(":").length).toBe(6);
7
+ });
@@ -0,0 +1,6 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
5
+ // Acceptance: acc:checkout:E001-UNIT-001
6
+ // URN: test:train:orders:covered:E2E-009-acceptance
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:0001-legacy
4
+ // Layer: assembly
5
+ // URN: test:train:orders:covered:E2E-004-bad-id
6
+
7
+ test("test:train:orders:covered:E2E-004-bad-id", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
5
+ // URN: test:train:orders:covered:E2E-1-too-short
6
+
7
+ test("test:train:orders:covered:E2E-1-too-short", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,6 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Journey: journey:buy
5
+ // Layer: assembly
6
+ // URN: test:train:orders:covered:E2E-005-both
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:A11Y-001-looks-but-never-runs-axe
6
+
7
+ test("test:journey:buy:A11Y-001-looks-but-never-runs-axe", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,11 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:RESP-001-only-desktop
6
+
7
+ test("test:journey:buy:RESP-001-only-desktop", async ({ page }) => {
8
+ await page.setViewportSize({ width: 1280, height: 900 });
9
+ await page.goto("/");
10
+ await expect(page.locator("main")).toBeVisible();
11
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:VIS-001-no-screenshot
6
+
7
+ test("test:journey:buy:VIS-001-no-screenshot", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
5
+ // URN: test:train:orders:covered:E2E-001-covered
6
+
7
+ test("test:train:orders:covered:E2E-001-covered", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,13 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Journey: journey:buy
4
+ // Layer: assembly
5
+ // URN: test:journey:buy:RESP-002-first-only
6
+
7
+ const VIEWPORTS = [375, 768, 1280];
8
+
9
+ test("test:journey:buy:RESP-002-first-only", async ({ page }) => {
10
+ await page.setViewportSize({ width: VIEWPORTS[0], height: 900 });
11
+ const measured = await page.evaluate(() => document.documentElement.scrollWidth);
12
+ expect(true).toBe(true);
13
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:ghost
4
+ // Layer: assembly
5
+ // URN: test:train:orders:ghost:E2E-010-ghost
6
+
7
+ test("test:train:orders:ghost:E2E-010-ghost", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
5
+ // URN: test:train:orders:covered:E2E-002-misnamed
6
+
7
+ test("test:train:orders:covered:E2E-002-misnamed", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,4 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Layer: assembly
4
+ // URN: test:train:orders:covered:E2E-003-no-binding
@@ -0,0 +1,4 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // URN: test:train:orders:covered:E2E-007-no-layer
@@ -0,0 +1,4 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
@@ -0,0 +1,11 @@
1
+ import AxeBuilder from "@axe-core/playwright";
2
+ import { expect, test } from "@playwright/test";
3
+
4
+ // Journey: journey:buy
5
+ // Layer: assembly
6
+ // URN: test:journey:buy:A11Y-002-tautology
7
+
8
+ test("test:journey:buy:A11Y-002-tautology", async ({ page }) => {
9
+ const results = await new AxeBuilder({ page }).analyze();
10
+ expect(results.violations.length).toBeGreaterThanOrEqual(0);
11
+ });
@@ -0,0 +1,6 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Train: train:orders:uncovered
5
+ // Layer: assembly
6
+ // URN: test:train:orders:covered:E2E-011-two-trains
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:unrouted
4
+ // Layer: assembly
5
+ // URN: test:train:orders:unrouted:E2E-001-unrouted
6
+
7
+ test("test:train:orders:unrouted:E2E-001-unrouted", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,5 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: presentation
5
+ // URN: test:train:orders:covered:E2E-008-wrong-layer
@@ -0,0 +1,10 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ // Train: train:orders:covered
4
+ // Layer: assembly
5
+ // URN: test:train:orders:uncovered:E2E-006-wrong-subject
6
+
7
+ test("test:train:orders:uncovered:E2E-006-wrong-subject", async ({ page }) => {
8
+ await page.goto("/");
9
+ await expect(page.locator("main")).toBeVisible();
10
+ });
@@ -0,0 +1,16 @@
1
+ schema_version: 1.0.0
2
+ journey_id: journey:browse
3
+ title: Browse
4
+ status: checked
5
+ entrypoint:
6
+ interlocking_id: interlocking:checkout
7
+ exposed: true
8
+ actions: [buy]
9
+ reason: null
10
+ surfaces: [frontend]
11
+ continuations: []
12
+ terminals:
13
+ - from: { interlocking_id: interlocking:checkout, route_id: nominal }
14
+ outcome: done
15
+ - from: { interlocking_id: interlocking:checkout, route_id: other }
16
+ outcome: other
@@ -0,0 +1,16 @@
1
+ schema_version: 1.0.0
2
+ journey_id: journey:buy
3
+ title: Buy
4
+ status: checked
5
+ entrypoint:
6
+ interlocking_id: interlocking:checkout
7
+ exposed: true
8
+ actions: [buy]
9
+ reason: null
10
+ surfaces: [frontend]
11
+ continuations: []
12
+ terminals:
13
+ - from: { interlocking_id: interlocking:checkout, route_id: nominal }
14
+ outcome: done
15
+ - from: { interlocking_id: interlocking:checkout, route_id: other }
16
+ outcome: other
@@ -0,0 +1,21 @@
1
+ schema_version: 1.0.0
2
+ interlocking_id: interlocking:checkout
3
+ title: checkout
4
+ theme: orders
5
+ status: checked
6
+ entrypoint:
7
+ exposed: true
8
+ actions: [buy]
9
+ reason: null
10
+ surfaces: [frontend]
11
+ routes:
12
+ - route_id: nominal
13
+ category: nominal
14
+ priority: 1
15
+ guard_ref: guard:nominal
16
+ train_id: train:orders:covered
17
+ - route_id: other
18
+ category: alternate
19
+ priority: 2
20
+ guard_ref: guard:other
21
+ train_id: train:orders:uncovered
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:covered
2
+ title: covered
3
+ description: covered.
4
+ themes: [orders]
5
+ participants: [user:buyer, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Do covered
9
+ from: user:buyer
10
+ to: wagon:checkout
11
+ artifact: orders:covered
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:uncovered
2
+ title: uncovered
3
+ description: uncovered.
4
+ themes: [orders]
5
+ participants: [user:buyer, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Do uncovered
9
+ from: user:buyer
10
+ to: wagon:checkout
11
+ artifact: orders:uncovered
@@ -0,0 +1,11 @@
1
+ train_id: train:orders:unrouted
2
+ title: unrouted
3
+ description: unrouted.
4
+ themes: [orders]
5
+ participants: [user:buyer, wagon:checkout]
6
+ sequence:
7
+ - step: 1
8
+ intent: Do unrouted
9
+ from: user:buyer
10
+ to: wagon:checkout
11
+ artifact: orders:unrouted
@@ -0,0 +1,3 @@
1
+ export function Invoice() {
2
+ return <section>Invoice</section>;
3
+ }