@sun-asterisk/sungen 3.2.10 → 3.2.11
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.
- package/dist/harness/query-catalog.d.ts +32 -2
- package/dist/harness/query-catalog.d.ts.map +1 -1
- package/dist/harness/query-catalog.js +0 -0
- package/dist/harness/query-catalog.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +15 -5
- package/dist/orchestrator/templates/specs-db.d.ts +201 -11
- package/dist/orchestrator/templates/specs-db.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-db.js +440 -91
- package/dist/orchestrator/templates/specs-db.js.map +1 -1
- package/dist/orchestrator/templates/specs-db.ts +463 -79
- package/dist/orchestrator/templates/specs-test-data.ts +39 -3
- package/package.json +7 -4
- package/src/harness/query-catalog.ts +0 -0
- package/src/index.ts +2 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +15 -5
- package/src/orchestrator/templates/specs-db.ts +463 -79
- package/src/orchestrator/templates/specs-test-data.ts +39 -3
|
@@ -48,9 +48,27 @@ export class TestDataLoader {
|
|
|
48
48
|
if (value === undefined || value === null) {
|
|
49
49
|
throw new Error(`Test data key not found: ${key}`);
|
|
50
50
|
}
|
|
51
|
+
// A projected array (e.g. `{{q.rows[*].name}}`) serializes as a JSON list so the full
|
|
52
|
+
// ordered set is preserved for the assert-compare — String([...]) would flatten it to a
|
|
53
|
+
// lossy comma-join that can't be distinguished from a scalar containing commas.
|
|
54
|
+
if (Array.isArray(value)) return this.interpolate(JSON.stringify(value));
|
|
51
55
|
return this.interpolate(String(value));
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a key to its RAW, uncoerced value (array/object/number kept as-is) — for binding
|
|
60
|
+
* DB query parameters, where type-strict stores (MySQL numeric columns, MongoDB) require the
|
|
61
|
+
* native type. get() stringifies for Gherkin text; raw() must not. Throws on missing, mirroring
|
|
62
|
+
* get()'s guard.
|
|
63
|
+
*/
|
|
64
|
+
raw(key: string): any {
|
|
65
|
+
const value = this.resolve(key);
|
|
66
|
+
if (value === undefined || value === null) {
|
|
67
|
+
throw new Error(`Test data key not found: ${key}`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
|
|
54
72
|
/**
|
|
55
73
|
* Substitute embedded `{{ref}}` cross-references inside a resolved string value.
|
|
56
74
|
* Each ref is looked up via resolve() (flat key, @cases row column, or dotted path),
|
|
@@ -78,6 +96,7 @@ export class TestDataLoader {
|
|
|
78
96
|
* `q.count` / `q.length` → number of rows
|
|
79
97
|
* `q.first.col` / `q.last.col` / `q[2].col` → a specific row's column
|
|
80
98
|
* `q.col` → shorthand for the first row's column
|
|
99
|
+
* `q.rows[*].col` → the `col` of EVERY row, projected to an ordered array
|
|
81
100
|
*/
|
|
82
101
|
private resolve(key: string): any {
|
|
83
102
|
// 1. Exact flat key — captured vars (set()) live under a literal, possibly dotted, key.
|
|
@@ -88,9 +107,26 @@ export class TestDataLoader {
|
|
|
88
107
|
return this.data[key];
|
|
89
108
|
}
|
|
90
109
|
// 2. Structured path: head from the row (cases) or shared data, then walk segments.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
// `[n]` → `.n` (numeric index); `[*]` → `.*` (project the rest of the path over each element).
|
|
111
|
+
const tokens = String(key).replace(/\[(\d+)\]/g, '.$1').replace(/\[\*\]/g, '.*').split('.');
|
|
112
|
+
const cur: any = (this.row && tokens[0] in this.row) ? this.row[tokens[0]] : this.data[tokens[0]];
|
|
113
|
+
return TestDataLoader.walk(cur, tokens, 1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Walk the remaining path tokens from `i`. A `*` token on an array projects: the rest of the
|
|
118
|
+
* path is mapped over every element and the collected array returned (recurses for nested `[*]`).
|
|
119
|
+
* Non-`*` tokens use the linear single-step navigation, so numeric/first/last/object access is
|
|
120
|
+
* unchanged.
|
|
121
|
+
*/
|
|
122
|
+
private static walk(cur: any, tokens: string[], i: number): any {
|
|
123
|
+
for (; i < tokens.length && cur != null; i++) {
|
|
124
|
+
if (tokens[i] === '*' && Array.isArray(cur)) {
|
|
125
|
+
const rest = tokens.slice(i + 1);
|
|
126
|
+
return cur.map((el) => TestDataLoader.walk(el, rest, 0));
|
|
127
|
+
}
|
|
128
|
+
cur = TestDataLoader.step(cur, tokens[i]);
|
|
129
|
+
}
|
|
94
130
|
return cur;
|
|
95
131
|
}
|
|
96
132
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sun-asterisk/sungen",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.11",
|
|
4
4
|
"description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"copy-templates": "mkdir -p dist/generators/test-generator/adapters/playwright/templates/steps && mkdir -p dist/generators/test-generator/templates && mkdir -p dist/orchestrator/templates && mkdir -p dist/dashboard/templates && cp -r src/generators/test-generator/adapters/playwright/templates/*.hbs dist/generators/test-generator/adapters/playwright/templates/ 2>/dev/null || true && cp -r src/generators/test-generator/adapters/playwright/templates/steps dist/generators/test-generator/adapters/playwright/templates/ && mkdir -p dist/generators/test-generator/adapters/appium/templates/steps && cp -r src/generators/test-generator/adapters/appium/templates/*.hbs dist/generators/test-generator/adapters/appium/templates/ 2>/dev/null || true && cp -r src/generators/test-generator/adapters/appium/templates/steps dist/generators/test-generator/adapters/appium/templates/ && cp src/generators/test-generator/templates/*.hbs dist/generators/test-generator/templates/ 2>/dev/null || true && cp -r src/orchestrator/templates/* dist/orchestrator/templates/ && cp src/dashboard/templates/index.html dist/dashboard/templates/index.html && mkdir -p dist/harness/catalog && cp src/harness/catalog/*.yaml dist/harness/catalog/",
|
|
13
13
|
"build:dashboard": "cd ../../dashboard && npm install --silent && npm run build && cd - && cp ../../dashboard/dist/index.html src/dashboard/templates/index.html",
|
|
14
14
|
"dev": "tsx src/cli/index.ts",
|
|
15
|
-
"test": "tsx tests/golden/run.ts && tsx tests/audit/run.ts && tsx tests/ingest/run.ts && tsx tests/eval/run.ts && tsx tests/exporter/run.ts && tsx tests/exporter/feature-parser-category.run.ts && tsx tests/exporter/api-detail-sheet.run.ts && tsx tests/exporter/overview-sheet.run.ts && tsx tests/exporter/delivery-divider-tcid.run.ts && tsx tests/exporter/note-expected-actual.run.ts && tsx tests/exporter/test-data-vars.run.ts && tsx tests/exporter/mobile-app-id.run.ts && tsx tests/exporter/api-testcase-cells.run.ts && tsx tests/exporter/delivery-cases-result.run.ts && tsx tests/exporter/precondition-auth-role.run.ts && tsx tests/exporter/report-builder-parity.run.ts && tsx tests/exporter/delivery-preflight-testdata.run.ts && tsx tests/exporter/delivery-preflight-selectors.run.ts && tsx tests/dashboard/api-flows-discovery.run.ts && tsx tests/dashboard/status-results-fallback.run.ts && tsx tests/codegen/verb-ref-masking.run.ts && tsx tests/codegen/table-aria-hidden-locators.run.ts && tsx tests/api-runtime/base-path-url-join.run.ts && tsx tests/api-runtime/file-upload-multipart.run.ts && tsx tests/api-runtime/schema-assertion.run.ts && tsx tests/runtime/test-data-cross-ref.run.ts && tsx tests/capabilities/run.ts && tsx tests/openapi/run.ts && tsx tests/api-field-coverage/run.ts && tsx tests/packaging/run.ts && tsx tests/generate-hint/run.ts && tsx tests/template-assertion/run.ts && tsx tests/journey/run.ts && tsx tests/harness/serial-cascade.run.ts && tsx tests/ai-skills/cross-assistant-orphan.run.ts && tsx tests/init/codex-mcp-config.run.ts && tsx src/orchestrator/ai-skills/golden-skills.test.ts && tsx tests/db-runtime/sql-placeholder-rewrite.run.ts && tsx tests/db-runtime/fallback-flow-codified.run.ts && tsx tests/db-runtime/mysql-integration.opt-in.run.ts",
|
|
15
|
+
"test": "tsx tests/golden/run.ts && tsx tests/audit/run.ts && tsx tests/ingest/run.ts && tsx tests/eval/run.ts && tsx tests/exporter/run.ts && tsx tests/exporter/feature-parser-category.run.ts && tsx tests/exporter/api-detail-sheet.run.ts && tsx tests/exporter/overview-sheet.run.ts && tsx tests/exporter/delivery-divider-tcid.run.ts && tsx tests/exporter/note-expected-actual.run.ts && tsx tests/exporter/test-data-vars.run.ts && tsx tests/exporter/mobile-app-id.run.ts && tsx tests/exporter/api-testcase-cells.run.ts && tsx tests/exporter/delivery-cases-result.run.ts && tsx tests/exporter/precondition-auth-role.run.ts && tsx tests/exporter/report-builder-parity.run.ts && tsx tests/exporter/delivery-preflight-testdata.run.ts && tsx tests/exporter/delivery-preflight-selectors.run.ts && tsx tests/dashboard/api-flows-discovery.run.ts && tsx tests/dashboard/status-results-fallback.run.ts && tsx tests/codegen/verb-ref-masking.run.ts && tsx tests/codegen/table-aria-hidden-locators.run.ts && tsx tests/api-runtime/base-path-url-join.run.ts && tsx tests/api-runtime/file-upload-multipart.run.ts && tsx tests/api-runtime/schema-assertion.run.ts && tsx tests/runtime/test-data-cross-ref.run.ts && tsx tests/runtime/test-data-array-projection.run.ts &&tsx tests/capabilities/run.ts && tsx tests/openapi/run.ts && tsx tests/api-field-coverage/run.ts && tsx tests/packaging/run.ts && tsx tests/generate-hint/run.ts && tsx tests/template-assertion/run.ts && tsx tests/journey/run.ts && tsx tests/harness/serial-cascade.run.ts && tsx tests/ai-skills/cross-assistant-orphan.run.ts && tsx tests/init/codex-mcp-config.run.ts && tsx src/orchestrator/ai-skills/golden-skills.test.ts && tsx tests/db-runtime/sql-placeholder-rewrite.run.ts && tsx tests/db-runtime/fallback-flow-codified.run.ts && tsx tests/db-runtime/cosmos-engine.run.ts && tsx tests/db-runtime/mongodb-engine.run.ts && tsx tests/db-runtime/dynamodb-engine.run.ts && tsx tests/db-runtime/mysql-integration.opt-in.run.ts && tsx tests/db-runtime/mongodb-integration.opt-in.run.ts && tsx tests/db-runtime/dynamodb-integration.opt-in.run.ts",
|
|
16
16
|
"test:update": "tsx tests/golden/run.ts --update && tsx tests/audit/run.ts --update && tsx tests/ingest/run.ts --update",
|
|
17
17
|
"prepublishOnly": "npm run build:dashboard && npm run build"
|
|
18
18
|
},
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@babel/types": "^7.28.5",
|
|
40
40
|
"@cucumber/gherkin": "^37.0.0",
|
|
41
41
|
"@cucumber/messages": "^31.0.0",
|
|
42
|
-
"@sungen/driver-ui": "3.2.
|
|
42
|
+
"@sungen/driver-ui": "3.2.11",
|
|
43
43
|
"chalk": "^5.6.2",
|
|
44
44
|
"commander": "^14.0.2",
|
|
45
45
|
"dotenv": "^17.2.3",
|
|
@@ -65,6 +65,9 @@
|
|
|
65
65
|
"LICENSE"
|
|
66
66
|
],
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"mysql2": "^3"
|
|
68
|
+
"mysql2": "^3",
|
|
69
|
+
"mongodb": "^7",
|
|
70
|
+
"@aws-sdk/client-dynamodb": "^3",
|
|
71
|
+
"@aws-sdk/lib-dynamodb": "^3"
|
|
69
72
|
}
|
|
70
73
|
}
|
|
Binary file
|
package/src/index.ts
CHANGED
|
@@ -25,8 +25,8 @@ export { getPathCode, inferPath, resolvePathVariables } from './generators/test-
|
|
|
25
25
|
export { parseQueryOverrides } from './harness/annotation-overrides';
|
|
26
26
|
|
|
27
27
|
// --- Named-query catalog (shared: the DB driver's codegen + core's data-driven advisory lint) ---
|
|
28
|
-
export { resolveQuery, compileQuery, lintCatalog } from './harness/query-catalog';
|
|
29
|
-
export type { QueryEntry } from './harness/query-catalog';
|
|
28
|
+
export { resolveQuery, compileQuery, compileShape, isShapeEntry, lintCatalog } from './harness/query-catalog';
|
|
29
|
+
export type { QueryEntry, MongoFind, MongoPipeline } from './harness/query-catalog';
|
|
30
30
|
|
|
31
31
|
// --- Shared harness: viewpoint catalog + coverage gate / assertion depth ---
|
|
32
32
|
// (the UI capability's gateProvider composes these; they also back core's ingest + audit fallback)
|
|
@@ -143,14 +143,24 @@ Scenario: ...
|
|
|
143
143
|
|
|
144
144
|
Path access on a bound result: `{{q.count}}`/`{{q.length}}`, `{{q.first.col}}`, `{{q.last.col}}`, `{{q[2].col}}`, `{{q.col}}` (= first row's col). `expect A is B` also supports `is at least` / `is at most` / `is not`. Tier-2 declarative (trivial inline, no catalog): `User see [<table>] row where [<col>] is {{v}} [has [<col2>] = "x"]`, `… no row where …`, `… count is {{n}}`. Full grammar + catalog/datasource/secret rules → **Advanced → Database** doc. Only emit DB steps when the project has a `database/` catalog / `datasources.yaml`.
|
|
145
145
|
|
|
146
|
+
### NoSQL engines (Cosmos, MongoDB, DynamoDB) — natively supported
|
|
147
|
+
|
|
148
|
+
Beyond the three SQL engines, the Data Driver has native NoSQL engines. Declarative steps (`User see [table] row where …`, `… no row …`, `… count is …`) work across ALL of them; only the raw `@query` catalog shape differs per engine:
|
|
149
|
+
|
|
150
|
+
- **`engine: cosmos`** (Azure Cosmos DB, NoSQL API) — SQL dialect. Author `sql:` catalog entries against the mandatory `c` alias (`SELECT * FROM c WHERE c.<field> = :p`); named params bind automatically. Config: `endpoint`+`key` (or a connection-string `url`), `database`, `container` (default when no `[table]`). Read-only by construction (the query API can't mutate).
|
|
151
|
+
- **`engine: mongodb`** — no SQL. Author a `find:` (`{collection, filter, projection?, sort?, limit?}`) or `pipeline:` (`{collection, stages: […]}`) catalog entry; `:param` placeholders bind at runtime. `$out`/`$merge`/`$where`/`$function`/`$accumulator`/`mapReduce` are refused. Config: a `mongodb://` `url`. Read-only = a server-side read role.
|
|
152
|
+
- **`engine: dynamodb`** — raw `@query` is PartiQL SELECT (`sql: SELECT … FROM "table" WHERE pk = :p`). Declarative steps route GetItem/Query only for partition-/sort-key filters via a `keySchema:` registry; a **non-key filter is refused** (use a raw PartiQL SELECT — never a full-table Scan). Config: `region` + `keySchema` (credentials from the AWS env chain). Read-only = IAM `PartiQLSelect`-only.
|
|
153
|
+
|
|
154
|
+
Full config + catalog examples → **Advanced → Database** doc.
|
|
155
|
+
|
|
146
156
|
### Unsupported DB engine — fallback (ask, don't improvise)
|
|
147
157
|
|
|
148
|
-
Direct SQL verification (`@query`, the Data Driver)
|
|
158
|
+
Direct SQL verification (`@query`, the Data Driver) covers these SQL engines: **`{postgres, sqlite, mysql}`** — plus the three native NoSQL engines above (Cosmos, MongoDB, DynamoDB). When a datasource's `engine` (or the DB the user describes) is **outside all of those** — e.g. Cassandra, Oracle, Neo4j, a proprietary store:
|
|
149
159
|
|
|
150
160
|
1. **Do not** attempt a direct connect. **Do not** improvise a verification method.
|
|
151
161
|
2. Present a fixed `AskUserQuestion` with exactly these 3 branches (always these, no others invented):
|
|
152
162
|
- **@api** — verify state via the project's internal API (route to the API driver).
|
|
153
|
-
- **@manual** — emit a `@manual` step + manual-check guidance (e.g.
|
|
163
|
+
- **@manual** — emit a `@manual` step + manual-check guidance (e.g. the vendor console / CLI — `cqlsh` for Cassandra, `cypher-shell` for Neo4j).
|
|
154
164
|
- **Proxy / read-replica SQL** — if the user can supply a SQL-compatible endpoint (including Azure Cosmos DB **for PostgreSQL** / Citus), treat it as `engine: postgres` (or `mysql`) and use the normal Data Driver path above.
|
|
155
165
|
3. **Recommend, don't decide.** Check the project for signals and put the best-fit branch **first**, tagged **"(Recommended)"** with a one-line reason:
|
|
156
166
|
- a project API driver / `qa/api/` catalog / `PEERCONNE_URL`-style internal API exists → **@api** first;
|
|
@@ -163,11 +173,11 @@ Direct SQL verification (`@query`, the Data Driver) only supports these engines:
|
|
|
163
173
|
Example:
|
|
164
174
|
```
|
|
165
175
|
AskUserQuestion:
|
|
166
|
-
question: "This datasource's engine (
|
|
176
|
+
question: "This datasource's engine (cassandra) isn't a supported Data Driver engine ({postgres, sqlite, mysql} + Cosmos/MongoDB/DynamoDB) — direct connect isn't supported. How should DB state be verified?"
|
|
167
177
|
options:
|
|
168
178
|
- "@api — verify via the project's internal API (Recommended: qa/api/ catalog found)"
|
|
169
|
-
- "@manual — emit a @manual step +
|
|
170
|
-
- "Proxy / read-replica SQL — supply a SQL-compatible endpoint
|
|
179
|
+
- "@manual — emit a @manual step + cqlsh check"
|
|
180
|
+
- "Proxy / read-replica SQL — supply a SQL-compatible endpoint → engine: postgres"
|
|
171
181
|
- "Other — describe your own verification approach"
|
|
172
182
|
```
|
|
173
183
|
|