@sun-asterisk/sungen 3.2.10-beta.5 → 3.2.10
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/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +2 -5
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +2 -44
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/harness/capability.d.ts +0 -1
- package/dist/harness/capability.d.ts.map +1 -1
- package/dist/harness/capability.js.map +1 -1
- package/dist/harness/catalog/drivers.yaml +1 -2
- package/dist/harness/query-catalog.d.ts +2 -32
- 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 +1 -3
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +0 -1
- package/dist/orchestrator/templates/ai-src/config/claude.md +1 -3
- package/dist/orchestrator/templates/ai-src/config/copilot.md +1 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +5 -15
- package/dist/orchestrator/templates/specs-db.d.ts +11 -201
- package/dist/orchestrator/templates/specs-db.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-db.js +91 -440
- package/dist/orchestrator/templates/specs-db.js.map +1 -1
- package/dist/orchestrator/templates/specs-db.ts +79 -463
- package/dist/orchestrator/templates/specs-test-data.ts +3 -39
- package/package.json +4 -8
- package/src/capabilities/discover.ts +2 -5
- package/src/cli/commands/capability.ts +2 -40
- package/src/harness/capability.ts +0 -1
- package/src/harness/catalog/drivers.yaml +1 -2
- package/src/harness/query-catalog.ts +0 -0
- package/src/index.ts +2 -2
- package/src/orchestrator/templates/ai-src/commands/run-test.md +0 -1
- package/src/orchestrator/templates/ai-src/config/claude.md +1 -3
- package/src/orchestrator/templates/ai-src/config/copilot.md +1 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +5 -15
- package/src/orchestrator/templates/specs-db.ts +79 -463
- package/src/orchestrator/templates/specs-test-data.ts +3 -39
- package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +0 -85
- package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +0 -101
- package/src/orchestrator/templates/ai-src/commands/create-data-test.md +0 -85
- package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +0 -101
|
@@ -48,27 +48,9 @@ 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));
|
|
55
51
|
return this.interpolate(String(value));
|
|
56
52
|
}
|
|
57
53
|
|
|
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
|
-
|
|
72
54
|
/**
|
|
73
55
|
* Substitute embedded `{{ref}}` cross-references inside a resolved string value.
|
|
74
56
|
* Each ref is looked up via resolve() (flat key, @cases row column, or dotted path),
|
|
@@ -96,7 +78,6 @@ export class TestDataLoader {
|
|
|
96
78
|
* `q.count` / `q.length` → number of rows
|
|
97
79
|
* `q.first.col` / `q.last.col` / `q[2].col` → a specific row's column
|
|
98
80
|
* `q.col` → shorthand for the first row's column
|
|
99
|
-
* `q.rows[*].col` → the `col` of EVERY row, projected to an ordered array
|
|
100
81
|
*/
|
|
101
82
|
private resolve(key: string): any {
|
|
102
83
|
// 1. Exact flat key — captured vars (set()) live under a literal, possibly dotted, key.
|
|
@@ -107,26 +88,9 @@ export class TestDataLoader {
|
|
|
107
88
|
return this.data[key];
|
|
108
89
|
}
|
|
109
90
|
// 2. Structured path: head from the row (cases) or shared data, then walk segments.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
}
|
|
91
|
+
const tokens = String(key).replace(/\[(\d+)\]/g, '.$1').split('.');
|
|
92
|
+
let cur: any = (this.row && tokens[0] in this.row) ? this.row[tokens[0]] : this.data[tokens[0]];
|
|
93
|
+
for (let i = 1; i < tokens.length && cur != null; i++) cur = TestDataLoader.step(cur, tokens[i]);
|
|
130
94
|
return cur;
|
|
131
95
|
}
|
|
132
96
|
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: create-data-test
|
|
3
|
-
description: "Generate standardized test-data for a screen/flow from the Data Factory catalog — valid/boundary/invalid values with CHK-* traceability (no free-form guessing)"
|
|
4
|
-
argument-hint: [screen-or-flow-name]
|
|
5
|
-
order: 25
|
|
6
|
-
claude-tools: "Read, Grep, Bash, Glob, Write, Edit, AskUserQuestion, Skill"
|
|
7
|
-
copilot-tools: "[vscode, execute, read, agent, edit, search, todo]"
|
|
8
|
-
codex-trigger: "Run when the user asks to CREATE, generate, or standardize TEST DATA / test values for a screen or flow (valid/boundary/invalid, boundary values, negative data). Uses the Data Factory driver. Not for generating the .feature scenarios themselves (that is create-test)."
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
**Input**: A screen or flow name (e.g., `/sungen:create-data-test login`), OR **no name** to do every unit (with a confirmation — see ALL mode). Load the `sungen-data-factory` skill for the full method.
|
|
12
|
-
|
|
13
|
-
## Role
|
|
14
|
-
|
|
15
|
-
You are a **Senior QA Engineer** producing **test data to a standard**, not by guessing. You do NOT invent values field-by-field. You follow the 4-source method (spec rules → field-type catalog → design technique → DB mapping), driven by the **Data Factory** capability driver. Values come from the catalog (`common/` + the project's `.overwrite`), each tagged with a `CHK-*` id that traces back to the spec. Where the catalog cannot cover a project-specific field, you **ask the QA** — you never fabricate domain data.
|
|
16
|
-
|
|
17
|
-
## Preconditions
|
|
18
|
-
|
|
19
|
-
1. **Availability** — Data Factory is **bundled with core** (no `capability add` needed); its CLI (`sungen data …`) is available out of the box. Just continue.
|
|
20
|
-
2. Determine mode from `$ARGUMENTS`:
|
|
21
|
-
- A **name** given → single-unit mode (that screen/flow only).
|
|
22
|
-
- **No name** → **ALL mode** (see below — always confirm first).
|
|
23
|
-
|
|
24
|
-
## ALL mode (no name) — confirm before doing everything
|
|
25
|
-
|
|
26
|
-
If no name was given, the user wants **all** screens/flows — but this is wide, and a missing name is often a typo (they meant `create-data-test home`). So:
|
|
27
|
-
|
|
28
|
-
1. List every unit under `qa/screens/*` and `qa/flows/*`, and classify each as **new** (no `test-data/<name>.yaml` yet) vs **would-overwrite**.
|
|
29
|
-
2. Show the list and use `AskUserQuestion` to confirm: *"Generate test-data for ALL N units? (X new · Y would overwrite)"* — default to **No**.
|
|
30
|
-
3. Only proceed when the user confirms. Then run the per-unit flow below for each (the CLI `sungen data gen --all` also enforces this confirm; `--yes` after the user agrees).
|
|
31
|
-
|
|
32
|
-
## Per-unit flow (single unit, or each unit in ALL mode)
|
|
33
|
-
|
|
34
|
-
Auto-detect: `qa/flows/<name>/` → flow; else `qa/screens/<name>/` → screen. (API units carry their contract in `apis.yaml` — data there is `@cases` in create-test, not this command.)
|
|
35
|
-
|
|
36
|
-
### 1. Read the sources (Nguồn 1 + 4)
|
|
37
|
-
|
|
38
|
-
Read `qa/<screens|flows>/<name>/requirements/spec.md` and `test-viewpoint.md`. For **each input field / parameter**, extract:
|
|
39
|
-
- data **type** (map to a catalog field-type: email · password · phone · string · number-integer · number-float · currency · postcode · katakana …),
|
|
40
|
-
- `required`, format, **min/max** length or value,
|
|
41
|
-
- the real **error/message code** the spec shows when a rule is violated,
|
|
42
|
-
- any **DB mapping** (unique, cross-entity dependency) noted in the spec.
|
|
43
|
-
|
|
44
|
-
Viewpoint tells you which fields are high-priority → give them the fullest data.
|
|
45
|
-
|
|
46
|
-
**No input fields → nothing to generate.** If the unit is a pure navigation / listing / capture-compare flow (e.g. a home-shopping browse flow) with **no user-input fields or parameters**, Data Factory has nothing to standardize. Report *"`<name>`: no input fields → nothing to generate"* and stop for this unit — do **not** write an empty `qa/data-factory/<name>.fields.yaml`. (Its scenarios are covered by create-test's data, not by field-level test data.)
|
|
47
|
-
|
|
48
|
-
### 2. Write the field-map — `qa/data-factory/<name>.fields.yaml`
|
|
49
|
-
|
|
50
|
-
This is the input the deterministic generator expands. One entry per field:
|
|
51
|
-
|
|
52
|
-
```yaml
|
|
53
|
-
screen: <name> # or: flow: <name>
|
|
54
|
-
fields:
|
|
55
|
-
- name: email
|
|
56
|
-
type: email
|
|
57
|
-
required: true
|
|
58
|
-
constraints: { maxLocal: 64, maxTotal: 254 } # project's real limits
|
|
59
|
-
errorMap: { M13: E1042, M02: E1001 } # catalog placeholder → project's real code
|
|
60
|
-
- name: password
|
|
61
|
-
type: password
|
|
62
|
-
constraints: { minLength: 8, maxLength: 32 }
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Map every placeholder error code you can (`errorMap`) to the spec's real code. Leave a code unmapped only if the spec truly has none — the lint will flag it as an open point to confirm with BA/Dev.
|
|
66
|
-
|
|
67
|
-
### 3. Blind spots — ask, do not invent
|
|
68
|
-
|
|
69
|
-
If a field's type is **not** in the catalog (a business enum, a cross-entity constraint, a project data model), **stop and ask the QA** with `AskUserQuestion` for: (1) the valid set, (2) invalid / non-existent values, (3) the error code when wrong, (4) dependencies on other fields. Record the answer in `qa/data-factory/project/<entity>.yaml` for reuse. Never fabricate domain values.
|
|
70
|
-
|
|
71
|
-
### 4. Lint the coverage
|
|
72
|
-
|
|
73
|
-
Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>`. Fix what it reports: add missing boundary values, resolve `UNRESOLVED` items (supply the constraint), map `OPEN_ERRORREF` codes. The bar is the phuong-phap §6 checklist — every required field has valid + boundary + invalid, one invalid per rule.
|
|
74
|
-
|
|
75
|
-
### 5. Generate the test-data
|
|
76
|
-
|
|
77
|
-
Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data gen --screen <name> || npx sungen data gen --screen <name>`. If `test-data/<name>.yaml` already exists it **asks before overwriting** — respect the user's choice (in ALL mode after they confirmed, add `--yes`; use `--force` only when the user explicitly wants an unconditional overwrite). The output is standardized `valid/boundary/invalid` values with `CHK-*` traceability.
|
|
78
|
-
|
|
79
|
-
### 6. Weave into scenarios (if create-test already ran)
|
|
80
|
-
|
|
81
|
-
If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
|
|
82
|
-
|
|
83
|
-
## After running
|
|
84
|
-
|
|
85
|
-
Use `AskUserQuestion` to offer the next step: review the generated data, run `/sungen:create-test <name>` (if scenarios don't exist yet), or `/sungen:run-test <name>`.
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sungen-data-factory
|
|
3
|
-
description: 'Use when create-data-test (or create-test) needs standardized TEST DATA — valid/boundary/invalid values for input fields with CHK-* traceability. Drives the Data Factory catalog + the 4-source method. Invoke after reading spec.md, when authoring the field-map or filling test-data.'
|
|
4
|
-
user-invocable: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## What this skill does
|
|
8
|
-
|
|
9
|
-
Turn a screen/flow's fields into **standardized test data** — not guessed values. You author a
|
|
10
|
-
**field-map**; the deterministic `sungen data gen` expands it from the Data Factory **catalog**
|
|
11
|
-
(field-type + security + technique library) into valid / boundary / invalid values, each carrying a
|
|
12
|
-
`CHK-*` id that traces to the spec. Your judgment goes into *reading the spec correctly* and
|
|
13
|
-
*answering blind spots* — never into inventing values the catalog or the QA should own.
|
|
14
|
-
|
|
15
|
-
Data Factory is **bundled with core** (runtime-free) — no `capability add` needed; the `sungen data …`
|
|
16
|
-
CLI is available out of the box.
|
|
17
|
-
|
|
18
|
-
## The 4-source method (phuong-phap-tao-test-data.md)
|
|
19
|
-
|
|
20
|
-
Never invent values from memory. Cross-reference four sources — each covers the previous one's gap:
|
|
21
|
-
|
|
22
|
-
1. **Spec validate rules** — required, format, min/max, business rules, and the **error/message code**
|
|
23
|
-
per rule. Defines the legal/illegal boundary. (Says the *law*, not every way to *break* it.)
|
|
24
|
-
2. **Field-type catalog** — the accumulated "how this type breaks" knowledge (email/password/phone/
|
|
25
|
-
number/…). This is the Data Factory `common/` — it fills the "spec doesn't list every break" gap.
|
|
26
|
-
3. **Design technique** — Boundary Value Analysis / Equivalence Partitioning / Decision Table / State
|
|
27
|
-
Transition — reduces the rule + candidates to a *minimal-but-sufficient* representative set.
|
|
28
|
-
4. **DB mapping** — unique constraints, cross-entity dependency, real backend limits → precondition
|
|
29
|
-
data, not just a single input value.
|
|
30
|
-
|
|
31
|
-
Then classify every value into **Valid / Boundary / Invalid** (each invalid tagged with its error
|
|
32
|
-
code) and give it a `CHK-*` id for traceability.
|
|
33
|
-
|
|
34
|
-
## The field-map — `qa/data-factory/<name>.fields.yaml`
|
|
35
|
-
|
|
36
|
-
Your main artifact. One entry per input field; the generator expands it:
|
|
37
|
-
|
|
38
|
-
```yaml
|
|
39
|
-
screen: login # or flow: <name>
|
|
40
|
-
fields:
|
|
41
|
-
- name: email
|
|
42
|
-
type: email # a catalog field-type (see list below)
|
|
43
|
-
required: true
|
|
44
|
-
constraints: { maxLocal: 64, maxTotal: 254 } # the project's REAL limits from spec
|
|
45
|
-
errorMap: { M13: E1042, M02: E1001 } # catalog placeholder code → project's real code
|
|
46
|
-
- name: password
|
|
47
|
-
type: password
|
|
48
|
-
constraints: { minLength: 8, maxLength: 32 }
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Catalog field-types** (P1): `email` · `password` · `phone` · `string` · `number-integer` ·
|
|
52
|
-
`number-float` · `currency` · `postcode` · `katakana` (JP). Security payload banks auto-append to a
|
|
53
|
-
field's invalid group via the type's `uses_security` (`sqli`, `xss`, `idor`, `broken-auth`, `upload`,
|
|
54
|
-
`input-validation`).
|
|
55
|
-
|
|
56
|
-
Rules:
|
|
57
|
-
- Pick the closest `type`; put the project's real numbers in `constraints` (they override the
|
|
58
|
-
catalog defaults).
|
|
59
|
-
- Map every `errorRef` placeholder (`M13`, `M39`, …) to the spec's real code via `errorMap`. Leave
|
|
60
|
-
one unmapped **only** if the spec has none — the lint flags it as an open point to confirm.
|
|
61
|
-
|
|
62
|
-
## No input fields → nothing to generate
|
|
63
|
-
|
|
64
|
-
Data Factory standardizes **field-level input data**. If a unit has no user-input fields or
|
|
65
|
-
parameters — a pure navigation, listing, or capture-compare flow — there is nothing to generate.
|
|
66
|
-
Report *"no input fields → nothing to generate"* and skip it; do **not** write an empty field-map.
|
|
67
|
-
Those scenarios are covered by the data create-test already produced, not by field-level test data.
|
|
68
|
-
(This is a correct outcome, not a gap — don't force a field-map to make the unit "processed".)
|
|
69
|
-
|
|
70
|
-
## Blind spots — ask, never fabricate
|
|
71
|
-
|
|
72
|
-
If a field's type is **not** in the catalog — a business enum, a cross-entity constraint, a
|
|
73
|
-
project-specific data model — do **not** guess. Ask the QA (via `AskUserQuestion`) for: (1) the valid
|
|
74
|
-
set, (2) invalid / non-existent values, (3) the error code when wrong, (4) dependencies on other
|
|
75
|
-
fields. Record it in `qa/data-factory/project/<entity>.yaml` so it becomes reusable project catalog.
|
|
76
|
-
This is the core discipline: *common is never enough; when blind, think and ask — don't invent.*
|
|
77
|
-
|
|
78
|
-
## Customizing the catalog — `.overwrite` (survives `sungen update`)
|
|
79
|
-
|
|
80
|
-
The shipped `common/` is a floor. Project rules go in `qa/data-factory/common.overwrite.yaml`,
|
|
81
|
-
deep-merged over the common (**later-wins**, keyed by `type` + data-point `id`): same `id` replaces,
|
|
82
|
-
new `id` appends, `constraints` merge key-by-key. `sungen update` refreshes `common/` but never
|
|
83
|
-
touches your overlay. If an update makes an overlay entry stale (references a bank/constraint that no
|
|
84
|
-
longer exists), the loader **warns you to prune it** — it never edits your file. Prefer a targeted
|
|
85
|
-
`errorMap`/`constraints` in the field-map for per-screen tweaks; use `.overwrite` only for rules that
|
|
86
|
-
apply project-wide.
|
|
87
|
-
|
|
88
|
-
## Verify before done — the phuong-phap §6 checklist
|
|
89
|
-
|
|
90
|
-
Run `sungen data lint` and clear it: every required field has **≥1 valid**, **boundary present**
|
|
91
|
-
(exact min/max, not only over-boundary) for bounded types, **≥1 invalid per rule** (not one generic
|
|
92
|
-
"wrong" value for many rules), no `UNRESOLVED` values, error codes mapped or explicitly left open.
|
|
93
|
-
Then `sungen data gen` writes the standardized `test-data/<name>.yaml`. Do not hand-edit the
|
|
94
|
-
generated values — change the field-map or `.overwrite` and re-run (determinism: same input → same
|
|
95
|
-
data).
|
|
96
|
-
|
|
97
|
-
## Weaving into scenarios
|
|
98
|
-
|
|
99
|
-
When a `.feature` exists, express invalid/boundary sets as data-driven `Scenario Outline` + `Examples`
|
|
100
|
-
(`@cases`) referencing the values — see `sungen-gherkin-syntax`. This keeps one logic + many values
|
|
101
|
-
instead of copy-pasted scenarios, and each row carries its `CHK-*` id for traceability.
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: create-data-test
|
|
3
|
-
description: "Generate standardized test-data for a screen/flow from the Data Factory catalog — valid/boundary/invalid values with CHK-* traceability (no free-form guessing)"
|
|
4
|
-
argument-hint: [screen-or-flow-name]
|
|
5
|
-
order: 25
|
|
6
|
-
claude-tools: "Read, Grep, Bash, Glob, Write, Edit, AskUserQuestion, Skill"
|
|
7
|
-
copilot-tools: "[vscode, execute, read, agent, edit, search, todo]"
|
|
8
|
-
codex-trigger: "Run when the user asks to CREATE, generate, or standardize TEST DATA / test values for a screen or flow (valid/boundary/invalid, boundary values, negative data). Uses the Data Factory driver. Not for generating the .feature scenarios themselves (that is create-test)."
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
**Input**: A screen or flow name (e.g., `/sungen:create-data-test login`), OR **no name** to do every unit (with a confirmation — see ALL mode). Load the `sungen-data-factory` skill for the full method.
|
|
12
|
-
|
|
13
|
-
## Role
|
|
14
|
-
|
|
15
|
-
You are a **Senior QA Engineer** producing **test data to a standard**, not by guessing. You do NOT invent values field-by-field. You follow the 4-source method (spec rules → field-type catalog → design technique → DB mapping), driven by the **Data Factory** capability driver. Values come from the catalog (`common/` + the project's `.overwrite`), each tagged with a `CHK-*` id that traces back to the spec. Where the catalog cannot cover a project-specific field, you **ask the QA** — you never fabricate domain data.
|
|
16
|
-
|
|
17
|
-
## Preconditions
|
|
18
|
-
|
|
19
|
-
1. **Availability** — Data Factory is **bundled with core** (no `capability add` needed); its CLI (`sungen data …`) is available out of the box. Just continue.
|
|
20
|
-
2. Determine mode from `$ARGUMENTS`:
|
|
21
|
-
- A **name** given → single-unit mode (that screen/flow only).
|
|
22
|
-
- **No name** → **ALL mode** (see below — always confirm first).
|
|
23
|
-
|
|
24
|
-
## ALL mode (no name) — confirm before doing everything
|
|
25
|
-
|
|
26
|
-
If no name was given, the user wants **all** screens/flows — but this is wide, and a missing name is often a typo (they meant `create-data-test home`). So:
|
|
27
|
-
|
|
28
|
-
1. List every unit under `qa/screens/*` and `qa/flows/*`, and classify each as **new** (no `test-data/<name>.yaml` yet) vs **would-overwrite**.
|
|
29
|
-
2. Show the list and use `AskUserQuestion` to confirm: *"Generate test-data for ALL N units? (X new · Y would overwrite)"* — default to **No**.
|
|
30
|
-
3. Only proceed when the user confirms. Then run the per-unit flow below for each (the CLI `sungen data gen --all` also enforces this confirm; `--yes` after the user agrees).
|
|
31
|
-
|
|
32
|
-
## Per-unit flow (single unit, or each unit in ALL mode)
|
|
33
|
-
|
|
34
|
-
Auto-detect: `qa/flows/<name>/` → flow; else `qa/screens/<name>/` → screen. (API units carry their contract in `apis.yaml` — data there is `@cases` in create-test, not this command.)
|
|
35
|
-
|
|
36
|
-
### 1. Read the sources (Nguồn 1 + 4)
|
|
37
|
-
|
|
38
|
-
Read `qa/<screens|flows>/<name>/requirements/spec.md` and `test-viewpoint.md`. For **each input field / parameter**, extract:
|
|
39
|
-
- data **type** (map to a catalog field-type: email · password · phone · string · number-integer · number-float · currency · postcode · katakana …),
|
|
40
|
-
- `required`, format, **min/max** length or value,
|
|
41
|
-
- the real **error/message code** the spec shows when a rule is violated,
|
|
42
|
-
- any **DB mapping** (unique, cross-entity dependency) noted in the spec.
|
|
43
|
-
|
|
44
|
-
Viewpoint tells you which fields are high-priority → give them the fullest data.
|
|
45
|
-
|
|
46
|
-
**No input fields → nothing to generate.** If the unit is a pure navigation / listing / capture-compare flow (e.g. a home-shopping browse flow) with **no user-input fields or parameters**, Data Factory has nothing to standardize. Report *"`<name>`: no input fields → nothing to generate"* and stop for this unit — do **not** write an empty `qa/data-factory/<name>.fields.yaml`. (Its scenarios are covered by create-test's data, not by field-level test data.)
|
|
47
|
-
|
|
48
|
-
### 2. Write the field-map — `qa/data-factory/<name>.fields.yaml`
|
|
49
|
-
|
|
50
|
-
This is the input the deterministic generator expands. One entry per field:
|
|
51
|
-
|
|
52
|
-
```yaml
|
|
53
|
-
screen: <name> # or: flow: <name>
|
|
54
|
-
fields:
|
|
55
|
-
- name: email
|
|
56
|
-
type: email
|
|
57
|
-
required: true
|
|
58
|
-
constraints: { maxLocal: 64, maxTotal: 254 } # project's real limits
|
|
59
|
-
errorMap: { M13: E1042, M02: E1001 } # catalog placeholder → project's real code
|
|
60
|
-
- name: password
|
|
61
|
-
type: password
|
|
62
|
-
constraints: { minLength: 8, maxLength: 32 }
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Map every placeholder error code you can (`errorMap`) to the spec's real code. Leave a code unmapped only if the spec truly has none — the lint will flag it as an open point to confirm with BA/Dev.
|
|
66
|
-
|
|
67
|
-
### 3. Blind spots — ask, do not invent
|
|
68
|
-
|
|
69
|
-
If a field's type is **not** in the catalog (a business enum, a cross-entity constraint, a project data model), **stop and ask the QA** with `AskUserQuestion` for: (1) the valid set, (2) invalid / non-existent values, (3) the error code when wrong, (4) dependencies on other fields. Record the answer in `qa/data-factory/project/<entity>.yaml` for reuse. Never fabricate domain values.
|
|
70
|
-
|
|
71
|
-
### 4. Lint the coverage
|
|
72
|
-
|
|
73
|
-
Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data lint --screen <name> || npx sungen data lint --screen <name>`. Fix what it reports: add missing boundary values, resolve `UNRESOLVED` items (supply the constraint), map `OPEN_ERRORREF` codes. The bar is the phuong-phap §6 checklist — every required field has valid + boundary + invalid, one invalid per rule.
|
|
74
|
-
|
|
75
|
-
### 5. Generate the test-data
|
|
76
|
-
|
|
77
|
-
Run (local-first): `[ -x ./bin/sungen.js ] && ./bin/sungen.js data gen --screen <name> || npx sungen data gen --screen <name>`. If `test-data/<name>.yaml` already exists it **asks before overwriting** — respect the user's choice (in ALL mode after they confirmed, add `--yes`; use `--force` only when the user explicitly wants an unconditional overwrite). The output is standardized `valid/boundary/invalid` values with `CHK-*` traceability.
|
|
78
|
-
|
|
79
|
-
### 6. Weave into scenarios (if create-test already ran)
|
|
80
|
-
|
|
81
|
-
If the `.feature` exists, turn the generated invalid/boundary sets into data-driven `Scenario Outline` + `Examples` (`@cases`) referencing the values — following `sungen-gherkin-syntax`. Otherwise leave the standardized `test-data/<name>.yaml` for `/sungen:run-test` to consume.
|
|
82
|
-
|
|
83
|
-
## After running
|
|
84
|
-
|
|
85
|
-
Use `AskUserQuestion` to offer the next step: review the generated data, run `/sungen:create-test <name>` (if scenarios don't exist yet), or `/sungen:run-test <name>`.
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: sungen-data-factory
|
|
3
|
-
description: 'Use when create-data-test (or create-test) needs standardized TEST DATA — valid/boundary/invalid values for input fields with CHK-* traceability. Drives the Data Factory catalog + the 4-source method. Invoke after reading spec.md, when authoring the field-map or filling test-data.'
|
|
4
|
-
user-invocable: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## What this skill does
|
|
8
|
-
|
|
9
|
-
Turn a screen/flow's fields into **standardized test data** — not guessed values. You author a
|
|
10
|
-
**field-map**; the deterministic `sungen data gen` expands it from the Data Factory **catalog**
|
|
11
|
-
(field-type + security + technique library) into valid / boundary / invalid values, each carrying a
|
|
12
|
-
`CHK-*` id that traces to the spec. Your judgment goes into *reading the spec correctly* and
|
|
13
|
-
*answering blind spots* — never into inventing values the catalog or the QA should own.
|
|
14
|
-
|
|
15
|
-
Data Factory is **bundled with core** (runtime-free) — no `capability add` needed; the `sungen data …`
|
|
16
|
-
CLI is available out of the box.
|
|
17
|
-
|
|
18
|
-
## The 4-source method (phuong-phap-tao-test-data.md)
|
|
19
|
-
|
|
20
|
-
Never invent values from memory. Cross-reference four sources — each covers the previous one's gap:
|
|
21
|
-
|
|
22
|
-
1. **Spec validate rules** — required, format, min/max, business rules, and the **error/message code**
|
|
23
|
-
per rule. Defines the legal/illegal boundary. (Says the *law*, not every way to *break* it.)
|
|
24
|
-
2. **Field-type catalog** — the accumulated "how this type breaks" knowledge (email/password/phone/
|
|
25
|
-
number/…). This is the Data Factory `common/` — it fills the "spec doesn't list every break" gap.
|
|
26
|
-
3. **Design technique** — Boundary Value Analysis / Equivalence Partitioning / Decision Table / State
|
|
27
|
-
Transition — reduces the rule + candidates to a *minimal-but-sufficient* representative set.
|
|
28
|
-
4. **DB mapping** — unique constraints, cross-entity dependency, real backend limits → precondition
|
|
29
|
-
data, not just a single input value.
|
|
30
|
-
|
|
31
|
-
Then classify every value into **Valid / Boundary / Invalid** (each invalid tagged with its error
|
|
32
|
-
code) and give it a `CHK-*` id for traceability.
|
|
33
|
-
|
|
34
|
-
## The field-map — `qa/data-factory/<name>.fields.yaml`
|
|
35
|
-
|
|
36
|
-
Your main artifact. One entry per input field; the generator expands it:
|
|
37
|
-
|
|
38
|
-
```yaml
|
|
39
|
-
screen: login # or flow: <name>
|
|
40
|
-
fields:
|
|
41
|
-
- name: email
|
|
42
|
-
type: email # a catalog field-type (see list below)
|
|
43
|
-
required: true
|
|
44
|
-
constraints: { maxLocal: 64, maxTotal: 254 } # the project's REAL limits from spec
|
|
45
|
-
errorMap: { M13: E1042, M02: E1001 } # catalog placeholder code → project's real code
|
|
46
|
-
- name: password
|
|
47
|
-
type: password
|
|
48
|
-
constraints: { minLength: 8, maxLength: 32 }
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Catalog field-types** (P1): `email` · `password` · `phone` · `string` · `number-integer` ·
|
|
52
|
-
`number-float` · `currency` · `postcode` · `katakana` (JP). Security payload banks auto-append to a
|
|
53
|
-
field's invalid group via the type's `uses_security` (`sqli`, `xss`, `idor`, `broken-auth`, `upload`,
|
|
54
|
-
`input-validation`).
|
|
55
|
-
|
|
56
|
-
Rules:
|
|
57
|
-
- Pick the closest `type`; put the project's real numbers in `constraints` (they override the
|
|
58
|
-
catalog defaults).
|
|
59
|
-
- Map every `errorRef` placeholder (`M13`, `M39`, …) to the spec's real code via `errorMap`. Leave
|
|
60
|
-
one unmapped **only** if the spec has none — the lint flags it as an open point to confirm.
|
|
61
|
-
|
|
62
|
-
## No input fields → nothing to generate
|
|
63
|
-
|
|
64
|
-
Data Factory standardizes **field-level input data**. If a unit has no user-input fields or
|
|
65
|
-
parameters — a pure navigation, listing, or capture-compare flow — there is nothing to generate.
|
|
66
|
-
Report *"no input fields → nothing to generate"* and skip it; do **not** write an empty field-map.
|
|
67
|
-
Those scenarios are covered by the data create-test already produced, not by field-level test data.
|
|
68
|
-
(This is a correct outcome, not a gap — don't force a field-map to make the unit "processed".)
|
|
69
|
-
|
|
70
|
-
## Blind spots — ask, never fabricate
|
|
71
|
-
|
|
72
|
-
If a field's type is **not** in the catalog — a business enum, a cross-entity constraint, a
|
|
73
|
-
project-specific data model — do **not** guess. Ask the QA (via `AskUserQuestion`) for: (1) the valid
|
|
74
|
-
set, (2) invalid / non-existent values, (3) the error code when wrong, (4) dependencies on other
|
|
75
|
-
fields. Record it in `qa/data-factory/project/<entity>.yaml` so it becomes reusable project catalog.
|
|
76
|
-
This is the core discipline: *common is never enough; when blind, think and ask — don't invent.*
|
|
77
|
-
|
|
78
|
-
## Customizing the catalog — `.overwrite` (survives `sungen update`)
|
|
79
|
-
|
|
80
|
-
The shipped `common/` is a floor. Project rules go in `qa/data-factory/common.overwrite.yaml`,
|
|
81
|
-
deep-merged over the common (**later-wins**, keyed by `type` + data-point `id`): same `id` replaces,
|
|
82
|
-
new `id` appends, `constraints` merge key-by-key. `sungen update` refreshes `common/` but never
|
|
83
|
-
touches your overlay. If an update makes an overlay entry stale (references a bank/constraint that no
|
|
84
|
-
longer exists), the loader **warns you to prune it** — it never edits your file. Prefer a targeted
|
|
85
|
-
`errorMap`/`constraints` in the field-map for per-screen tweaks; use `.overwrite` only for rules that
|
|
86
|
-
apply project-wide.
|
|
87
|
-
|
|
88
|
-
## Verify before done — the phuong-phap §6 checklist
|
|
89
|
-
|
|
90
|
-
Run `sungen data lint` and clear it: every required field has **≥1 valid**, **boundary present**
|
|
91
|
-
(exact min/max, not only over-boundary) for bounded types, **≥1 invalid per rule** (not one generic
|
|
92
|
-
"wrong" value for many rules), no `UNRESOLVED` values, error codes mapped or explicitly left open.
|
|
93
|
-
Then `sungen data gen` writes the standardized `test-data/<name>.yaml`. Do not hand-edit the
|
|
94
|
-
generated values — change the field-map or `.overwrite` and re-run (determinism: same input → same
|
|
95
|
-
data).
|
|
96
|
-
|
|
97
|
-
## Weaving into scenarios
|
|
98
|
-
|
|
99
|
-
When a `.feature` exists, express invalid/boundary sets as data-driven `Scenario Outline` + `Examples`
|
|
100
|
-
(`@cases`) referencing the values — see `sungen-gherkin-syntax`. This keeps one logic + many values
|
|
101
|
-
instead of copy-pasted scenarios, and each row carries its `CHK-*` id for traceability.
|