@sun-asterisk/sungen 3.2.19 → 3.2.20-beta.1

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 (79) hide show
  1. package/dist/cli/commands/generate.d.ts.map +1 -1
  2. package/dist/cli/commands/generate.js +6 -0
  3. package/dist/cli/commands/generate.js.map +1 -1
  4. package/dist/exporters/matrix/build.d.ts.map +1 -1
  5. package/dist/exporters/matrix/build.js +9 -1
  6. package/dist/exporters/matrix/build.js.map +1 -1
  7. package/dist/exporters/test-data-resolver.d.ts +15 -0
  8. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  9. package/dist/exporters/test-data-resolver.js +34 -1
  10. package/dist/exporters/test-data-resolver.js.map +1 -1
  11. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +1 -0
  12. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  13. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +1 -0
  14. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
  15. package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
  16. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +1 -0
  17. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  18. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  19. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  20. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +4 -0
  21. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +11 -6
  22. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  23. package/dist/generators/test-generator/code-generator.js +9 -1
  24. package/dist/generators/test-generator/code-generator.js.map +1 -1
  25. package/dist/generators/test-generator/diagnostics.d.ts +10 -1
  26. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  27. package/dist/generators/test-generator/diagnostics.js +9 -0
  28. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  29. package/dist/generators/test-generator/step-mapper.d.ts +24 -0
  30. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  31. package/dist/generators/test-generator/step-mapper.js +53 -0
  32. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  33. package/dist/generators/test-generator/template-engine.d.ts +1 -0
  34. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  35. package/dist/generators/test-generator/template-engine.js +1 -1
  36. package/dist/generators/test-generator/template-engine.js.map +1 -1
  37. package/dist/generators/test-generator/utils/data-resolver.d.ts +11 -0
  38. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  39. package/dist/generators/test-generator/utils/data-resolver.js +20 -0
  40. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  41. package/dist/harness/script-check.d.ts.map +1 -1
  42. package/dist/harness/script-check.js +9 -1
  43. package/dist/harness/script-check.js.map +1 -1
  44. package/dist/harness/secret-scan.d.ts.map +1 -1
  45. package/dist/harness/secret-scan.js +13 -1
  46. package/dist/harness/secret-scan.js.map +1 -1
  47. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +6 -0
  48. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -0
  49. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +33 -5
  50. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -1
  51. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +6 -3
  52. package/dist/orchestrator/templates/specs-url-assert.d.ts +67 -0
  53. package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -0
  54. package/dist/orchestrator/templates/specs-url-assert.js +121 -0
  55. package/dist/orchestrator/templates/specs-url-assert.js.map +1 -0
  56. package/dist/orchestrator/templates/specs-url-assert.ts +134 -0
  57. package/package.json +3 -3
  58. package/src/cli/commands/generate.ts +5 -0
  59. package/src/exporters/matrix/build.ts +9 -1
  60. package/src/exporters/test-data-resolver.ts +34 -1
  61. package/src/generators/test-generator/adapters/adapter-interface.ts +1 -1
  62. package/src/generators/test-generator/adapters/appium/appium-adapter.ts +1 -1
  63. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +1 -1
  64. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  65. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +4 -0
  66. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +11 -6
  67. package/src/generators/test-generator/code-generator.ts +10 -2
  68. package/src/generators/test-generator/diagnostics.ts +10 -1
  69. package/src/generators/test-generator/step-mapper.ts +54 -0
  70. package/src/generators/test-generator/template-engine.ts +2 -2
  71. package/src/generators/test-generator/utils/data-resolver.ts +19 -0
  72. package/src/harness/script-check.ts +9 -1
  73. package/src/harness/secret-scan.ts +12 -1
  74. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +6 -0
  75. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -0
  76. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +33 -5
  77. package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -1
  78. package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +6 -3
  79. package/src/orchestrator/templates/specs-url-assert.ts +134 -0
