@qa-gentic/stlc-agents 1.0.14 → 1.0.16
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/README.md +1 -2
- package/package.json +1 -1
- package/skills/AGENT-BEHAVIOR.md +15 -22
- package/skills/deduplication-protocol/SKILL.md +51 -3
- package/skills/generate-gherkin/SKILL.md +15 -30
- package/skills/generate-gherkin/references/step-by-step.md +2 -6
- package/skills/generate-playwright-code/SKILL.md +19 -122
- package/skills/generate-playwright-code/references/file-structures.md +128 -0
- package/skills/generate-test-cases/SKILL.md +2 -2
- package/skills/write-helix-files/SKILL.md +12 -3
- package/src/stlc_agents/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/server.py +14 -62
- package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/tools/__pycache__/ado_gherkin.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_gherkin_generator/tools/ado_gherkin.py +5 -126
- package/src/stlc_agents/agent_helix_writer/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/boilerplate.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_helix_writer/tools/__pycache__/helix_write.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/server.py +0 -32
- package/src/stlc_agents/agent_jira_manager/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/tools/__pycache__/jira_workitem.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_jira_manager/tools/jira_workitem.py +3 -78
- package/src/stlc_agents/agent_playwright_generator/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/server.py +57 -7
- package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_playwright_generator/tools/__pycache__/ado_attach.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/server.py +4 -4
- package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/tools/__pycache__/ado_workitem.cpython-310.pyc +0 -0
- package/src/stlc_agents/agent_test_case_manager/tools/ado_workitem.py +3 -5
- package/src/stlc_agents/shared/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared/__pycache__/auth.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared_jira/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/stlc_agents/shared_jira/__pycache__/auth.cpython-310.pyc +0 -0
package/README.md
CHANGED
|
@@ -170,7 +170,6 @@ Write the generated files to my Helix-QA project at /workspace/my-qa-project
|
|
|
170
170
|
|
|
171
171
|
| Tool | Description |
|
|
172
172
|
|---|---|
|
|
173
|
-
| `fetch_epic_hierarchy` | Fetch an Epic and all child Features, PBIs, Bugs, and existing test cases. |
|
|
174
173
|
| `fetch_feature_hierarchy` | Fetch a Feature and all child PBIs/Bugs with acceptance criteria and existing attachments. |
|
|
175
174
|
| `fetch_work_item_for_gherkin` | Fetch a PBI or Bug with parent Feature context, suggested file name, and linked test case steps. |
|
|
176
175
|
| `attach_gherkin_to_feature` | Validate and attach a `.feature` file to a Feature work item. |
|
|
@@ -331,7 +330,7 @@ and refreshed automatically for ~60 days — no re-prompting.
|
|
|
331
330
|
| Step | Azure DevOps | Jira Cloud |
|
|
332
331
|
|---|---|---|
|
|
333
332
|
| Fetch issue | `fetch_work_item` | `fetch_jira_issue` |
|
|
334
|
-
| Fetch Epic hierarchy |
|
|
333
|
+
| Fetch Epic hierarchy | ⛔ Not supported — warn user | ⛔ Not supported — warn user |
|
|
335
334
|
| Check for duplicates | `get_linked_test_cases` | `get_linked_test_cases` |
|
|
336
335
|
| Create & link test cases | `create_and_link_test_cases` | `create_and_link_test_cases` |
|
|
337
336
|
| Generate Gherkin | `fetch_work_item_for_gherkin` → `attach_gherkin_to_work_item` | `qa-gherkin-generator` with Jira issue AC (save locally or attach to Jira) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qa-gentic/stlc-agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "QA STLC Agents — five MCP servers + skills for AI-powered test case, Gherkin, Playwright generation, and Helix-QA file writing against Azure DevOps and Jira Cloud. Full pipeline for both: fetch → test cases → Gherkin → Playwright → Helix-QA. Works with Claude Code, GitHub Copilot, Cursor, Windsurf.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|
package/skills/AGENT-BEHAVIOR.md
CHANGED
|
@@ -229,25 +229,18 @@ OUTPUT: .feature file attached to PBI/Bug work item (or shown inline)
|
|
|
229
229
|
```
|
|
230
230
|
INPUT: Epic ID + org URL + project name
|
|
231
231
|
│
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
│ ├─ [ASK: "Attach .feature to Feature #{child_id}?"]
|
|
245
|
-
│ └─ yes → attach_gherkin_to_feature(child_id)
|
|
246
|
-
│
|
|
247
|
-
└─ [NEVER call create_and_link_test_cases on the Epic ID]
|
|
248
|
-
|
|
249
|
-
OUTPUT: one .feature file per child Feature
|
|
250
|
-
test cases NOT created unless user explicitly asks for child Feature/PBI coverage
|
|
232
|
+
└─ DO NOT call any fetch tool.
|
|
233
|
+
Respond immediately with:
|
|
234
|
+
"Epic-scoped Gherkin generation is not supported. An Epic spans multiple Features
|
|
235
|
+
and would produce files that are too large and unfocused to be useful.
|
|
236
|
+
|
|
237
|
+
Please provide one of the following instead:
|
|
238
|
+
• A Feature ID — I will generate 5–10 scenarios covering all child PBIs
|
|
239
|
+
• A PBI or Bug ID — I will generate 3–9 scenarios scoped to that work item
|
|
240
|
+
|
|
241
|
+
To find the child Features under this Epic, look up the work item in Azure DevOps
|
|
242
|
+
and note the Feature IDs, then share them with me."
|
|
243
|
+
Wait for the user to provide a Feature or PBI/Bug ID. Do not proceed.
|
|
251
244
|
```
|
|
252
245
|
|
|
253
246
|
### Chain E — Playwright TypeScript from Gherkin
|
|
@@ -322,7 +315,7 @@ User provides work item ID
|
|
|
322
315
|
│
|
|
323
316
|
▼
|
|
324
317
|
Call the fetch tool for the intended operation
|
|
325
|
-
(fetch_work_item
|
|
318
|
+
(fetch_work_item or fetch_work_item_for_gherkin)
|
|
326
319
|
│
|
|
327
320
|
▼
|
|
328
321
|
Read work_item_type from response
|
|
@@ -332,8 +325,8 @@ User provides work item ID
|
|
|
332
325
|
"Epic" not "Epic"
|
|
333
326
|
│ │
|
|
334
327
|
▼ ┌─────┴────────┐
|
|
335
|
-
HARD STOP
|
|
336
|
-
|
|
328
|
+
HARD STOP — warn user to provide "Feature" "PBI"/"Bug"
|
|
329
|
+
a Feature or PBI/Bug ID instead │ │
|
|
337
330
|
Never call create_and_link_test_cases │ │
|
|
338
331
|
Never call attach_code_to_work_item │ │
|
|
339
332
|
on the Epic ID Feature path PBI/Bug path
|
|
@@ -122,6 +122,53 @@ From the feature hierarchy response, check for:
|
|
|
122
122
|
> If you cannot read an attachment's content, treat it as fully covering its domain and
|
|
123
123
|
> produce NO new file of that type unless you can prove a gap.
|
|
124
124
|
|
|
125
|
+
### 1E — Helix step-pattern scan (mandatory before generating any step definitions)
|
|
126
|
+
|
|
127
|
+
ADO attachments only cover files explicitly uploaded. The Helix-QA project on disk contains
|
|
128
|
+
all currently registered step definitions — many of which are **never attached to ADO** but
|
|
129
|
+
will be active at runtime because `cucumber.js` loads them via `src/test/steps/**/*.ts`.
|
|
130
|
+
|
|
131
|
+
Generating a new step that duplicates an existing Helix step causes an
|
|
132
|
+
`Ambiguous step definition` runtime error, even if the ADO dedup scan found nothing.
|
|
133
|
+
|
|
134
|
+
**Procedure — run every time before writing any `*.steps.ts`:**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
1. qa-helix-writer:list_helix_tree(helix_root)
|
|
138
|
+
→ collect all paths matching src/test/steps/*.steps.ts
|
|
139
|
+
|
|
140
|
+
2. For each path found:
|
|
141
|
+
qa-helix-writer:read_helix_file(helix_root, path)
|
|
142
|
+
→ extract all step pattern strings (Given/When/Then/And/But)
|
|
143
|
+
→ extract all Before/After hook tags
|
|
144
|
+
→ add to CACHE[id].existing_attachments.steps_files[]
|
|
145
|
+
|
|
146
|
+
3. For each path matching src/test/features/*.feature:
|
|
147
|
+
qa-helix-writer:read_helix_file(helix_root, path)
|
|
148
|
+
→ extract the Background step strings verbatim
|
|
149
|
+
→ add to CACHE[id].existing_attachments.background_steps[]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Background reuse rule:** If a Background in a new feature file can be expressed entirely
|
|
153
|
+
using step patterns already registered in any existing `*.steps.ts`, you **must** use the
|
|
154
|
+
exact registered wording — do NOT generate new step strings for the same intent.
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
# ✅ Correct — reuses registered pattern from reset-app-state.steps.ts
|
|
158
|
+
Background:
|
|
159
|
+
Given the user is logged in as "standard_user"
|
|
160
|
+
And the user is on the inventory page
|
|
161
|
+
|
|
162
|
+
# ❌ Wrong — generates duplicate steps that cause Ambiguous step definition
|
|
163
|
+
Background:
|
|
164
|
+
Given I am on the SauceDemo login page at "https://www.saucedemo.com/"
|
|
165
|
+
And I log in with username "standard_user" and password "secret_sauce"
|
|
166
|
+
And I am on the inventory page at "https://www.saucedemo.com/inventory.html"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
> This scan is **not optional for Jira pipelines either**. If the Helix project is present,
|
|
170
|
+
> always perform step 1E before writing steps, regardless of the work item source.
|
|
171
|
+
|
|
125
172
|
---
|
|
126
173
|
|
|
127
174
|
## PHASE 2 — DIFF Using Semantic Matching
|
|
@@ -163,7 +210,7 @@ For each proposed Gherkin scenario:
|
|
|
163
210
|
|
|
164
211
|
- `locators.ts`: only emit keys not already in existing file; if delta empty → skip; if non-empty → attach as `locators.delta.ts`
|
|
165
212
|
- `*Page.ts`: only emit methods not already present; if delta empty → skip; if non-empty → attach as `*Page.delta.ts`
|
|
166
|
-
- `*.steps.ts`: only emit step strings
|
|
213
|
+
- `*.steps.ts`: cross-check every proposed step pattern against **both** ADO attachment step strings (1D) **and** Helix on-disk step strings (1E); only emit step strings that appear in neither; NEVER re-register an existing step (causes `Ambiguous step definition` runtime error); reuse exact registered wording in Background blocks
|
|
167
214
|
|
|
168
215
|
---
|
|
169
216
|
|
|
@@ -211,7 +258,7 @@ Output after every run regardless of whether anything was created:
|
|
|
211
258
|
|
|
212
259
|
1. **NEVER call `create_and_link_test_cases` without first calling `get_linked_test_cases`** on the same work item.
|
|
213
260
|
2. **NEVER attach a `.feature` file without first checking for existing feature file attachments.**
|
|
214
|
-
3. **NEVER attach a `steps.ts` that re-registers an existing step string** — causes `Ambiguous step definition` at runtime.
|
|
261
|
+
3. **NEVER attach a `steps.ts` that re-registers an existing step string** — causes `Ambiguous step definition` at runtime. Perform the Helix step-pattern scan (Phase 1E) before writing any step definition. ADO attachment checks alone are insufficient because most Helix step files are never attached to ADO.
|
|
215
262
|
4. **NEVER treat tag differences as meaningful.** `[REGRESSION] Export List downloads CSV` is a duplicate of `[SMOKE] Clicking Export List downloads a valid CSV file`.
|
|
216
263
|
5. **NEVER create more than one test case covering the same (subject, condition) pair.**
|
|
217
264
|
6. **NEVER skip this protocol because the work item appears new.** `existing_test_cases_count: 0` in the hierarchy can still have cases via `get_linked_test_cases` — always call both.
|
|
@@ -252,7 +299,8 @@ CACHE[work_item_id] = {
|
|
|
252
299
|
feature_files: [{ name, content }],
|
|
253
300
|
locators_ts: { found: bool, keys: [] },
|
|
254
301
|
page_objects: [{ name, methods: [] }],
|
|
255
|
-
steps_files: [{ name, step_strings: [] }],
|
|
302
|
+
steps_files: [{ name, step_strings: [] }], # populated from BOTH 1D (ADO attachments) AND 1E (Helix on-disk read)
|
|
303
|
+
background_steps: [], # exact step strings from existing Helix *.feature Background blocks — new Backgrounds must reuse these
|
|
256
304
|
},
|
|
257
305
|
gap_check_completed: bool, # set true after generate-gherkin Step 2 passes
|
|
258
306
|
phase1_completed: true,
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Use when generating Gherkin feature files, BDD scenarios, or .feature files from Azure DevOps
|
|
5
5
|
or Jira work items. Triggers on: "Gherkin", "feature file", "BDD", "scenarios", "acceptance
|
|
6
6
|
criteria automation", "Given When Then", "regression suite". Enforces live navigation before
|
|
7
|
-
writing any scenario and links generated files back to work items. Works with
|
|
7
|
+
writing any scenario and links generated files back to work items. Works with Feature,
|
|
8
8
|
PBI, and Bug work item types.
|
|
9
9
|
license: MIT
|
|
10
10
|
compatibility: "Requires qa-gherkin-generator, qa-playwright-generator, qa-test-case-manager MCP servers and Playwright MCP running at localhost:8931 for live locator verification."
|
|
@@ -60,7 +60,7 @@ work items in ADO.**
|
|
|
60
60
|
|
|
61
61
|
| ID type given by user | Goal | Fetch tool | Attach tool | Scope |
|
|
62
62
|
|---|---|---|---|---|
|
|
63
|
-
| **Epic ID** |
|
|
63
|
+
| **Epic ID** | ⛔ Not supported — warn user | — | — | — |
|
|
64
64
|
| **Feature ID** | Full regression suite across all child PBIs | `fetch_feature_hierarchy` | `attach_gherkin_to_feature` | 5–10 scenarios |
|
|
65
65
|
| **PBI or Bug ID** | Scoped file for that single story in the current sprint | `fetch_work_item_for_gherkin` | `attach_gherkin_to_work_item` | 3–9 scenarios |
|
|
66
66
|
|
|
@@ -68,15 +68,19 @@ work items in ADO.**
|
|
|
68
68
|
|
|
69
69
|
```
|
|
70
70
|
if user_input contains an Epic ID:
|
|
71
|
-
→
|
|
72
|
-
→
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
→ DO NOT call any fetch tool.
|
|
72
|
+
→ Respond immediately with:
|
|
73
|
+
"Epic-scoped Gherkin generation is not supported. An Epic spans multiple Features
|
|
74
|
+
and would produce files that are too large and unfocused to be useful as a
|
|
75
|
+
regression suite.
|
|
76
|
+
|
|
77
|
+
Please provide one of the following instead:
|
|
78
|
+
• A Feature ID — I will generate 5–10 scenarios covering all child PBIs
|
|
79
|
+
• A PBI or Bug ID — I will generate 3–9 scenarios scoped to that work item
|
|
80
|
+
|
|
81
|
+
To find the child Features under this Epic, look up the work item in Azure DevOps
|
|
82
|
+
and note the Feature IDs, then share them with me."
|
|
83
|
+
→ Wait for the user to provide a Feature or PBI/Bug ID. Do not proceed.
|
|
80
84
|
|
|
81
85
|
if user_input contains a Feature ID:
|
|
82
86
|
→ use fetch_feature_hierarchy + attach_gherkin_to_feature
|
|
@@ -93,12 +97,6 @@ if ambiguous (no ID, just a title or description):
|
|
|
93
97
|
→ do not guess or default to either path
|
|
94
98
|
```
|
|
95
99
|
|
|
96
|
-
When using the **Epic path**, `fetch_epic_hierarchy` returns a `features` list where each
|
|
97
|
-
entry contains the Feature's metadata plus its `child_work_items` (PBIs/Bugs) and
|
|
98
|
-
`existing_test_cases`. **Read every Feature and every child PBI/Bug in this list** before
|
|
99
|
-
writing a single scenario — the full cross-Feature flow is the only correct input for an
|
|
100
|
-
Epic-scope suite.
|
|
101
|
-
|
|
102
100
|
When using the **PBI/Bug path**, `fetch_work_item_for_gherkin` returns `parent_feature`
|
|
103
101
|
metadata. Use it for context when writing scenarios — but the generated file covers **only
|
|
104
102
|
the PBI/Bug's own acceptance criteria**, not the full Feature. The file is attached to the
|
|
@@ -153,19 +151,6 @@ A single work item never tells the whole story.
|
|
|
153
151
|
|
|
154
152
|
**1A — Route to the correct fetch tool (see Tool Routing above):**
|
|
155
153
|
|
|
156
|
-
*Epic path (ALWAYS use when an Epic ID is provided):*
|
|
157
|
-
```
|
|
158
|
-
qa-gherkin-generator:fetch_epic_hierarchy(
|
|
159
|
-
epic_id : <Epic ID>
|
|
160
|
-
organization_url : ...
|
|
161
|
-
project_name : ...
|
|
162
|
-
)
|
|
163
|
-
```
|
|
164
|
-
Extract: epic title/description, **all child Features**, each Feature's child PBIs/Bugs
|
|
165
|
-
with their ACs, and all existing test cases. Analyse the ENTIRE hierarchy — every Feature
|
|
166
|
-
and every PBI/Bug — before writing a single scenario. Generate one .feature file per
|
|
167
|
-
child Feature.
|
|
168
|
-
|
|
169
154
|
*Feature path:*
|
|
170
155
|
```
|
|
171
156
|
qa-gherkin-generator:fetch_feature_hierarchy(
|
|
@@ -197,15 +197,11 @@ that document — do not carry over the Gherkin attachment confirmation.
|
|
|
197
197
|
|
|
198
198
|
## Quality Gates — Do Not Attach Without These
|
|
199
199
|
|
|
200
|
-
- [ ] Work item type identified — **correct tool-routing path selected** (
|
|
201
|
-
- [ ] **Epic path**: `fetch_epic_hierarchy` called — NOT `fetch_feature_hierarchy` or `fetch_work_item_for_gherkin`
|
|
202
|
-
- [ ] **Epic path**: ALL child Features and ALL child PBIs/Bugs read and analysed before any Gherkin written
|
|
203
|
-
- [ ] **Epic path**: One .feature file generated per child Feature (not one file for the whole Epic)
|
|
204
|
-
- [ ] **Epic path**: `create_and_link_test_cases` NOT called on the Epic ID — user informed that test cases are scoped to Features/PBIs/Bugs only
|
|
200
|
+
- [ ] Work item type identified — **correct tool-routing path selected** (Feature vs PBI/Bug)
|
|
205
201
|
- [ ] **Feature path**: `fetch_feature_hierarchy` called — all child PBIs/Bugs reviewed
|
|
206
202
|
- [ ] **Feature path**: User confirmation received before calling `create_and_link_test_cases`
|
|
207
203
|
- [ ] **PBI/Bug path**: `fetch_work_item_for_gherkin` called — parent Feature context reviewed
|
|
208
|
-
- [ ] Correct fetch tool called: `
|
|
204
|
+
- [ ] Correct fetch tool called: `fetch_feature_hierarchy` for Feature, `fetch_work_item_for_gherkin` for PBI/Bug
|
|
209
205
|
- [ ] Parent Feature hierarchy context reviewed — all active sibling PBIs/Bugs read and flow map built
|
|
210
206
|
- [ ] Gap check (Step 2) completed — every G1–G7 gap type checked
|
|
211
207
|
- [ ] **All gaps answered by user before any Gherkin was written** (or explicit sign-off obtained)
|
|
@@ -218,7 +218,15 @@ qa-playwright-generator:generate_playwright_code(
|
|
|
218
218
|
)
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
The
|
|
221
|
+
The response contains `cache_key`, `files_manifest` (list of file paths), and `validation`. File
|
|
222
|
+
contents are held server-side to keep them out of conversation history. Retrieve them only when
|
|
223
|
+
you are about to attach or write to disk:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
qa-playwright-generator:get_generated_files(cache_key: "<cache_key from above>")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The four generated files are:
|
|
222
230
|
- `locators.ts` — selector registry with intent, stability score, visualIntent flag
|
|
223
231
|
- `{ScreenName}Page.ts` — three-layer self-healing page object
|
|
224
232
|
- `{feature}.steps.ts` — Cucumber step definitions
|
|
@@ -264,17 +272,21 @@ Note:
|
|
|
264
272
|
|
|
265
273
|
**Do not call `attach_code_to_work_item` until the user replies "yes".**
|
|
266
274
|
|
|
267
|
-
If user says "yes",
|
|
275
|
+
If user says "yes", first retrieve the file contents then attach:
|
|
268
276
|
|
|
269
277
|
```
|
|
278
|
+
# 1 — Retrieve file contents from cache
|
|
279
|
+
qa-playwright-generator:get_generated_files(cache_key: "<cache_key>")
|
|
280
|
+
|
|
281
|
+
# 2 — Attach delta files only
|
|
270
282
|
qa-playwright-generator:attach_code_to_work_item(
|
|
271
283
|
organization_url : "<org_url>",
|
|
272
284
|
project_name : "<project>",
|
|
273
285
|
work_item_id : <id>,
|
|
274
286
|
files : [
|
|
275
|
-
{ file_name: "locators.delta.ts", content: "
|
|
276
|
-
{ file_name: "{ScreenName}Page.delta.ts", content: "
|
|
277
|
-
{ file_name: "{feature}.steps.delta.ts", content: "
|
|
287
|
+
{ file_name: "locators.delta.ts", content: "<from get_generated_files>" },
|
|
288
|
+
{ file_name: "{ScreenName}Page.delta.ts", content: "<from get_generated_files>" },
|
|
289
|
+
{ file_name: "{feature}.steps.delta.ts", content: "<from get_generated_files>" }
|
|
278
290
|
]
|
|
279
291
|
)
|
|
280
292
|
```
|
|
@@ -289,123 +301,8 @@ Helix-QA disk writes are a separate decision requiring a separate user request.
|
|
|
289
301
|
|
|
290
302
|
## Generated File Structures
|
|
291
303
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
/**
|
|
296
|
-
* Locators: <ScreenName>Page
|
|
297
|
-
* SOURCE: Playwright MCP AX tree snapshot — <app-url>/<route>
|
|
298
|
-
* Stability: data-testid(100) > role+name(90) > id(80) > aria-label(70) > placeholder(60)
|
|
299
|
-
* ⚠ stability:0 entries were NOT reached in the live session — get user sign-off before using.
|
|
300
|
-
*/
|
|
301
|
-
export const <ScreenName>Locators = {
|
|
302
|
-
// stability: 100 — data-testid, survives refactors
|
|
303
|
-
addUsersButton: {
|
|
304
|
-
selector : "[data-testid='person_header-button-add_users']",
|
|
305
|
-
intent : "Add Users button that opens the slide-out panel",
|
|
306
|
-
stability : 100,
|
|
307
|
-
},
|
|
308
|
-
// stability: 90 — aria-role+name, visualIntent: screenshot at assertions
|
|
309
|
-
exportListButton: {
|
|
310
|
-
selector : "button:has-text('Export List')",
|
|
311
|
-
intent : "Export List button on the failure summary screen",
|
|
312
|
-
stability : 90,
|
|
313
|
-
visualIntent : true,
|
|
314
|
-
},
|
|
315
|
-
// ⚠ stability: 0 — NOT VERIFIED: could not reach this screen (reason: <why>)
|
|
316
|
-
// Get user sign-off before using in automation.
|
|
317
|
-
someUnreachedElement: {
|
|
318
|
-
selector : "[data-testid='TODO']",
|
|
319
|
-
intent : "...",
|
|
320
|
-
stability : 0,
|
|
321
|
-
},
|
|
322
|
-
} as const;
|
|
323
|
-
|
|
324
|
-
export type LocatorKey = keyof typeof <ScreenName>Locators;
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### {ScreenName}Page.ts
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
import { Page, expect, Download } from '@playwright/test';
|
|
331
|
-
import { fixture } from '@hooks/pageFixture';
|
|
332
|
-
import { <ScreenName>Locators } from './locators';
|
|
333
|
-
import { LocatorHealer } from '@utils/locators/LocatorHealer';
|
|
334
|
-
import { LocatorRepository } from '@utils/locators/LocatorRepository';
|
|
335
|
-
import { VisualIntentChecker } from '@utils/locators/VisualIntentChecker';
|
|
336
|
-
import { TimingHealer } from '@utils/locators/TimingHealer';
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* <ScreenName>Page — Three-Layer Self-Healing Page Object
|
|
340
|
-
* Layer 1 (LocatorHealer): primary → role → label → text → AI Vision → AX tree
|
|
341
|
-
* Layer 2 (TimingHealer): network-trace drift → auto-adjusted timeouts
|
|
342
|
-
* Layer 3 (VisualIntentChecker): element screenshot diff at key assertions
|
|
343
|
-
* HealingDashboard: http://localhost:7890
|
|
344
|
-
* RULE: Never use page.click / page.fill / page.locator directly.
|
|
345
|
-
*/
|
|
346
|
-
export default class <ScreenName>Page {
|
|
347
|
-
private readonly loc = <ScreenName>Locators;
|
|
348
|
-
private readonly page: Page;
|
|
349
|
-
private readonly healer: LocatorHealer;
|
|
350
|
-
private readonly repo: LocatorRepository;
|
|
351
|
-
private readonly visual: VisualIntentChecker;
|
|
352
|
-
private readonly timing: TimingHealer;
|
|
353
|
-
|
|
354
|
-
constructor(page?: Page) {
|
|
355
|
-
this.page = page ?? fixture().page;
|
|
356
|
-
this.repo = fixture().locatorRepository ?? new LocatorRepository();
|
|
357
|
-
this.healer = new LocatorHealer(this.page, fixture().logger, this.repo);
|
|
358
|
-
this.visual = new VisualIntentChecker(this.page, fixture().logger, this.repo);
|
|
359
|
-
this.timing = new TimingHealer(this.page, fixture().logger, this.repo);
|
|
360
|
-
Object.entries(this.loc).forEach(([k, v]) => this.repo.register(k, v.selector, v.intent));
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
async login(email: string, password: string): Promise<void> {
|
|
364
|
-
await this.page.goto(process.env.APP_BASE_URL!, { waitUntil: 'networkidle' });
|
|
365
|
-
await this.healer.fillWithHealing('emailInput', this.loc.emailInput.selector, email, this.loc.emailInput.intent);
|
|
366
|
-
await this.healer.fillWithHealing('passwordInput', this.loc.passwordInput.selector, password, this.loc.passwordInput.intent);
|
|
367
|
-
await this.healer.clickWithHealing('loginButton', this.loc.loginButton.selector, this.loc.loginButton.intent);
|
|
368
|
-
await this.timing.waitForNetworkIdle('login');
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// All interactions go through LocatorHealer — never raw page.click / page.fill
|
|
372
|
-
}
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
### {feature}.steps.ts
|
|
376
|
-
|
|
377
|
-
```typescript
|
|
378
|
-
import { Given, When, Then, Before } from '@cucumber/cucumber';
|
|
379
|
-
import { expect } from '@playwright/test';
|
|
380
|
-
import { fixture } from '@hooks/pageFixture';
|
|
381
|
-
import <ScreenName>Page from '@pages/<screenName>/<ScreenName>Page';
|
|
382
|
-
|
|
383
|
-
let page_: <ScreenName>Page;
|
|
384
|
-
|
|
385
|
-
Before(async () => { page_ = new <ScreenName>Page(fixture().page); });
|
|
386
|
-
|
|
387
|
-
Given('I am logged in to {word} as {string}', async (_app: string, email: string) => {
|
|
388
|
-
await page_.login(email, process.env.APP_PASSWORD!);
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
// Only net-new steps — never re-register steps already in existing files
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
## Run Commands
|
|
397
|
-
|
|
398
|
-
```bash
|
|
399
|
-
ENABLE_SELF_HEALING=true \
|
|
400
|
-
HEALING_DASHBOARD_PORT=7890 \
|
|
401
|
-
APP_BASE_URL=https://account.myamplify.io \
|
|
402
|
-
APP_EMAIL=<email> \
|
|
403
|
-
APP_PASSWORD=<password> \
|
|
404
|
-
cucumber-js --config=config/cucumber.js -p <feature_profile>
|
|
405
|
-
|
|
406
|
-
# Smoke only:
|
|
407
|
-
cucumber-js --config=config/cucumber.js -p <feature_profile> --tags "@smoke"
|
|
408
|
-
```
|
|
304
|
+
For TypeScript code templates and run commands, see
|
|
305
|
+
[references/file-structures.md](references/file-structures.md).
|
|
409
306
|
|
|
410
307
|
---
|
|
411
308
|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Generated File Structures — Reference
|
|
2
|
+
|
|
3
|
+
Read this file when you need to understand the exact TypeScript output format or
|
|
4
|
+
run commands. It is not loaded into context automatically.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## locators.ts
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
/**
|
|
12
|
+
* Locators: <ScreenName>Page
|
|
13
|
+
* SOURCE: Playwright MCP AX tree snapshot — <app-url>/<route>
|
|
14
|
+
* Stability: data-testid(100) > role+name(90) > id(80) > aria-label(70) > placeholder(60)
|
|
15
|
+
* ⚠ stability:0 entries were NOT reached in the live session — get user sign-off before using.
|
|
16
|
+
*/
|
|
17
|
+
export const <ScreenName>Locators = {
|
|
18
|
+
// stability: 100 — data-testid, survives refactors
|
|
19
|
+
addUsersButton: {
|
|
20
|
+
selector : "[data-testid='person_header-button-add_users']",
|
|
21
|
+
intent : "Add Users button that opens the slide-out panel",
|
|
22
|
+
stability : 100,
|
|
23
|
+
},
|
|
24
|
+
// stability: 90 — aria-role+name, visualIntent: screenshot at assertions
|
|
25
|
+
exportListButton: {
|
|
26
|
+
selector : "button:has-text('Export List')",
|
|
27
|
+
intent : "Export List button on the failure summary screen",
|
|
28
|
+
stability : 90,
|
|
29
|
+
visualIntent : true,
|
|
30
|
+
},
|
|
31
|
+
// ⚠ stability: 0 — NOT VERIFIED: could not reach this screen (reason: <why>)
|
|
32
|
+
// Get user sign-off before using in automation.
|
|
33
|
+
someUnreachedElement: {
|
|
34
|
+
selector : "[data-testid='TODO']",
|
|
35
|
+
intent : "...",
|
|
36
|
+
stability : 0,
|
|
37
|
+
},
|
|
38
|
+
} as const;
|
|
39
|
+
|
|
40
|
+
export type LocatorKey = keyof typeof <ScreenName>Locators;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## {ScreenName}Page.ts
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { Page, expect, Download } from '@playwright/test';
|
|
49
|
+
import { fixture } from '@hooks/pageFixture';
|
|
50
|
+
import { <ScreenName>Locators } from './locators';
|
|
51
|
+
import { LocatorHealer } from '@utils/locators/LocatorHealer';
|
|
52
|
+
import { LocatorRepository } from '@utils/locators/LocatorRepository';
|
|
53
|
+
import { VisualIntentChecker } from '@utils/locators/VisualIntentChecker';
|
|
54
|
+
import { TimingHealer } from '@utils/locators/TimingHealer';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* <ScreenName>Page — Three-Layer Self-Healing Page Object
|
|
58
|
+
* Layer 1 (LocatorHealer): primary → role → label → text → AI Vision → AX tree
|
|
59
|
+
* Layer 2 (TimingHealer): network-trace drift → auto-adjusted timeouts
|
|
60
|
+
* Layer 3 (VisualIntentChecker): element screenshot diff at key assertions
|
|
61
|
+
* HealingDashboard: http://localhost:7890
|
|
62
|
+
* RULE: Never use page.click / page.fill / page.locator directly.
|
|
63
|
+
*/
|
|
64
|
+
export default class <ScreenName>Page {
|
|
65
|
+
private readonly loc = <ScreenName>Locators;
|
|
66
|
+
private readonly page: Page;
|
|
67
|
+
private readonly healer: LocatorHealer;
|
|
68
|
+
private readonly repo: LocatorRepository;
|
|
69
|
+
private readonly visual: VisualIntentChecker;
|
|
70
|
+
private readonly timing: TimingHealer;
|
|
71
|
+
|
|
72
|
+
constructor(page?: Page) {
|
|
73
|
+
this.page = page ?? fixture().page;
|
|
74
|
+
this.repo = fixture().locatorRepository ?? new LocatorRepository();
|
|
75
|
+
this.healer = new LocatorHealer(this.page, fixture().logger, this.repo);
|
|
76
|
+
this.visual = new VisualIntentChecker(this.page, fixture().logger, this.repo);
|
|
77
|
+
this.timing = new TimingHealer(this.page, fixture().logger, this.repo);
|
|
78
|
+
Object.entries(this.loc).forEach(([k, v]) => this.repo.register(k, v.selector, v.intent));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async login(email: string, password: string): Promise<void> {
|
|
82
|
+
await this.page.goto(process.env.APP_BASE_URL!, { waitUntil: 'networkidle' });
|
|
83
|
+
await this.healer.fillWithHealing('emailInput', this.loc.emailInput.selector, email, this.loc.emailInput.intent);
|
|
84
|
+
await this.healer.fillWithHealing('passwordInput', this.loc.passwordInput.selector, password, this.loc.passwordInput.intent);
|
|
85
|
+
await this.healer.clickWithHealing('loginButton', this.loc.loginButton.selector, this.loc.loginButton.intent);
|
|
86
|
+
await this.timing.waitForNetworkIdle('login');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// All interactions go through LocatorHealer — never raw page.click / page.fill
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## {feature}.steps.ts
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { Given, When, Then, Before } from '@cucumber/cucumber';
|
|
99
|
+
import { expect } from '@playwright/test';
|
|
100
|
+
import { fixture } from '@hooks/pageFixture';
|
|
101
|
+
import <ScreenName>Page from '@pages/<screenName>/<ScreenName>Page';
|
|
102
|
+
|
|
103
|
+
let page_: <ScreenName>Page;
|
|
104
|
+
|
|
105
|
+
Before(async () => { page_ = new <ScreenName>Page(fixture().page); });
|
|
106
|
+
|
|
107
|
+
Given('I am logged in to {word} as {string}', async (_app: string, email: string) => {
|
|
108
|
+
await page_.login(email, process.env.APP_PASSWORD!);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Only net-new steps — never re-register steps already in existing files
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Run Commands
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
ENABLE_SELF_HEALING=true \
|
|
120
|
+
HEALING_DASHBOARD_PORT=7890 \
|
|
121
|
+
APP_BASE_URL=https://account.myamplify.io \
|
|
122
|
+
APP_EMAIL=<email> \
|
|
123
|
+
APP_PASSWORD=<password> \
|
|
124
|
+
cucumber-js --config=config/cucumber.js -p <feature_profile>
|
|
125
|
+
|
|
126
|
+
# Smoke only:
|
|
127
|
+
cucumber-js --config=config/cucumber.js -p <feature_profile> --tags "@smoke"
|
|
128
|
+
```
|
|
@@ -35,8 +35,8 @@ If the user provides an Epic ID and asks for test cases:
|
|
|
35
35
|
- Inform the user explicitly:
|
|
36
36
|
> "Manual test cases cannot be created or linked to an Epic in ADO.
|
|
37
37
|
> Test cases must be attached to individual Features, PBIs, or Bugs.
|
|
38
|
-
>
|
|
39
|
-
>
|
|
38
|
+
> Please look up the child Features of this Epic in Azure DevOps, then share
|
|
39
|
+
> the Feature or PBI/Bug IDs and I will create test cases for each."
|
|
40
40
|
- Do NOT call `create_and_link_test_cases` with an Epic ID under any circumstances.
|
|
41
41
|
|
|
42
42
|
**HARD STOP 2 — Always ask for user confirmation before creating test cases for a Feature.**
|
|
@@ -200,10 +200,18 @@ qa-playwright-generator:generate_playwright_code(
|
|
|
200
200
|
|
|
201
201
|
### Step 6 — Write files
|
|
202
202
|
|
|
203
|
+
First retrieve the file contents from the playwright generator's cache:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
qa-playwright-generator:get_generated_files(cache_key: "<cache_key from Step 5>")
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Then write to Helix:
|
|
210
|
+
|
|
203
211
|
```
|
|
204
212
|
qa-helix-writer:write_helix_files(
|
|
205
213
|
helix_root = "<helix_root>",
|
|
206
|
-
files = <files dict from
|
|
214
|
+
files = <files dict from get_generated_files>,
|
|
207
215
|
mode = "<recommendation from Step 2>"
|
|
208
216
|
)
|
|
209
217
|
```
|
|
@@ -318,8 +326,9 @@ Before calling `write_helix_files`:
|
|
|
318
326
|
- [ ] Every `*.steps.ts` in the `files` dict uses Cucumber expression syntax (not regex).
|
|
319
327
|
- [ ] `mode` matches `recommendation` — never override without user instruction.
|
|
320
328
|
- [ ] `force_scaffold` is `false` unless the user explicitly asked to regenerate.
|
|
321
|
-
- [ ] The `files` dict comes
|
|
322
|
-
`
|
|
329
|
+
- [ ] The `files` dict comes from `get_generated_files(cache_key)` — never manually
|
|
330
|
+
constructed. `generate_playwright_code` and `scaffold_locator_repository` return
|
|
331
|
+
a `cache_key`; call `get_generated_files` to retrieve file contents.
|
|
323
332
|
- [ ] After writing, the `deduplication` field has been reviewed and reported.
|
|
324
333
|
|
|
325
334
|
---
|
|
Binary file
|
|
Binary file
|