@@ -1 +1 @@
1
- {"version":3,"file":"script-check.js","sourceRoot":"","sources":["../../src/harness/script-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"script-check.js","sourceRoot":"","sources":["../../src/harness/script-check.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"secret-scan.d.ts","sourceRoot":"","sources":["../../src/harness/secret-scan.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AA4BzE;;sFAEsF;AACtF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAYhE"}
1
+ {"version":3,"file":"secret-scan.d.ts","sourceRoot":"","sources":["../../src/harness/secret-scan.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAuCzE;;sFAEsF;AACtF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAYhE"}
@@ -59,7 +59,19 @@ function scanText(text, file) {
59
59
  }
60
60
  const m = raw.match(SECRET_KEY);
61
61
  if (m) {
62
- const val = m[2].trim().replace(/^["']|["']$/g, '');
62
+ // Take only the FIRST scalar after the key. The old `(.+)$` capture swallowed
63
+ // the rest of the line, so in an inline-map @cases row
64
+ // - { …, password: "${QA_X}", expected_status: 201 }
65
+ // the "value" included `, expected_status: 201 }` — whose digits + length
66
+ // pushed EVERY such row over the threshold regardless of the actual value
67
+ // (field report: ${QA_*} refs and a deliberate wrong_password all warned).
68
+ const tail = m[2].trim();
69
+ const quoted = tail.match(/^(["'])((?:\\.|(?!\1).)*)\1/);
70
+ const val = (quoted ? quoted[2] : tail.split(/[,}\s]/, 1)[0]).trim();
71
+ // A ${VAR} env ref IS the recommended practice (.env.qa overlays) — never
72
+ // warn on it, or the gate teaches users the opposite of the convention.
73
+ if (/^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(val))
74
+ return;
63
75
  // Long, high-entropy-ish, not an obvious placeholder/test value.
64
76
  if (val.length >= 20 && !PLACEHOLDERish.test(raw) && /[A-Za-z]/.test(val) && /[0-9]/.test(val)) {
65
77
  hits.push({ file, line, reason: `secret-named key "${m[1]}" with a long literal value` });
@@ -1 +1 @@
1
- {"version":3,"file":"secret-scan.js","sourceRoot":"","sources":["../../src/harness/secret-scan.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,kDAYC;AAtDD;;;;;;;GAOG;AACH,uCAAyB;AACzB,2CAA6B;AAI7B,wEAAwE;AACxE,MAAM,eAAe,GAAG,0LAA0L,CAAC;AACnN,6DAA6D;AAC7D,MAAM,UAAU,GAAG,8GAA8G,CAAC;AAClI,MAAM,cAAc,GAAG,kEAAkE,CAAC;AAE1F,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY;IAC1C,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC5E,OAAO;QACT,CAAC;QACD,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YACpD,iEAAiE;YACjE,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/F,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,6BAA6B,EAAE,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;sFAEsF;AACtF,SAAgB,mBAAmB,CAAC,OAAe;IACjD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,SAAS;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"secret-scan.js","sourceRoot":"","sources":["../../src/harness/secret-scan.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,kDAYC;AAjED;;;;;;;GAOG;AACH,uCAAyB;AACzB,2CAA6B;AAI7B,wEAAwE;AACxE,MAAM,eAAe,GAAG,0LAA0L,CAAC;AACnN,6DAA6D;AAC7D,MAAM,UAAU,GAAG,8GAA8G,CAAC;AAClI,MAAM,cAAc,GAAG,kEAAkE,CAAC;AAE1F,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY;IAC1C,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC5E,OAAO;QACT,CAAC;QACD,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC;YACN,8EAA8E;YAC9E,uDAAuD;YACvD,uDAAuD;YACvD,0EAA0E;YAC1E,0EAA0E;YAC1E,2EAA2E;YAC3E,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACzD,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrE,0EAA0E;YAC1E,wEAAwE;YACxE,IAAI,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,OAAO;YACvD,iEAAiE;YACjE,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/F,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,6BAA6B,EAAE,CAAC,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;sFAEsF;AACtF,SAAgB,mBAAmB,CAAC,OAAe;IACjD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,SAAS;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -99,6 +99,12 @@ scheme (`SEC-123`, `PER-345`, `MS-HP-001`) is addressed the same way, and the ca
99
99
  exist in test-data, so Gate D does not ask for them: the capture step renders as an instruction
100
100
  (`Note the X text for later (as "v")`) and later references read `the captured v`.
101
101
 
102
+ **Dynamic vars**: `{{$timestamp}}`, `{{$uuid}}`, `{{$random:min:max}}`, `{{$date}}`, `{{$datetime}}`
103
+ are resolved by TestDataLoader at execution time — including when nested inside a test-data value
104
+ (`seed: "Summary intro {{$timestamp}}"`). They have no static value to print, so the report names
105
+ them instead: `<unique timestamp>`, `<unique id>`, `<random 1-100>`, `<today's date>`,
106
+ `<current date-time>`. An unknown `{{$foo}}` is left raw on purpose — it is a typo and Gate D says so.
107
+
102
108
  **Data fidelity**: invisible test data is made visible, never normalized — `''` → `(empty)`,
103
109
  whitespace-only → `(5 spaces)`, padded → `" value "` quoted verbatim. A trim/collapse here would
104
110
  silently break the whitespace tests it describes.
@@ -95,6 +95,10 @@ needs any of these, it is a **finding for QA** — surface it in the run summary
95
95
  | `SG-W008` | `@manual` scenario incomplete in either direction: (a) HAS Gherkin steps but NO `Then` — a dangling `When` is invalid Gherkin, comments can NOT substitute; (b) documentation-style (NO steps) but its comments lack numbered action lines and/or a labeled oracle line — prose paragraphs / rationale-only comments export EMPTY Steps + Expected cells | Two valid shapes only: complete the Gherkin with a `Then`, or write the FULL procedure in the `# Tester verifies:` block as NUMBERED lines — action steps first (`1. <action>`), then labeled `Observable:`/`Oracle:`/`Expected:` lines (the number is what fills Steps, the label is what fills Expected results) |
96
96
  | `SG-W009` | test-data references `${QA_<NAME>}` (a SECRET env ref) but the name is declared in neither `.env.qa` nor `.env.qa.example` — the test throws "environment variable not set" the moment the key is used. (Only the `${QA_*}` shape is checked; any other `${...}` is literal data and never flagged.) | Add `QA_<NAME>=<value>` to `.env.qa` (gitignored) and list the NAME in `.env.qa.example` (the committed checklist). See `qa/TEST-DATA-GUIDE.md` |
97
97
  | `SG-W010` | A row step's `[Ref]` looks POSITIONAL (`First…`/`Last…`/`Top…`/`nth`) but has no selectors.yaml entry — the label is display-only, so the step checks existence ANYWHERE in the table; an ordering/sort-stability rule would pass even when the row moved | Declare the row in selectors.yaml (a `type: locator` value RELATIVE to the table, e.g. `first contact row:` → `value: 'tbody tr:first-child'`) — the step then asserts `toContainText` on that exact row. This is a selectors.yaml-only fix — allowed inside the run-test auto-fix loop |
98
+ | `SG-W011` | A storage assertion written as `expect … in local/session storage` — `expect` steps only read `{{response}}` refs, so this compiles to a silent no-op | Rewrite using the supported grammar: `User see [KEY] in local storage exists/…` |
99
+ | `SG-W012` | A mock-install step written AFTER a navigation step in the same block — `page.route()` registered after `goto()` misses every request fired during page load | Move the mock-install step before the navigation, or into `Background` |
100
+ | `SG-W013` | A page assertion (`see [X] page` / `is on [X] page`) whose `[Ref]` has no `type: page` selector entry (or collides with a non-page entry) — the step falls back to the feature's own path (or `/<ref>/`) instead of `X`'s real URL, so the anchored assertion can never pass | Declare a `type: page` entry for `[Ref]` with its real URL; if the key collides with another type, disambiguate with a `--type` suffix (`sungen-selector-keys` § Collision rule) |
101
+ | `SG-W014` | `[X] page with {{v}}` where `{{v}}`'s base test-data value carries no query and no fragment — the step checks the PATH only, asserting less than it reads as | Informational — pass a value like `?q=…` if you meant to assert a query, or drop `with {{v}}` for a bare page |
98
102
 
99
103
  ### Runtime error → `Test data "<key>" references ${QA_*} but the environment variable is not set`
100
104
 
@@ -106,11 +106,39 @@ two content-filtered queries can hit different rows if the table re-renders in b
106
106
  # 8. Page: User see [T] page | page with {{url}} ← `with` also asserts the query string
107
107
  ```
108
108
 
109
- **Pattern 8 — assert the query, not just the path.** Bare `see [T] page` only checks the base path,
110
- so a search/filter test PASSES when the query string is wrong or gone entirely. When the URL carries
111
- state worth proving, pass it: `Then User see [Search] page with {{search_query}}` compiles to the
112
- path assertion PLUS `expect(page.url()).toContain(<value>)`. Same for `Then User is on [T] page with
113
- {{v}}`. A dynamic segment in the selector value (`/users/:id/profile`) wildcards to `[^/]+` on its own.
109
+ **Pattern 8 — the page assertion judges pathname AND query together.** Both `see [T] page` and
110
+ `is on [T] page` (Then-side) compile to ONE web-first predicate `toHaveURL(urlMatches({…}))`,
111
+ which retries like any other assertion comparing the **exact** pathname (anchored, trailing slash
112
+ normalised) plus the query:
113
+
114
+ | step | asserts |
115
+ |---|---|
116
+ | `Then User see [Search] page` | pathname `/vi/search` **and no query at all** — `/vi/search?x=1` FAILS |
117
+ | `… page with {{v}}`, `v` = `?q=abc` | pathname + **every declared param must match**; extra params are tolerated (a UTM/tracking param cannot turn the test red); a repeated param (`?tag=a&tag=b`) matches per value, so param ORDER never matters |
118
+ | `… page with {{v}}`, `v` = `?q=abc#tab` | the fragment is asserted too |
119
+ | `… page with {{v}}`, `v` = `/vi/search?q=abc` | only the query part is used — the page selector already owns the path |
120
+ | `… page with {{v}}`, `v` = `/vi/search` (no query) | **path only**, and the compiler warns (`SG-W014`): the step asserts less than it reads as |
121
+ | `… page with {{v}}`, `v` empty or key missing at run time | **throws, naming the key** — an unusable value is never a silent pass |
122
+
123
+ So pass `with {{v}}` whenever the URL carries state worth proving, and leave it off when the page
124
+ must be reached clean. A dynamic segment in the selector value (`/users/:id/profile`) wildcards to
125
+ `[^/]+` on its own, still anchored — `/users/42/profile/edit` does not match. Params compare
126
+ decoded on both sides, so a deliberately malformed query still asserts what was written.
127
+
128
+ Two asymmetries worth knowing rather than discovering:
129
+
130
+ 1. **`Given`/`When` navigate, `Then` asserts** — so they read `{{v}}` differently. `Then` uses only
131
+ its query/fragment; `Given User is on [T] page with {{v}}` also honours a path the value carries
132
+ (`/vi/other?q=1` navigates to `/vi/other?q=1`, and a value repeating the page's own path no
133
+ longer doubles it). Anything that is not a path, query, or fragment is appended **verbatim** —
134
+ nothing is encoded or normalised, so a test can still drive a deliberately malformed query.
135
+ 2. **A repeated param matches as a subset per key**, which is the same rule as "extra params are
136
+ tolerated": every value you declare must be present, and the URL may carry more.
137
+
138
+ The predicate itself lives in `specs/url-assert.ts` (auto-generated, `DO NOT EDIT`). If `[T]` has no
139
+ `type: page` selector entry — or its key collides with a non-page entry, so `value` is something like
140
+ `button` rather than a URL — the step falls back to another path and cannot match the real URL. The
141
+ compiler warns (`SG-W013`); declare the page (or rename the colliding key) instead of chasing the red.
114
142
 
115
143
  ### Collection / all-card (P5)
116
144
 
@@ -97,7 +97,7 @@ When running Phase 0 for a **flow** (`qa/flows/<name>/`), check existing screen
97
97
  - Loading indicator for `wait for [T] table to refresh` → `feedback.loading.indicator` (skip if the app sets `aria-busy`).
98
98
  - **Every qa/app.yaml edit MUST carry provenance** in `detection:`: who/when (`detected_by`) and the observed evidence per key (`evidence:`). A profile without evidence is a guess a human cannot review.
99
99
  8. **Merge, don't overwrite**: preserve the page selector and any user-authored entries in `selectors.yaml`. Only add missing keys.
100
- - **Type-collision check** (see `sungen-selector-keys` § Collision rule): before writing a base key, check whether it already exists with a *different* `type`. If so, give **both** entries a `--type` suffix instead of clobbering or sharing the base key — a base-key entry of the wrong type gets picked up by any step referencing that label. Watch `page` especially: a `[X] page` step reads `value` as a URL, so if `X` already holds a button (`value: 'button'`) the assertion compiles to `toHaveURL(/button/)`. Write `X--page` (URL from the live page / feature `Path:`) alongside `X--button`.
100
+ - **Type-collision check** (see `sungen-selector-keys` § Collision rule): before writing a base key, check whether it already exists with a *different* `type`. If so, give **both** entries a `--type` suffix instead of clobbering or sharing the base key — a base-key entry of the wrong type gets picked up by any step referencing that label. Watch `page` especially: a `[X] page` step reads `value` as a URL, so if `X` already holds a button (`value: 'button'`) the compiler won't use the button's value as a URL, but it can't invent the real one either — it falls back to the feature's own path and warns `SG-W013`, asserting a page that isn't `X`'s. Write `X--page` (URL from the live page / feature `Path:`) alongside `X--button`.
101
101
  9. **Show summary + confirm**: list the keys that will be added, ask the user to approve, then write the file.
102
102
  10. **Compile**: **Screen**: `sungen generate --screen <screen>`. **Flow**: `sungen generate --flow <flow>`. Then proceed to Phase 1.
103
103
 
@@ -97,12 +97,15 @@ its own `--type` suffix. A key match alone does not carry type: the resolver wal
97
97
  picked up by any step referencing that label, regardless of the type the step expects.
98
98
 
99
99
  The `page` type is the sharpest trap. A page step (`Then User see [X] page`) reads the entry's
100
- `value` as a **URL**. If key `X` already holds a `role`/button entry, the page step resolves that
101
- button and emits `toHaveURL(/button/)` — a literal button label treated as a URL path.
100
+ `value` as a **URL**. If key `X` already holds a `role`/button entry, the compiler guards the type
101
+ it does NOT emit `toHaveURL(/button/)` — but it can't invent the real URL either, so it falls
102
+ back to the feature's own path (or `/<ref>/`) and warns `SG-W013`: a test that reads as asserting
103
+ `X`'s page but never can, since the fallback path is anchored and almost certainly wrong.
102
104
 
103
105
  ```yaml
104
106
  # Gherkin: `When User click [読取結果一覧] button` AND `Then User see [読取結果一覧] page`
105
- # WRONG — one base key, page step inherits the button's value ('button') as a URL:
107
+ # WRONG — one base key: the page step can't use the button's value, falls back to the feature path
108
+ # instead, and the compiler warns SG-W013 rather than asserting the real page:
106
109
  読取結果一覧:
107
110
  type: 'role'
108
111
  value: 'button'
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Sungen URL assertion helper — auto-generated into specs/url-assert.ts. DO NOT EDIT.
3
+ *
4
+ * Every Then-side URL assertion (`see [X] page`, `is on [X] page`) compiles to one call here.
5
+ *
6
+ * Why a helper and not an inline predicate. The predicate used to be emitted inline into every
7
+ * spec, so each correction to what "the URL matches" MEANS was a breaking change for every
8
+ * generated suite in the field: regenerate everything, re-review every newly-red test. Behind a
9
+ * helper the same correction ships as a runtime patch. The generator's job shrinks to what it
10
+ * alone knows — the pathname pattern — and the semantics live in one readable place.
11
+ *
12
+ * Why a predicate and not two assertions. The shape before this one was
13
+ * await expect(page).toHaveURL(/\/vi\/search/); // unanchored: passes on /vi/search-x
14
+ * expect(page.url()).toContain('<query>'); // synchronous, one-shot: never retries
15
+ * — two half-checks, neither anchored, and nothing ever compared pathname and query together.
16
+ * `toHaveURL(predicate)` is web-first (it retries like any other assertion), receives a parsed
17
+ * URL, and needs no regex escaping of runtime values, which is what forced the split.
18
+ */
19
+ export interface UrlExpectation {
20
+ /**
21
+ * Anchored pathname pattern, compiled by the generator from the page selector's `value`
22
+ * (`:id` segments already wildcarded). Anchored against `u.pathname` ONLY: pathname never
23
+ * carries the query, so `^…$` is exact there — the same source that was unsafe to anchor
24
+ * against a full URL.
25
+ */
26
+ pathname: RegExp;
27
+ /**
28
+ * The `with {{v}}` value, raw from test-data: '?q=1' · '/vi/search?q=1' · '#tab' · ''.
29
+ * `undefined` means the step declared nothing, which is itself an assertion — see below.
30
+ */
31
+ declared?: string;
32
+ /** The test-data key behind `declared`, so a failure can name what an author must go fix. */
33
+ dataRef?: string;
34
+ }
35
+ /**
36
+ * Join a page's URL with the `with {{v}}` value for a NAVIGATION step
37
+ * (`Given User is on [X] page with {{v}}`).
38
+ *
39
+ * Why this is not a plain `base + path + value`. It used to be, and an author writing the value as a
40
+ * whole relative URL — the habit the assertion side already had to accommodate — navigated to
41
+ * `/vi/search/vi/search?q=1`: the page's own path, twice. The Then side then asserted the real path
42
+ * correctly, so the scenario could never go green.
43
+ *
44
+ * `base` (the configured baseURL, possibly '') and `path` (the page selector's value) arrive
45
+ * SEPARATELY so a value that carries its own rooted path replaces the page's path without also
46
+ * discarding a path prefix baked into the baseURL — a deployment under `https://host/tenant-a`
47
+ * would otherwise navigate to the wrong tenant, and only when a `with {{v}}` was present, which is
48
+ * exactly the kind of inconsistency nobody would think to look for.
49
+ *
50
+ * What it deliberately does NOT do is sanitize. A test may legitimately drive a MALFORMED query to
51
+ * prove the app rejects it (issue #464), so anything that is not a duplicated path is appended
52
+ * verbatim: no encoding, no normalising, no reordering.
53
+ */
54
+ export declare function joinPath(base: string, path: string, declared?: string | null): string;
55
+ /**
56
+ * Build the predicate for `expect(page).toHaveURL(...)`.
57
+ *
58
+ * Query semantics are deliberately asymmetric:
59
+ * no `with {{v}}` → the URL must carry NO query. A bare page means a bare page, so
60
+ * `/vi/search` does not pass on `/vi/search?x=1`.
61
+ * `with {{v}}` → every declared param must match; extra params are tolerated, so a
62
+ * tracking/UTM param the test never cared about cannot turn it red.
63
+ * A declared fragment is asserted too; a declared value carrying no query
64
+ * at all constrains the path only (the compiler warns: SG-W014).
65
+ */
66
+ export declare function urlMatches({ pathname, declared, dataRef }: UrlExpectation): (u: URL) => boolean;
67
+ //# sourceMappingURL=specs-url-assert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specs-url-assert.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/templates/specs-url-assert.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAYrF;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,cAAc,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,CAuC/F"}
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /* eslint-disable */
3
+ /**
4
+ * Sungen URL assertion helper — auto-generated into specs/url-assert.ts. DO NOT EDIT.
5
+ *
6
+ * Every Then-side URL assertion (`see [X] page`, `is on [X] page`) compiles to one call here.
7
+ *
8
+ * Why a helper and not an inline predicate. The predicate used to be emitted inline into every
9
+ * spec, so each correction to what "the URL matches" MEANS was a breaking change for every
10
+ * generated suite in the field: regenerate everything, re-review every newly-red test. Behind a
11
+ * helper the same correction ships as a runtime patch. The generator's job shrinks to what it
12
+ * alone knows — the pathname pattern — and the semantics live in one readable place.
13
+ *
14
+ * Why a predicate and not two assertions. The shape before this one was
15
+ * await expect(page).toHaveURL(/\/vi\/search/); // unanchored: passes on /vi/search-x
16
+ * expect(page.url()).toContain('<query>'); // synchronous, one-shot: never retries
17
+ * — two half-checks, neither anchored, and nothing ever compared pathname and query together.
18
+ * `toHaveURL(predicate)` is web-first (it retries like any other assertion), receives a parsed
19
+ * URL, and needs no regex escaping of runtime values, which is what forced the split.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.joinPath = joinPath;
23
+ exports.urlMatches = urlMatches;
24
+ /**
25
+ * Join a page's URL with the `with {{v}}` value for a NAVIGATION step
26
+ * (`Given User is on [X] page with {{v}}`).
27
+ *
28
+ * Why this is not a plain `base + path + value`. It used to be, and an author writing the value as a
29
+ * whole relative URL — the habit the assertion side already had to accommodate — navigated to
30
+ * `/vi/search/vi/search?q=1`: the page's own path, twice. The Then side then asserted the real path
31
+ * correctly, so the scenario could never go green.
32
+ *
33
+ * `base` (the configured baseURL, possibly '') and `path` (the page selector's value) arrive
34
+ * SEPARATELY so a value that carries its own rooted path replaces the page's path without also
35
+ * discarding a path prefix baked into the baseURL — a deployment under `https://host/tenant-a`
36
+ * would otherwise navigate to the wrong tenant, and only when a `with {{v}}` was present, which is
37
+ * exactly the kind of inconsistency nobody would think to look for.
38
+ *
39
+ * What it deliberately does NOT do is sanitize. A test may legitimately drive a MALFORMED query to
40
+ * prove the app rejects it (issue #464), so anything that is not a duplicated path is appended
41
+ * verbatim: no encoding, no normalising, no reordering.
42
+ */
43
+ function joinPath(base, path, declared) {
44
+ if (declared === undefined || declared === null || declared === '')
45
+ return base + path;
46
+ const value = String(declared);
47
+ // A query/fragment appends — the overwhelmingly common shape, and the only one #464 needs.
48
+ if (value.startsWith('?') || value.startsWith('#'))
49
+ return base + path + value;
50
+ // An absolute URL replaces everything: the author pasted a full address.
51
+ if (/^[a-z]+:\/\//i.test(value))
52
+ return value;
53
+ // A rooted path carries its own path, so it replaces the PAGE's path while everything the
54
+ // baseURL contributed — scheme, host, and any path prefix — is kept.
55
+ if (value.startsWith('/'))
56
+ return base + value;
57
+ // Anything else is raw input the test wants appended as-is.
58
+ return base + path + value;
59
+ }
60
+ /**
61
+ * `u.pathname` is percent-encoded; a regex built from a selector's literal `value` is not, so a
62
+ * non-ASCII route (`/読取結果一覧`) could never match. Decoding can throw on a lone `%`, in which
63
+ * case the raw form is all there is.
64
+ */
65
+ function decodedPath(pathname) {
66
+ try {
67
+ return decodeURIComponent(pathname);
68
+ }
69
+ catch {
70
+ return pathname;
71
+ }
72
+ }
73
+ /**
74
+ * Build the predicate for `expect(page).toHaveURL(...)`.
75
+ *
76
+ * Query semantics are deliberately asymmetric:
77
+ * no `with {{v}}` → the URL must carry NO query. A bare page means a bare page, so
78
+ * `/vi/search` does not pass on `/vi/search?x=1`.
79
+ * `with {{v}}` → every declared param must match; extra params are tolerated, so a
80
+ * tracking/UTM param the test never cared about cannot turn it red.
81
+ * A declared fragment is asserted too; a declared value carrying no query
82
+ * at all constrains the path only (the compiler warns: SG-W014).
83
+ */
84
+ function urlMatches({ pathname, declared, dataRef }) {
85
+ return (u) => {
86
+ if (!pathname.test(u.pathname) && !pathname.test(decodedPath(u.pathname)))
87
+ return false;
88
+ // `dataRef`, not `declared`, decides which rule applies. Both "the step declared nothing" and
89
+ // "the step declared {{v}} but the key resolved to nothing at runtime" arrive here as
90
+ // undefined, and they mean opposite things: the first is a real assertion (a bare page must be
91
+ // bare), the second is broken test-data. Only the generator knows which, and it says so by
92
+ // emitting `dataRef` exactly when the step carried a `with {{v}}`.
93
+ if (!dataRef)
94
+ return u.search === '';
95
+ // Silence is the whole bug class this assertion exists to kill, so an unusable declared value
96
+ // is an ERROR, not a quiet verdict. Returning false would read as "the app is wrong"; these
97
+ // throws say "your test-data is wrong, and here is the key". An empty value used to parse to
98
+ // an empty param list, and `[].every()` is vacuously TRUE — it passed on any query at all.
99
+ if (declared === undefined || declared === null) {
100
+ throw new Error(`url assertion: test-data key "${dataRef}" is missing — nothing to assert`);
101
+ }
102
+ if (String(declared).trim() === '') {
103
+ throw new Error(`url assertion: test-data key "${dataRef}" is empty — nothing to assert`);
104
+ }
105
+ // Parsing against the live pathname as base lets ONE expression handle every shape an author
106
+ // writes: '?q=1' (query only), '/vi/search?q=1' (a whole relative URL — its path is ignored,
107
+ // the page selector already owns the path), and '#tab' (fragment only). The predecessor
108
+ // regex-stripped the prefix instead, which silently turned a value with NO query
109
+ // ('/vi/search') into a bogus param NAME — an assertion that could never be satisfied.
110
+ const d = new URL(String(declared), 'http://sungen.invalid' + u.pathname);
111
+ // getAll, not get: a multi-select filter (?tag=a&tag=b) is the exact case this assertion is
112
+ // for, and `get()` returns only the first value — so the correct URL failed. Comparing as a
113
+ // subset per key keeps this consistent with "extra params are tolerated", and makes param
114
+ // order meaningless, which is what a URL actually means.
115
+ const queryOk = [...d.searchParams].every(([k, v]) => u.searchParams.getAll(k).includes(v));
116
+ // Only assert a fragment the author actually declared.
117
+ const hashOk = !d.hash || d.hash === u.hash;
118
+ return queryOk && hashOk;
119
+ };
120
+ }
121
+ //# sourceMappingURL=specs-url-assert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specs-url-assert.js","sourceRoot":"","sources":["../../../src/orchestrator/templates/specs-url-assert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Sungen URL assertion helper — auto-generated into specs/url-assert.ts. DO NOT EDIT.
4
+ *
5
+ * Every Then-side URL assertion (`see [X] page`, `is on [X] page`) compiles to one call here.
6
+ *
7
+ * Why a helper and not an inline predicate. The predicate used to be emitted inline into every
8
+ * spec, so each correction to what "the URL matches" MEANS was a breaking change for every
9
+ * generated suite in the field: regenerate everything, re-review every newly-red test. Behind a
10
+ * helper the same correction ships as a runtime patch. The generator's job shrinks to what it
11
+ * alone knows — the pathname pattern — and the semantics live in one readable place.
12
+ *
13
+ * Why a predicate and not two assertions. The shape before this one was
14
+ * await expect(page).toHaveURL(/\/vi\/search/); // unanchored: passes on /vi/search-x
15
+ * expect(page.url()).toContain('<query>'); // synchronous, one-shot: never retries
16
+ * — two half-checks, neither anchored, and nothing ever compared pathname and query together.
17
+ * `toHaveURL(predicate)` is web-first (it retries like any other assertion), receives a parsed
18
+ * URL, and needs no regex escaping of runtime values, which is what forced the split.
19
+ */
20
+
21
+ export interface UrlExpectation {
22
+ /**
23
+ * Anchored pathname pattern, compiled by the generator from the page selector's `value`
24
+ * (`:id` segments already wildcarded). Anchored against `u.pathname` ONLY: pathname never
25
+ * carries the query, so `^…$` is exact there — the same source that was unsafe to anchor
26
+ * against a full URL.
27
+ */
28
+ pathname: RegExp;
29
+ /**
30
+ * The `with {{v}}` value, raw from test-data: '?q=1' · '/vi/search?q=1' · '#tab' · ''.
31
+ * `undefined` means the step declared nothing, which is itself an assertion — see below.
32
+ */
33
+ declared?: string;
34
+ /** The test-data key behind `declared`, so a failure can name what an author must go fix. */
35
+ dataRef?: string;
36
+ }
37
+
38
+ /**
39
+ * Join a page's URL with the `with {{v}}` value for a NAVIGATION step
40
+ * (`Given User is on [X] page with {{v}}`).
41
+ *
42
+ * Why this is not a plain `base + path + value`. It used to be, and an author writing the value as a
43
+ * whole relative URL — the habit the assertion side already had to accommodate — navigated to
44
+ * `/vi/search/vi/search?q=1`: the page's own path, twice. The Then side then asserted the real path
45
+ * correctly, so the scenario could never go green.
46
+ *
47
+ * `base` (the configured baseURL, possibly '') and `path` (the page selector's value) arrive
48
+ * SEPARATELY so a value that carries its own rooted path replaces the page's path without also
49
+ * discarding a path prefix baked into the baseURL — a deployment under `https://host/tenant-a`
50
+ * would otherwise navigate to the wrong tenant, and only when a `with {{v}}` was present, which is
51
+ * exactly the kind of inconsistency nobody would think to look for.
52
+ *
53
+ * What it deliberately does NOT do is sanitize. A test may legitimately drive a MALFORMED query to
54
+ * prove the app rejects it (issue #464), so anything that is not a duplicated path is appended
55
+ * verbatim: no encoding, no normalising, no reordering.
56
+ */
57
+ export function joinPath(base: string, path: string, declared?: string | null): string {
58
+ if (declared === undefined || declared === null || declared === '') return base + path;
59
+ const value = String(declared);
60
+ // A query/fragment appends — the overwhelmingly common shape, and the only one #464 needs.
61
+ if (value.startsWith('?') || value.startsWith('#')) return base + path + value;
62
+ // An absolute URL replaces everything: the author pasted a full address.
63
+ if (/^[a-z]+:\/\//i.test(value)) return value;
64
+ // A rooted path carries its own path, so it replaces the PAGE's path while everything the
65
+ // baseURL contributed — scheme, host, and any path prefix — is kept.
66
+ if (value.startsWith('/')) return base + value;
67
+ // Anything else is raw input the test wants appended as-is.
68
+ return base + path + value;
69
+ }
70
+
71
+ /**
72
+ * `u.pathname` is percent-encoded; a regex built from a selector's literal `value` is not, so a
73
+ * non-ASCII route (`/読取結果一覧`) could never match. Decoding can throw on a lone `%`, in which
74
+ * case the raw form is all there is.
75
+ */
76
+ function decodedPath(pathname: string): string {
77
+ try {
78
+ return decodeURIComponent(pathname);
79
+ } catch {
80
+ return pathname;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Build the predicate for `expect(page).toHaveURL(...)`.
86
+ *
87
+ * Query semantics are deliberately asymmetric:
88
+ * no `with {{v}}` → the URL must carry NO query. A bare page means a bare page, so
89
+ * `/vi/search` does not pass on `/vi/search?x=1`.
90
+ * `with {{v}}` → every declared param must match; extra params are tolerated, so a
91
+ * tracking/UTM param the test never cared about cannot turn it red.
92
+ * A declared fragment is asserted too; a declared value carrying no query
93
+ * at all constrains the path only (the compiler warns: SG-W014).
94
+ */
95
+ export function urlMatches({ pathname, declared, dataRef }: UrlExpectation): (u: URL) => boolean {
96
+ return (u: URL): boolean => {
97
+ if (!pathname.test(u.pathname) && !pathname.test(decodedPath(u.pathname))) return false;
98
+
99
+ // `dataRef`, not `declared`, decides which rule applies. Both "the step declared nothing" and
100
+ // "the step declared {{v}} but the key resolved to nothing at runtime" arrive here as
101
+ // undefined, and they mean opposite things: the first is a real assertion (a bare page must be
102
+ // bare), the second is broken test-data. Only the generator knows which, and it says so by
103
+ // emitting `dataRef` exactly when the step carried a `with {{v}}`.
104
+ if (!dataRef) return u.search === '';
105
+
106
+ // Silence is the whole bug class this assertion exists to kill, so an unusable declared value
107
+ // is an ERROR, not a quiet verdict. Returning false would read as "the app is wrong"; these
108
+ // throws say "your test-data is wrong, and here is the key". An empty value used to parse to
109
+ // an empty param list, and `[].every()` is vacuously TRUE — it passed on any query at all.
110
+ if (declared === undefined || declared === null) {
111
+ throw new Error(`url assertion: test-data key "${dataRef}" is missing — nothing to assert`);
112
+ }
113
+ if (String(declared).trim() === '') {
114
+ throw new Error(`url assertion: test-data key "${dataRef}" is empty — nothing to assert`);
115
+ }
116
+
117
+ // Parsing against the live pathname as base lets ONE expression handle every shape an author
118
+ // writes: '?q=1' (query only), '/vi/search?q=1' (a whole relative URL — its path is ignored,
119
+ // the page selector already owns the path), and '#tab' (fragment only). The predecessor
120
+ // regex-stripped the prefix instead, which silently turned a value with NO query
121
+ // ('/vi/search') into a bogus param NAME — an assertion that could never be satisfied.
122
+ const d = new URL(String(declared), 'http://sungen.invalid' + u.pathname);
123
+
124
+ // getAll, not get: a multi-select filter (?tag=a&tag=b) is the exact case this assertion is
125
+ // for, and `get()` returns only the first value — so the correct URL failed. Comparing as a
126
+ // subset per key keeps this consistent with "extra params are tolerated", and makes param
127
+ // order meaningless, which is what a URL actually means.
128
+ const queryOk = [...d.searchParams].every(([k, v]) => u.searchParams.getAll(k).includes(v));
129
+
130
+ // Only assert a fragment the author actually declared.
131
+ const hashOk = !d.hash || d.hash === u.hash;
132
+ return queryOk && hashOk;
133
+ };
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.2.19",
3
+ "version": "3.2.20-beta.1",
4
4
  "description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -39,8 +39,8 @@
39
39
  "@babel/types": "^7.28.5",
40
40
  "@cucumber/gherkin": "^37.0.0",
41
41
  "@cucumber/messages": "^31.0.0",
42
- "@sungen/driver-data-factory": "3.2.19",
43
- "@sungen/driver-ui": "3.2.19",
42
+ "@sungen/driver-data-factory": "3.2.20-beta.1",
43
+ "@sungen/driver-ui": "3.2.20-beta.1",
44
44
  "chalk": "^5.6.2",
45
45
  "commander": "^14.0.2",
46
46
  "dotenv": "^17.2.3",
@@ -208,9 +208,14 @@ export function registerGenerateCommand(program: Command): void {
208
208
  }
209
209
 
210
210
  // Security S0 — warn (never block) if test-data looks to hold a real secret.
211
+ // Scoped to the unit being generated: --area used to fall through to the
212
+ // enumerate-everything branch, so `generate --area X` printed OTHER units'
213
+ // secret-scan and dead-data lint findings under X's run (field report: one
214
+ // unit's "service_url is dead data" warning repeated on all 10 API units).
211
215
  const scanDirs: string[] = [];
212
216
  if (screenName) scanDirs.push(path.join(process.cwd(), 'qa', 'screens', screenName));
213
217
  else if (flowName) scanDirs.push(path.join(process.cwd(), 'qa', 'flows', flowName));
218
+ else if (apiName) scanDirs.push(path.join(process.cwd(), 'qa', 'api', apiName));
214
219
  else {
215
220
  // qa/api units are yaml sinks too (apis.yaml headers, mock bodies once shared);
216
221
  // api/flows nests one level deeper. A file entry in the list is harmless —
@@ -15,6 +15,7 @@ import {
15
15
  splitVpAndName,
16
16
  } from '../feature-parser';
17
17
  import { getCasesDatasetRows, resolveResultVariants } from '../result-variants';
18
+ import { renderDynamicTokens } from '../test-data-resolver';
18
19
  import { classifyManualComments, renderAction, renderExpected, renderPrecondition, renderSetupInstruction, runtimeVarsOf } from './wording';
19
20
  import { scenarioFingerprint, combinedFingerprint, mapContentFingerprint } from './fingerprint';
20
21
  import {
@@ -265,7 +266,7 @@ function substituteDisplayVars(
265
266
  // `remember … as {{v}}` DECLARES v — leave that token for renderAction, which
266
267
  // turns it into a quoted name ("note it as …"), not a value to look up.
267
268
  const isCapture = /\bremember\b/i.test(text);
268
- return text.replace(/\{\{\s*([^}\s]+)\s*\}\}/g, (m, key: string, offset: number) => {
269
+ const out = text.replace(/\{\{\s*([^}\s]+)\s*\}\}/g, (m, key: string, offset: number) => {
269
270
  if (isCapture && /\bas\s+$/i.test(text.slice(0, offset))) return m;
270
271
  // A value the test produces at run time has no static form — name it so the
271
272
  // tester knows to compare against what the earlier step captured.
@@ -273,6 +274,9 @@ function substituteDisplayVars(
273
274
  if (!(key in vars)) return m; // unknown stays literal → Gate D flags it
274
275
  return displayValue(vars[key]);
275
276
  });
277
+ // A dynamic token written straight into a step (`{{$uuid}}`) never reaches
278
+ // displayValue — name it here so the same wording covers both routes.
279
+ return renderDynamicTokens(out);
276
280
  }
277
281
 
278
282
  /**
@@ -281,6 +285,10 @@ function substituteDisplayVars(
281
285
  * The canonical value is never changed — only its presentation.
282
286
  */
283
287
  export function displayValue(v: string): string {
288
+ // Runtime-generated tokens nested in a value ("Summary intro {{$timestamp}}")
289
+ // are presentation, not canon — name them before the fidelity checks below,
290
+ // which judge the value's real whitespace.
291
+ v = renderDynamicTokens(v);
284
292
  if (v === '') return '(empty)';
285
293
  if (/^\s+$/.test(v)) return `(${v.length} space${v.length > 1 ? 's' : ''})`;
286
294
  if (v !== v.trim()) return `"${v}"`;