qaa-agent 1.6.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.mcp.json +8 -8
  2. package/CHANGELOG.md +93 -71
  3. package/CLAUDE.md +553 -553
  4. package/agents/qa-pipeline-orchestrator.md +1378 -1378
  5. package/agents/qaa-analyzer.md +539 -524
  6. package/agents/qaa-bug-detective.md +479 -446
  7. package/agents/qaa-codebase-mapper.md +935 -935
  8. package/agents/qaa-discovery.md +384 -0
  9. package/agents/qaa-e2e-runner.md +416 -415
  10. package/agents/qaa-executor.md +651 -651
  11. package/agents/qaa-planner.md +405 -390
  12. package/agents/qaa-project-researcher.md +319 -319
  13. package/agents/qaa-scanner.md +424 -424
  14. package/agents/qaa-testid-injector.md +643 -585
  15. package/agents/qaa-validator.md +490 -452
  16. package/bin/install.cjs +200 -198
  17. package/bin/lib/commands.cjs +709 -709
  18. package/bin/lib/config.cjs +307 -307
  19. package/bin/lib/core.cjs +497 -497
  20. package/bin/lib/frontmatter.cjs +299 -299
  21. package/bin/lib/init.cjs +989 -989
  22. package/bin/lib/milestone.cjs +241 -241
  23. package/bin/lib/model-profiles.cjs +60 -60
  24. package/bin/lib/phase.cjs +911 -911
  25. package/bin/lib/roadmap.cjs +306 -306
  26. package/bin/lib/state.cjs +748 -748
  27. package/bin/lib/template.cjs +222 -222
  28. package/bin/lib/verify.cjs +842 -842
  29. package/bin/qaa-tools.cjs +607 -607
  30. package/commands/qa-audit.md +119 -0
  31. package/commands/qa-create-test.md +288 -0
  32. package/commands/qa-fix.md +147 -0
  33. package/commands/qa-map.md +137 -0
  34. package/{.claude/commands → commands}/qa-pr.md +23 -23
  35. package/{.claude/commands → commands}/qa-start.md +22 -22
  36. package/{.claude/commands → commands}/qa-testid.md +19 -19
  37. package/docs/COMMANDS.md +341 -341
  38. package/docs/DEMO.md +182 -182
  39. package/docs/TESTING.md +156 -156
  40. package/package.json +6 -7
  41. package/{.claude/settings.json → settings.json} +1 -2
  42. package/templates/failure-classification.md +391 -391
  43. package/templates/gap-analysis.md +409 -409
  44. package/templates/pr-template.md +48 -48
  45. package/templates/qa-analysis.md +381 -381
  46. package/templates/qa-audit-report.md +465 -465
  47. package/templates/qa-repo-blueprint.md +636 -636
  48. package/templates/scan-manifest.md +312 -312
  49. package/templates/test-inventory.md +582 -582
  50. package/templates/testid-audit-report.md +354 -354
  51. package/templates/validation-report.md +243 -243
  52. package/workflows/qa-analyze.md +296 -296
  53. package/workflows/qa-from-ticket.md +536 -536
  54. package/workflows/qa-gap.md +309 -303
  55. package/workflows/qa-pr.md +389 -389
  56. package/workflows/qa-start.md +1192 -1168
  57. package/workflows/qa-testid.md +384 -356
  58. package/workflows/qa-validate.md +299 -295
  59. package/.claude/commands/create-test.md +0 -164
  60. package/.claude/commands/qa-audit.md +0 -37
  61. package/.claude/commands/qa-blueprint.md +0 -54
  62. package/.claude/commands/qa-fix.md +0 -36
  63. package/.claude/commands/qa-from-ticket.md +0 -24
  64. package/.claude/commands/qa-gap.md +0 -20
  65. package/.claude/commands/qa-map.md +0 -47
  66. package/.claude/commands/qa-pom.md +0 -36
  67. package/.claude/commands/qa-pyramid.md +0 -37
  68. package/.claude/commands/qa-report.md +0 -38
  69. package/.claude/commands/qa-research.md +0 -33
  70. package/.claude/commands/qa-validate.md +0 -42
  71. package/.claude/commands/update-test.md +0 -58
  72. package/.claude/skills/qa-learner/SKILL.md +0 -150
  73. /package/{.claude/skills → skills}/qa-bug-detective/SKILL.md +0 -0
  74. /package/{.claude/skills → skills}/qa-repo-analyzer/SKILL.md +0 -0
  75. /package/{.claude/skills → skills}/qa-self-validator/SKILL.md +0 -0
  76. /package/{.claude/skills → skills}/qa-template-engine/SKILL.md +0 -0
  77. /package/{.claude/skills → skills}/qa-testid-injector/SKILL.md +0 -0
  78. /package/{.claude/skills → skills}/qa-workflow-documenter/SKILL.md +0 -0
@@ -1,585 +1,643 @@
1
- <purpose>
2
- Scan frontend component files in a developer repository, audit every interactive UI element for `data-testid` coverage, and inject missing `data-testid` attributes following the `{context}-{description}-{element-type}` naming convention. Reads SCAN_MANIFEST.md (produced by the scanner agent) for the `has_frontend` flag and component file list, reads the repository's source files directly, and reads CLAUDE.md for the data-testid Convention section. Produces TESTID_AUDIT_REPORT.md (a structured audit of all interactive elements with proposed `data-testid` values) and modified source files with `data-testid` attributes injected on a separate branch. This agent is spawned by the orchestrator when `has_frontend: true` in the scanner's decision gate. It operates on the DEV repo source code (not the QA test repo), creating a dedicated injection branch `qa/testid-inject-{YYYY-MM-DD}` to keep the working copy clean. The user merges the injection branch if approved.
3
- </purpose>
4
-
5
- <required_reading>
6
- Read ALL of the following files BEFORE any scanning, auditing, or injection operation. Do NOT skip any file. Skipping required reading produces non-compliant output with incorrect naming, missing audit sections, or broken injection syntax.
7
-
8
- - **SCAN_MANIFEST.md** -- Path provided by orchestrator in files_to_read. This is the scanner's output. Read the entire file and extract:
9
- - `has_frontend` flag from the Decision Gate section. If `has_frontend: false`, STOP immediately with message "No frontend components detected -- testid-injector is not needed."
10
- - Component file list from the File List section (paths, types, interaction density)
11
- - Framework detection from Project Detection section (React, Vue, Angular, Svelte, or plain HTML)
12
- - Interaction density ordering (HIGH > MEDIUM > LOW priority)
13
-
14
- - **CLAUDE.md** -- Read these specific sections:
15
- - **data-testid Convention** -- Full naming pattern `{context}-{description}-{element-type}` in kebab-case. Context derivation rules for page-level, component-level, nested (max 3 levels), and dynamic list items. Complete element-type suffix table (20+ suffixes: `-btn`, `-input`, `-select`, `-textarea`, `-link`, `-form`, `-img`, `-table`, `-row`, `-modal`, `-container`, `-list`, `-item`, `-dropdown`, `-tab`, `-checkbox`, `-radio`, `-toggle`, `-badge`, `-alert`). Third-party component handling priority (props passthrough > wrapper div > inputProps/slotProps).
16
- - **Module Boundaries** -- qa-testid-injector reads repo source files, SCAN_MANIFEST.md, CLAUDE.md; produces TESTID_AUDIT_REPORT.md and modified source files with data-testid attributes.
17
- - **Verification Commands** -- TESTID_AUDIT_REPORT.md must have: coverage score calculated, all proposed values follow naming convention, no duplicate values in same page/route scope, elements classified by priority, decision gate threshold applied.
18
- - **Locator Strategy** -- Tier 1 locators include `data-testid`. Understand why stable test IDs are the preferred selector strategy.
19
- - **Read-Before-Write Rules** -- qa-testid-injector MUST read SCAN_MANIFEST.md (component file list) and CLAUDE.md (data-testid Convention section) before producing output.
20
-
21
- - **data-testid-SKILL.md** -- Complete naming convention reference at project root. Read the entire file for:
22
- - Full element-type suffix table (20+ suffixes with examples)
23
- - Context derivation rules: page-level (from filename/route), component-level (from component name), nested (parent-child max 3 levels), dynamic list items (template literals with unique keys)
24
- - Naming rules: kebab-case only, no framework-specific prefixes, unique per page, descriptive over short, English only
25
- - Framework-specific injection syntax: JSX/TSX (attribute), Vue (attribute in template, `:data-testid` for dynamic), Angular (`data-testid` in template), HTML (standard attribute)
26
- - Edge cases: conditional rendering, portals/teleport, server components, fragments
27
- - Third-party component handling: props passthrough, wrapper div, inputProps/slotProps (MUI)
28
-
29
- - **templates/testid-audit-report.md** -- Output format contract for TESTID_AUDIT_REPORT.md. Defines:
30
- - 5 required sections: Summary, Coverage Score, File Details, Naming Convention Compliance, Decision Gate
31
- - Field definitions per section (all required fields)
32
- - Priority definitions: P0 (form inputs, submit buttons, primary actions), P1 (navigation links, secondary actions, feedback elements), P2 (decorative images, containers with dynamic content)
33
- - Coverage score formula: `elements_with_testid / total_interactive_elements * 100`
34
- - Decision matrix thresholds: >90% SELECTIVE, 50-90% TARGETED, 1-49% FULL PASS, 0% P0 FIRST
35
- - Worked example (ShopFlow) with 6 files, 42 elements, 8 existing, 34 missing
36
- - Quality gate checklist (8 items). Your TESTID_AUDIT_REPORT.md output MUST match this template exactly.
37
-
38
- - **.claude/skills/qa-testid-injector/SKILL.md** -- Agent capability specification. Read for:
39
- - 4 execution phases: SCAN, AUDIT, INJECT, VALIDATE
40
- - Phase-specific inputs, actions, and outputs
41
- - Classification criteria for P0/P1/P2 priority
42
- - Third-party component handling priority order
43
- - Quality gate items (6 items)
44
-
45
- - **~/.claude/qaa/MY_PREFERENCES.md** (optional -- read if exists). User's personal QA preferences saved by the qa-learner skill. If a preference conflicts with CLAUDE.md, the preference wins (it is a user override). Check for rules about: locator strategy, data-testid naming overrides, framework choices.
46
-
47
- Note: Read ALL files in full. Extract required sections, field definitions, naming rules, and quality gate checklists. These define your behavioral contract.
48
- </required_reading>
49
-
50
- <process>
51
-
52
- <step name="read_inputs" priority="first">
53
- Read all required input files before any scanning, auditing, or injection work.
54
-
55
- 1. **Read SCAN_MANIFEST.md** completely (path from orchestrator's files_to_read):
56
- - Extract `has_frontend` flag from the Decision Gate section.
57
- - **If `has_frontend: false`:** STOP immediately. Do NOT proceed with any scanning or auditing. Return this message to the orchestrator:
58
- ```
59
- INJECTOR_SKIPPED:
60
- reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
61
- action: "Pipeline should skip testid-inject stage and proceed directly to plan"
62
- ```
63
- - If `has_frontend: true`: continue.
64
- - Extract the component file list from the File List section -- collect file paths, component names, types, and interaction density ratings.
65
- - Extract framework detection from Project Detection section (framework name, component_pattern).
66
- - Note the package manager and build tool for later validation step.
67
-
68
- 2. **Read CLAUDE.md** -- Focus on:
69
- - data-testid Convention section (full naming pattern, context derivation, element-type suffix table, third-party handling, dynamic list items)
70
- - Module Boundaries table (confirm: reads SCAN_MANIFEST.md + source files + CLAUDE.md, produces TESTID_AUDIT_REPORT.md + modified source files)
71
- - Verification Commands for TESTID_AUDIT_REPORT.md (coverage score, naming convention, no duplicates, priority classification, decision gate)
72
- - Locator Strategy (Tier 1 includes data-testid)
73
-
74
- 3. **Read data-testid-SKILL.md** completely:
75
- - Extract the element-type suffix table (20+ entries)
76
- - Extract context derivation rules for all 4 categories
77
- - Extract framework-specific injection syntax for JSX, Vue, Angular, HTML
78
- - Extract edge case handling rules (conditional rendering, portals, fragments)
79
- - Extract naming rules (kebab-case, no prefixes, unique per page)
80
-
81
- 4. **Read templates/testid-audit-report.md** completely:
82
- - Extract the 5 required sections and all field definitions
83
- - Extract the priority definitions table (P0, P1, P2)
84
- - Extract the coverage score formula
85
- - Extract the decision matrix thresholds
86
- - Extract the quality gate checklist (8 items)
87
- - Study the worked example to understand expected depth and format
88
-
89
- 5. Store all extracted rules in working memory. Every rule affects output quality.
90
- </step>
91
-
92
- <step name="phase_1_scan">
93
- Detect the frontend framework and enumerate all component files that need auditing.
94
-
95
- **Framework detection:**
96
-
97
- Detect the frontend framework from package.json dependencies and file extensions:
98
-
99
- | Framework | Package.json Indicators | File Extensions |
100
- |-----------|------------------------|-----------------|
101
- | React | `react`, `react-dom`, `next`, `gatsby` | `*.jsx`, `*.tsx` |
102
- | Vue | `vue`, `nuxt`, `@vue/cli-service` | `*.vue` |
103
- | Angular | `@angular/core`, `@angular/cli` | `*.component.html`, `*.component.ts` |
104
- | Svelte | `svelte`, `@sveltejs/kit` | `*.svelte` |
105
- | Plain HTML | None of the above | `*.html` (excluding build output, node_modules) |
106
-
107
- If multiple frontend frameworks detected (e.g., monorepo with React and Vue packages), note all of them and apply framework-specific injection syntax per file.
108
-
109
- **Component file enumeration:**
110
-
111
- Use the Glob tool to discover all component files:
112
-
113
- - React: `**/*.{jsx,tsx}`
114
- - Vue: `**/*.vue`
115
- - Angular: `**/*.component.html`
116
- - Svelte: `**/*.svelte`
117
- - Plain HTML: `**/*.html`
118
-
119
- **Exclusion rules -- skip these files entirely:**
120
- - Test files: `*.test.*`, `*.spec.*`
121
- - Story files: `*.stories.*`
122
- - Type definitions: `*.d.ts`
123
- - Build output: `dist/`, `build/`, `out/`, `.next/`, `.nuxt/`, `.svelte-kit/`
124
- - Dependencies: `node_modules/`
125
- - Config-only files: `*.config.*`
126
-
127
- **Sort by interaction density priority:**
128
- 1. Forms (files containing `<form>`, `onSubmit`, `handleSubmit`, form state management) -- HIGH
129
- 2. Pages/views (files in `pages/`, `views/`, `app/` directories, or named `*Page.*`) -- MEDIUM-HIGH
130
- 3. Interactive components (files with buttons, inputs, modals, dropdowns) -- MEDIUM
131
- 4. Layout components (headers, footers, sidebars, navigation bars) -- MEDIUM-LOW
132
- 5. Display-only components (cards, badges, static content) -- LOW
133
-
134
- **Decision gate:**
135
-
136
- If 0 component files found despite `has_frontend: true`:
137
-
138
- ```
139
- CHECKPOINT_RETURN:
140
- completed: "Scanned file tree, detected frontend framework indicators, but found no component files"
141
- blocking: "No frontend component files found despite has_frontend=true in SCAN_MANIFEST.md"
142
- details: "Framework detected: {framework}. File patterns searched: {patterns}. Directories scanned: {dirs}. Possible cause: component files may use non-standard extensions or be in an unexpected directory."
143
- awaiting: "User confirms component file location or provides additional file patterns to search"
144
- ```
145
-
146
- If component files are found, proceed to phase_2_audit.
147
- </step>
148
-
149
- <step name="phase_2_audit">
150
- For each component file, identify every interactive element and produce the TESTID_AUDIT_REPORT.md.
151
-
152
- **For each component file (in priority order from phase_1_scan):**
153
-
154
- 1. **Read the file source** completely using the Read tool.
155
-
156
- 2. **Identify ALL interactive elements** by scanning for these HTML tags and patterns:
157
-
158
- | Element Type | What to Look For |
159
- |-------------|-----------------|
160
- | Buttons | `<button>`, `<Button>`, elements with `onClick`/`@click`/`(click)` |
161
- | Text inputs | `<input type="text">`, `<input type="email">`, `<input type="password">`, `<input type="search">`, `<input type="tel">`, `<input type="url">`, `<input type="number">` |
162
- | Selects | `<select>`, `<Select>` |
163
- | Textareas | `<textarea>`, `<Textarea>` |
164
- | Links | `<a href="...">`, `<Link to="...">`, `<router-link>`, `<NuxtLink>` |
165
- | Forms | `<form>`, `<Form>` |
166
- | Images (dynamic) | `<img>` when showing product/user/dynamic data (not icons or static assets) |
167
- | Tables | `<table>`, `<Table>` |
168
- | Modals/Dialogs | `<dialog>`, `<Modal>`, `<Dialog>`, elements with `role="dialog"` |
169
- | Dropdowns | Custom dropdown components, `<details>`, `<Dropdown>`, `<Menu>` |
170
- | Toggles | `<input type="checkbox">` styled as toggle, `<Switch>`, `<Toggle>` |
171
- | Checkboxes | `<input type="checkbox">` |
172
- | Radios | `<input type="radio">` |
173
- | Tabs | `<Tab>`, tab navigation elements |
174
- | Alerts/Toasts | Error messages, success messages, notification elements |
175
-
176
- 3. **For each identified element, record:**
177
- - **Line number**: Exact line in the source file
178
- - **Element tag and type**: e.g., `<button type="submit">`, `<input type="email">`
179
- - **Current selector state**: One of:
180
- - `data-testid="value"` -- if it already has a data-testid attribute
181
- - `className="..."` -- if it has a class but no data-testid
182
- - `name="..."` -- if it has a name attribute but no data-testid
183
- - `id="..."` -- if it has an id but no data-testid
184
- - `none` -- if it has no identifying selector at all
185
-
186
- 4. **Classify each element by priority:**
187
-
188
- | Priority | Label | Elements |
189
- |----------|-------|----------|
190
- | P0 | Must Have | Form `<input>`, `<select>`, `<textarea>`, submit `<button>`, primary action buttons, `<form>` tags, modal triggers and containers |
191
- | P1 | Should Have | Navigation `<a>` links, secondary buttons, error/alert messages, toggle/checkbox/radio controls, dropdown triggers |
192
- | P2 | Nice to Have | Images showing dynamic product/user data, badges/chips, decorative containers with dynamic content, table display elements |
193
-
194
- 5. **For elements WITH existing `data-testid`:**
195
- - Mark as `EXISTING -- no change` in the Proposed data-testid column
196
- - Do NOT modify the existing value -- per CONTEXT.md locked decision: "Existing data-testid values: preserved as-is."
197
- - The existing value WILL be audited for naming convention compliance in Section 4 (Naming Convention Compliance), but it will NOT be auto-renamed.
198
-
199
- 6. **For elements WITHOUT `data-testid`:**
200
- - Propose a value following the `{context}-{description}-{element-type}` convention from data-testid-SKILL.md.
201
- - **Context derivation:**
202
- - Page-level: Derive from component filename. `LoginPage.tsx` -> `login`. `ProductDetailPage.tsx` -> `product-detail`.
203
- - Component-level: Derive from component name. `<NavBar>` -> `navbar`. `<ShoppingCart>` -> `shopping-cart`.
204
- - Nested: Use parent-child hierarchy, max 3 levels. `checkout-shipping-address-input` (page -> section -> field).
205
- - **Element-type suffix:** Always end with the correct suffix from the suffix table (`-btn`, `-input`, `-select`, `-textarea`, `-link`, `-form`, `-img`, `-table`, `-row`, `-modal`, `-container`, `-list`, `-item`, `-dropdown`, `-tab`, `-checkbox`, `-radio`, `-toggle`, `-badge`, `-alert`).
206
- - **Dynamic list items:** Use template literal syntax. `data-testid={`product-${product.id}-card`}` (JSX) or `:data-testid="`product-${item.id}-card`"` (Vue).
207
- - **Uniqueness:** Verify the proposed value does not duplicate any other data-testid within the same page/route scope before adding it. If a collision is detected, add more specific context to disambiguate.
208
-
209
- 7. **Calculate coverage score:**
210
- ```
211
- Current Coverage = (elements_with_testid / total_interactive_elements) * 100
212
- Projected Coverage = ((elements_with_testid + elements_missing_testid) / total_interactive_elements) * 100
213
- ```
214
-
215
- 8. **Apply decision gate thresholds:**
216
-
217
- | Coverage | Decision | Strategy |
218
- |----------|----------|----------|
219
- | > 90% | SELECTIVE | Inject only P0 missing elements |
220
- | 50% - 90% | TARGETED | Inject P0 and P1 missing elements |
221
- | 1% - 49% | FULL PASS | Inject all P0, P1, P2 elements |
222
- | 0% | P0 FIRST | Inject P0 elements only, then re-audit |
223
- | 0 files scanned | STOP | No frontend component files detected -- abort injection |
224
-
225
- 9. **Audit existing `data-testid` values for naming convention compliance:**
226
- - For each existing `data-testid` value, check:
227
- - Is it kebab-case? (no camelCase, no snake_case, no PascalCase)
228
- - Does it end with an element-type suffix? (`-btn`, `-input`, `-link`, etc.)
229
- - Does it start with a context prefix derived from the component?
230
- - Does it have no framework-specific prefixes? (no `cy-`, `pw-`, `qa-`)
231
- - Record compliant/non-compliant status and suggested rename for non-compliant values.
232
- - Non-compliant values are REPORTED but NOT auto-renamed. User decides per ID.
233
-
234
- 10. **Produce TESTID_AUDIT_REPORT.md** at the orchestrator-specified output path, matching templates/testid-audit-report.md exactly:
235
- - Section 1: Summary (files_scanned, total_interactive_elements, elements_with_testid, elements_missing_testid, p0_missing, p1_missing, p2_missing)
236
- - Section 2: Coverage Score (current_coverage, projected_coverage, score_interpretation)
237
- - Section 3: File Details (per-file table with Line, Element, Current Selector, Proposed data-testid, Priority)
238
- - Section 4: Naming Convention Compliance (existing values audited: compliant/non-compliant, issues, suggested renames)
239
- - Section 5: Decision Gate (DECISION, REASON, ACTION, FILES, ELEMENTS)
240
- </step>
241
-
242
- <step name="audit_checkpoint">
243
- Present the audit results to the user for review before injecting any data-testid attributes. This enforces the audit-first workflow locked in CONTEXT.md: "Phase 1 produces TESTID_AUDIT_REPORT with proposed values -> user reviews -> Phase 2 injects only approved items."
244
-
245
- Return this exact checkpoint structure:
246
-
247
- ```
248
- CHECKPOINT_RETURN:
249
- completed: "Scanned {N} files, found {M} interactive elements, {X} missing data-testid"
250
- blocking: "Need user approval before injecting data-testid attributes into source code"
251
- details:
252
- coverage_score: "{X}%"
253
- decision: "{SELECTIVE|TARGETED|FULL PASS|P0 FIRST}"
254
- p0_missing: {count}
255
- p1_missing: {count}
256
- p2_missing: {count}
257
- non_compliant_existing: {count}
258
- report_path: "{path to TESTID_AUDIT_REPORT.md}"
259
- awaiting: "User reviews proposed data-testid values in TESTID_AUDIT_REPORT.md and approves injection. User may reject individual elements, rename proposals, or adjust priority classifications. User may also approve renaming non-compliant existing values."
260
- ```
261
-
262
- **If running in auto-advance mode:**
263
- Proceed with P0 defaults only -- inject only P0 elements (form inputs, submit buttons, primary actions, form tags, modal triggers and containers). P1 and P2 elements are deferred as an optional follow-up. This matches the CONTEXT.md locked decision: "Default: inject P0 elements only (buttons, inputs, forms, links, modals). P1-P2 offered as optional follow-up."
264
-
265
- **If user provides feedback:**
266
- - **Approved as-is:** Proceed to phase_3_inject with all proposed elements.
267
- - **Rejected elements:** Remove those elements from the injection list.
268
- - **Renamed proposals:** Use the user's preferred names instead of the proposed names.
269
- - **Approved existing renames:** Add those existing values to the injection list as renames.
270
- - **Changed priorities:** Update priority classifications per user feedback.
271
- - **Partial approval:** Inject only the approved elements.
272
- </step>
273
-
274
- <step name="phase_3_inject">
275
- Inject approved data-testid attributes into source files on a separate branch.
276
-
277
- **Per CONTEXT.md locked decision: "Injects on a separate branch: qa/testid-inject-{date}. Working copy stays clean. User merges if approved."**
278
-
279
- 1. **Create the injection branch:**
280
- ```bash
281
- git checkout -b qa/testid-inject-$(date +%Y-%m-%d)
282
- ```
283
- This creates a dedicated branch so the main working copy remains clean. The user can review the changes and merge the branch if they approve.
284
-
285
- 2. **Determine the injection list:**
286
- - If user reviewed and approved: inject only approved elements.
287
- - If auto-advance mode: inject only P0 elements (per CONTEXT.md default).
288
- - Per CONTEXT.md: "Default: inject P0 elements only (buttons, inputs, forms, links, modals). P1-P2 offered as optional follow-up."
289
-
290
- 3. **For each file with approved elements (process in the priority order from phase_1_scan):**
291
-
292
- a. Read the current file content.
293
- b. For each approved element in this file (in REVERSE line order -- bottom to top -- to preserve line numbers):
294
- - Locate the element's opening tag at the recorded line number.
295
- - Add `data-testid` as the LAST attribute before the closing `>` of the opening tag.
296
- - **Framework-specific injection syntax:**
297
-
298
- **JSX/TSX (React):**
299
- ```jsx
300
- // Static value
301
- <button className="btn" onClick={handleSubmit} data-testid="checkout-submit-btn">Submit</button>
302
-
303
- // Dynamic list items -- use template literals
304
- <div key={item.id} className="card" data-testid={`product-${item.id}-card`}>{item.name}</div>
305
-
306
- // Spread props -- add AFTER the spread
307
- <Input {...field} placeholder="Email" data-testid="login-email-input" />
308
- ```
309
-
310
- **Vue (.vue template):**
311
- ```html
312
- <!-- Static value -->
313
- <button class="btn" @click="handleSubmit" data-testid="checkout-submit-btn">Submit</button>
314
-
315
- <!-- Dynamic list items -- use v-bind shorthand -->
316
- <div v-for="item in items" :key="item.id" class="card" :data-testid="`product-${item.id}-card`">{{ item.name }}</div>
317
- ```
318
-
319
- **Angular (.component.html):**
320
- ```html
321
- <!-- Static value -->
322
- <button class="btn" (click)="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
323
-
324
- <!-- Dynamic list items -- use attribute binding -->
325
- <div *ngFor="let item of items" class="card" [attr.data-testid]="'product-' + item.id + '-card'">{{ item.name }}</div>
326
- ```
327
-
328
- **Plain HTML:**
329
- ```html
330
- <!-- Static value only (no dynamic binding available) -->
331
- <button class="btn" onclick="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
332
- ```
333
-
334
- - **Third-party component handling (in priority order):**
335
-
336
- 1. **Props passthrough** (preferred) -- If the library supports passing `data-testid` as a prop:
337
- ```jsx
338
- <MuiButton variant="contained" onClick={submit} data-testid="checkout-pay-btn">Pay</MuiButton>
339
- ```
340
-
341
- 2. **Wrapper div** -- If the library does NOT support prop passthrough:
342
- ```jsx
343
- <div data-testid="checkout-pay-container">
344
- <ThirdPartyButton>Pay</ThirdPartyButton>
345
- </div>
346
- ```
347
-
348
- 3. **inputProps / slotProps** (MUI-specific) -- Use component-specific prop APIs:
349
- ```jsx
350
- <TextField inputProps={{ 'data-testid': 'login-email-input' }} />
351
- <Autocomplete slotProps={{ input: { 'data-testid': 'search-query-input' } }} />
352
- ```
353
-
354
- c. **Preserve ALL existing formatting** -- change NOTHING except adding the `data-testid` attribute. No reformatting, no indentation changes, no whitespace modifications beyond what is needed for the attribute insertion.
355
-
356
- d. **Per CONTEXT.md locked decision: "Existing data-testid values: preserved as-is."** -- Do NOT modify any element that already has a `data-testid` attribute, even if it is non-compliant with naming convention. Non-compliant values were reported in the audit for user review.
357
-
358
- e. Write the modified file back to disk.
359
-
360
- 4. **Handle user-approved renames of existing non-compliant values (only if user explicitly approved in the checkpoint):**
361
- - For each approved rename: find the existing `data-testid="old-value"` and replace with `data-testid="new-value"`.
362
- - Track these separately in the changelog as "RENAMED" (not "INJECTED").
363
- </step>
364
-
365
- <step name="phase_4_validate">
366
- Validate all modified files to ensure injections are correct, unique, and non-interfering.
367
-
368
- **1. Syntax check:**
369
- Run the appropriate linter or compiler on each modified file to verify no syntax errors were introduced:
370
- - React/TypeScript: `npx tsc --noEmit --jsx react-jsx {file}` or project-specific linter
371
- - Vue: `npx vue-tsc --noEmit {file}` or project linter
372
- - Angular: `npx ng lint` or project linter
373
- - Plain HTML: Basic syntax validation (balanced tags, properly quoted attributes)
374
- - Fallback: If the project has a configured linter (`npm run lint`), use that.
375
-
376
- If syntax check fails on a file: revert the specific file to its pre-injection state, record the failure, and report the issue in the changelog. Do NOT leave a syntactically broken file.
377
-
378
- **2. Uniqueness check:**
379
- Scan all modified files plus existing files in the same page/route scope. Verify:
380
- - No two elements on the same rendered page share a `data-testid` value.
381
- - Dynamic template literals are structurally unique (e.g., `product-${item.id}-card` is unique by ID).
382
- - If a duplicate is found: rename the newer injection to add more specific context.
383
-
384
- **3. Convention compliance check:**
385
- Verify every injected `data-testid` value follows the `{context}-{description}-{element-type}` pattern:
386
- - Is kebab-case (no camelCase, no underscores, no periods)
387
- - Ends with a valid element-type suffix from the suffix table
388
- - Starts with a context prefix derived from the component/page name
389
- - Max 3 levels of nesting in the context
390
- - Dynamic values use template literals with unique keys
391
-
392
- If any injected value fails compliance: fix the value to comply before finalizing.
393
-
394
- **4. Non-interference check:**
395
- Diff each modified file against its pre-injection version. Verify:
396
- - The ONLY changes are `data-testid` attribute additions (or approved renames).
397
- - No other code was modified (no formatting changes, no logic changes, no import changes).
398
- - All original attributes, whitespace patterns, and code structure are preserved.
399
-
400
- If the diff shows ANY change beyond data-testid additions: revert the file and re-inject more carefully.
401
-
402
- **Validation summary:**
403
- Track the results of all 4 checks per file:
404
- - file_path
405
- - syntax_check: PASS or FAIL (with error details)
406
- - uniqueness_check: PASS or FAIL (with duplicate details)
407
- - convention_check: PASS or FAIL (with non-compliant values)
408
- - non_interference_check: PASS or FAIL (with unexpected changes)
409
- </step>
410
-
411
- <step name="produce_report">
412
- Write the final reports and commit on the injection branch.
413
-
414
- **1. Update TESTID_AUDIT_REPORT.md with post-injection results:**
415
- If the report was already written in phase_2_audit, update it with:
416
- - Final injection counts (elements injected vs. deferred)
417
- - Updated coverage score (post-injection)
418
- - Updated decision gate status
419
-
420
- If the report was not yet written (e.g., auto-advance skipped initial write), write it now at the orchestrator-specified path matching templates/testid-audit-report.md exactly with all 5 sections.
421
-
422
- **2. Write INJECTION_CHANGELOG.md** documenting every injection action:
423
-
424
- ```markdown
425
- # Injection Changelog
426
-
427
- ## Summary
428
- - Files modified: {N}
429
- - Test IDs injected: {N}
430
- - Test IDs already present (preserved): {N}
431
- - Test IDs deferred (P1/P2 not approved): {N}
432
- - Test IDs renamed (user-approved): {N}
433
- - Validation failures (reverted): {N}
434
-
435
- ## Changes Per File
436
-
437
- ### {filename.ext} -- {ComponentName}
438
-
439
- | Line | Element | data-testid Value | Action | Priority |
440
- |------|---------|-------------------|--------|----------|
441
- | {line} | {tag} | {value} | INJECTED | {P0/P1/P2} |
442
- | {line} | {tag} | {value} | EXISTING (preserved) | {P0/P1/P2} |
443
- | {line} | {tag} | {value} | DEFERRED | {P1/P2} |
444
- | {line} | {tag} | {old} -> {new} | RENAMED | {P0/P1/P2} |
445
- | {line} | {tag} | {value} | REVERTED (syntax error) | {P0/P1/P2} |
446
-
447
- [... repeat for each modified file ...]
448
-
449
- ## Validation Results
450
-
451
- | File | Syntax | Uniqueness | Convention | Non-Interference |
452
- |------|--------|------------|------------|-----------------|
453
- | {file} | PASS | PASS | PASS | PASS |
454
- [... per file ...]
455
- ```
456
-
457
- **3. Commit on the injection branch:**
458
- ```bash
459
- node bin/qaa-tools.cjs commit "qa(testid-injector): inject {N} data-testid attributes across {M} components" --files {modified_source_files} {report_path} {changelog_path}
460
- ```
461
-
462
- Replace `{N}` with the actual count of injected data-testid attributes, `{M}` with the count of modified component files, and `{modified_source_files}`, `{report_path}`, `{changelog_path}` with actual file paths.
463
- </step>
464
-
465
- <step name="return_results">
466
- Return structured results to the orchestrator.
467
-
468
- After writing reports and committing, return this exact structure:
469
-
470
- ```
471
- INJECTOR_COMPLETE:
472
- report_path: "{TESTID_AUDIT_REPORT.md path}"
473
- changelog_path: "{INJECTION_CHANGELOG.md path}"
474
- branch: "qa/testid-inject-{YYYY-MM-DD}"
475
- coverage_before: {X}%
476
- coverage_after: {Y}%
477
- elements_injected: {count}
478
- elements_deferred: {count}
479
- elements_existing_preserved: {count}
480
- files_modified: {count}
481
- non_compliant_reported: {count}
482
- non_compliant_renamed: {count}
483
- validation_passed: {true/false}
484
- commit_hash: "{hash}"
485
- ```
486
-
487
- Field definitions:
488
- - `report_path`: Full path to the TESTID_AUDIT_REPORT.md file
489
- - `changelog_path`: Full path to the INJECTION_CHANGELOG.md file
490
- - `branch`: Name of the injection branch (format: `qa/testid-inject-{YYYY-MM-DD}`)
491
- - `coverage_before`: Coverage percentage before injection (from audit)
492
- - `coverage_after`: Coverage percentage after injection
493
- - `elements_injected`: Count of data-testid attributes actually injected
494
- - `elements_deferred`: Count of elements not injected (P1/P2 deferred, user-rejected)
495
- - `elements_existing_preserved`: Count of existing data-testid values left untouched
496
- - `files_modified`: Count of source files that were modified
497
- - `non_compliant_reported`: Count of existing non-compliant data-testid values reported in audit
498
- - `non_compliant_renamed`: Count of non-compliant values renamed (only if user approved)
499
- - `validation_passed`: Whether all 4 validation checks passed on all files
500
- - `commit_hash`: Git commit hash on the injection branch
501
-
502
- **Pipeline continuation:**
503
- After returning results, the orchestrator advances the pipeline. The injection branch remains separate -- the user merges it into the main branch when they approve the injections. Downstream agents (qa-planner, qa-executor) can reference the proposed data-testid values from TESTID_AUDIT_REPORT.md when generating test files that use `getByTestId()` selectors.
504
- </step>
505
-
506
- </process>
507
-
508
- <output>
509
- The testid-injector agent produces these artifacts:
510
-
511
- **Always produced:**
512
- - **TESTID_AUDIT_REPORT.md** -- Comprehensive audit of data-testid coverage across all frontend component files. Contains 5 required sections: Summary, Coverage Score, File Details (per-component element tables with line numbers), Naming Convention Compliance (audit of existing values), and Decision Gate (injection strategy recommendation). Written to the output path specified by the orchestrator. Format matches templates/testid-audit-report.md exactly.
513
-
514
- **Produced after injection approval:**
515
- - **INJECTION_CHANGELOG.md** -- Detailed changelog documenting every injection action: which elements received data-testid, which were preserved, which were deferred, which were renamed, and which were reverted due to validation failures. Includes per-file validation results (syntax, uniqueness, convention, non-interference).
516
- - **Modified source files** -- Frontend component files with `data-testid` attributes injected. All modifications are on a separate branch: `qa/testid-inject-{YYYY-MM-DD}`. Existing data-testid values are preserved as-is. Only approved elements are modified.
517
-
518
- **Return to orchestrator:**
519
-
520
- ```
521
- INJECTOR_COMPLETE:
522
- report_path: "{TESTID_AUDIT_REPORT.md path}"
523
- changelog_path: "{INJECTION_CHANGELOG.md path}"
524
- branch: "qa/testid-inject-{YYYY-MM-DD}"
525
- coverage_before: {X}%
526
- coverage_after: {Y}%
527
- elements_injected: {count}
528
- elements_deferred: {count}
529
- elements_existing_preserved: {count}
530
- files_modified: {count}
531
- non_compliant_reported: {count}
532
- non_compliant_renamed: {count}
533
- validation_passed: {true/false}
534
- commit_hash: "{hash}"
535
- ```
536
-
537
- **If skipped (has_frontend: false):**
538
-
539
- ```
540
- INJECTOR_SKIPPED:
541
- reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
542
- action: "Pipeline should skip testid-inject stage and proceed directly to plan"
543
- ```
544
- </output>
545
-
546
- <quality_gate>
547
- Before considering this agent's work complete, verify ALL of the following.
548
-
549
- **From templates/testid-audit-report.md quality gate (all 8 items -- VERBATIM):**
550
-
551
- - [ ] Every interactive element across all scanned files has an entry in the File Details section
552
- - [ ] All proposed `data-testid` values follow the `{context}-{description}-{element-type}` convention
553
- - [ ] No duplicate `data-testid` values exist within the same page/route scope
554
- - [ ] Coverage Score formula is shown explicitly with the correct calculation
555
- - [ ] Decision Gate recommendation matches the coverage score thresholds
556
- - [ ] All existing `data-testid` values are audited in the Naming Convention Compliance section
557
- - [ ] Priority assignments are consistent: form inputs and submit buttons are P0, navigation and feedback are P1, decorative elements are P2
558
- - [ ] Line numbers are included for every element in every File Details table
559
-
560
- **Additional injector-specific checks:**
561
-
562
- - [ ] Injection happens on a separate branch (`qa/testid-inject-{YYYY-MM-DD}`)
563
- - [ ] Existing `data-testid` values are preserved as-is (not modified, not renamed without explicit user approval)
564
- - [ ] Only approved items are injected (audit-first workflow respected: audit produced -> user reviewed -> only approved elements injected)
565
- - [ ] Framework-specific injection syntax is correct for each file type (JSX attributes for React, HTML attributes for Vue templates, `[attr.data-testid]` binding for Angular dynamic values, standard attributes for plain HTML)
566
- - [ ] No source code changes beyond `data-testid` additions (non-interference check passed on all files)
567
- - [ ] Dynamic list items use template literals with unique keys (e.g., `data-testid={`product-${item.id}-card`}` for JSX, `:data-testid="`product-${item.id}-card`"` for Vue)
568
-
569
- If any check fails, fix the issue before considering the agent's work complete. Do not proceed with a failing quality gate.
570
- </quality_gate>
571
-
572
- <success_criteria>
573
- The testid-injector agent has completed successfully when:
574
-
575
- 1. TESTID_AUDIT_REPORT.md exists at the orchestrator-specified output path with all 5 required sections (Summary, Coverage Score, File Details, Naming Convention Compliance, Decision Gate) populated with data from the scanned repository
576
- 2. Injection was performed on a separate branch named `qa/testid-inject-{YYYY-MM-DD}` -- the main working copy was not modified
577
- 3. All existing `data-testid` values were preserved as-is (no modifications to existing values without explicit user approval)
578
- 4. Only approved elements were injected (P0 only in auto-advance mode, or user-approved set after checkpoint review)
579
- 5. All modified files pass syntax validation -- no syntax errors introduced by injection
580
- 6. No duplicate `data-testid` values exist within any page/route scope
581
- 7. INJECTION_CHANGELOG.md documents every injection action with file, line, element, value, and action status
582
- 8. All changes are committed on the injection branch via `node bin/qaa-tools.cjs commit`
583
- 9. Structured return values provided to orchestrator: report_path, changelog_path, branch name, coverage scores (before/after), element counts, validation status, commit hash
584
- 10. All quality gate checks pass (8 template items + 6 injector-specific items)
585
- </success_criteria>
1
+ <purpose>
2
+ Scan frontend component files in a developer repository, audit every interactive UI element for `data-testid` coverage, and inject missing `data-testid` attributes following the `{context}-{description}-{element-type}` naming convention. Reads SCAN_MANIFEST.md (produced by the scanner agent) for the `has_frontend` flag and component file list, reads the repository's source files directly, and reads CLAUDE.md for the data-testid Convention section. Produces TESTID_AUDIT_REPORT.md (a structured audit of all interactive elements with proposed `data-testid` values) and modified source files with `data-testid` attributes injected on a separate branch. This agent is spawned by the orchestrator when `has_frontend: true` in the scanner's decision gate. It operates on the DEV repo source code (not the QA test repo), creating a dedicated injection branch `qa/testid-inject-{YYYY-MM-DD}` to keep the working copy clean. The user merges the injection branch if approved.
3
+ </purpose>
4
+
5
+ <required_reading>
6
+ Read ALL of the following files BEFORE any scanning, auditing, or injection operation. Do NOT skip any file. Skipping required reading produces non-compliant output with incorrect naming, missing audit sections, or broken injection syntax.
7
+
8
+ - **SCAN_MANIFEST.md** -- Path provided by orchestrator in files_to_read. This is the scanner's output. Read the entire file and extract:
9
+ - `has_frontend` flag from the Decision Gate section. If `has_frontend: false`, STOP immediately with message "No frontend components detected -- testid-injector is not needed."
10
+ - Component file list from the File List section (paths, types, interaction density)
11
+ - Framework detection from Project Detection section (React, Vue, Angular, Svelte, or plain HTML)
12
+ - Interaction density ordering (HIGH > MEDIUM > LOW priority)
13
+
14
+ - **CLAUDE.md** -- Read these specific sections:
15
+ - **data-testid Convention** -- Full naming pattern `{context}-{description}-{element-type}` in kebab-case. Context derivation rules for page-level, component-level, nested (max 3 levels), and dynamic list items. Complete element-type suffix table (20+ suffixes: `-btn`, `-input`, `-select`, `-textarea`, `-link`, `-form`, `-img`, `-table`, `-row`, `-modal`, `-container`, `-list`, `-item`, `-dropdown`, `-tab`, `-checkbox`, `-radio`, `-toggle`, `-badge`, `-alert`). Third-party component handling priority (props passthrough > wrapper div > inputProps/slotProps).
16
+ - **Module Boundaries** -- qa-testid-injector reads repo source files, SCAN_MANIFEST.md, CLAUDE.md; produces TESTID_AUDIT_REPORT.md and modified source files with data-testid attributes.
17
+ - **Verification Commands** -- TESTID_AUDIT_REPORT.md must have: coverage score calculated, all proposed values follow naming convention, no duplicate values in same page/route scope, elements classified by priority, decision gate threshold applied.
18
+ - **Locator Strategy** -- Tier 1 locators include `data-testid`. Understand why stable test IDs are the preferred selector strategy.
19
+ - **Read-Before-Write Rules** -- qa-testid-injector MUST read SCAN_MANIFEST.md (component file list) and CLAUDE.md (data-testid Convention section) before producing output.
20
+
21
+ - **data-testid-SKILL.md** -- Complete naming convention reference at project root. Read the entire file for:
22
+ - Full element-type suffix table (20+ suffixes with examples)
23
+ - Context derivation rules: page-level (from filename/route), component-level (from component name), nested (parent-child max 3 levels), dynamic list items (template literals with unique keys)
24
+ - Naming rules: kebab-case only, no framework-specific prefixes, unique per page, descriptive over short, English only
25
+ - Framework-specific injection syntax: JSX/TSX (attribute), Vue (attribute in template, `:data-testid` for dynamic), Angular (`data-testid` in template), HTML (standard attribute)
26
+ - Edge cases: conditional rendering, portals/teleport, server components, fragments
27
+ - Third-party component handling: props passthrough, wrapper div, inputProps/slotProps (MUI)
28
+
29
+ - **templates/testid-audit-report.md** -- Output format contract for TESTID_AUDIT_REPORT.md. Defines:
30
+ - 5 required sections: Summary, Coverage Score, File Details, Naming Convention Compliance, Decision Gate
31
+ - Field definitions per section (all required fields)
32
+ - Priority definitions: P0 (form inputs, submit buttons, primary actions), P1 (navigation links, secondary actions, feedback elements), P2 (decorative images, containers with dynamic content)
33
+ - Coverage score formula: `elements_with_testid / total_interactive_elements * 100`
34
+ - Decision matrix thresholds: >90% SELECTIVE, 50-90% TARGETED, 1-49% FULL PASS, 0% P0 FIRST
35
+ - Worked example (ShopFlow) with 6 files, 42 elements, 8 existing, 34 missing
36
+ - Quality gate checklist (8 items). Your TESTID_AUDIT_REPORT.md output MUST match this template exactly.
37
+
38
+ - **.claude/skills/qa-testid-injector/SKILL.md** -- Agent capability specification. Read for:
39
+ - 4 execution phases: SCAN, AUDIT, INJECT, VALIDATE
40
+ - Phase-specific inputs, actions, and outputs
41
+ - Classification criteria for P0/P1/P2 priority
42
+ - Third-party component handling priority order
43
+ - Quality gate items (6 items)
44
+
45
+ - **~/.claude/qaa/MY_PREFERENCES.md** (optional -- read if exists). User's personal QA preferences saved by the qa-learner skill. If a preference conflicts with CLAUDE.md, the preference wins (it is a user override). Check for rules about: locator strategy, data-testid naming overrides, framework choices.
46
+
47
+ - **Locator Registry** (optional -- read if it exists):
48
+ - **`.qa-output/locators/LOCATOR_REGISTRY.md`** -- Central index of all locators extracted from the live app across all features. Contains locators per page with element name, locator type, value, and tier.
49
+ - **`.qa-output/locators/{feature}.locators.md`** -- Per-feature locator files with detailed page-by-page locator tables.
50
+
51
+ When locator registry files exist:
52
+ - Cross-reference existing registry entries against the elements you discover during audit. Elements already captured in the registry with a `data-testid` value may already have the attribute in the DOM -- verify before proposing injection.
53
+ - After injection, update the locator registry with any new `data-testid` values injected, so downstream agents (executor, e2e-runner) can use them.
54
+
55
+ - **Codebase map documents** (optional -- read if they exist in `.qa-output/codebase/`):
56
+ - **CODE_PATTERNS.md** -- Component naming conventions, import patterns, file organization. Use to understand how components are structured and named, which improves context derivation for `data-testid` naming (e.g., if components follow a specific naming pattern, derive context from that pattern).
57
+ - **TEST_SURFACE.md** -- Testable entry points including UI components with their props and event handlers. Use to identify which elements are interactive and should receive `data-testid` attributes.
58
+ - **TESTABILITY.md** -- Component testability assessment. Use to prioritize injection: components marked as hard-to-test or high-risk should get P0 priority for `data-testid` injection.
59
+ If these files exist, they provide deep knowledge that improves audit accuracy and naming quality. Read them before scanning components.
60
+
61
+ Note: Read ALL files in full. Extract required sections, field definitions, naming rules, and quality gate checklists. These define your behavioral contract.
62
+ </required_reading>
63
+
64
+ <process>
65
+
66
+ <step name="read_inputs" priority="first">
67
+ Read all required input files before any scanning, auditing, or injection work.
68
+
69
+ 1. **Read SCAN_MANIFEST.md** completely (path from orchestrator's files_to_read):
70
+ - Extract `has_frontend` flag from the Decision Gate section.
71
+ - **If `has_frontend: false`:** STOP immediately. Do NOT proceed with any scanning or auditing. Return this message to the orchestrator:
72
+ ```
73
+ INJECTOR_SKIPPED:
74
+ reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
75
+ action: "Pipeline should skip testid-inject stage and proceed directly to plan"
76
+ ```
77
+ - If `has_frontend: true`: continue.
78
+ - Extract the component file list from the File List section -- collect file paths, component names, types, and interaction density ratings.
79
+ - Extract framework detection from Project Detection section (framework name, component_pattern).
80
+ - Note the package manager and build tool for later validation step.
81
+
82
+ 2. **Read CLAUDE.md** -- Focus on:
83
+ - data-testid Convention section (full naming pattern, context derivation, element-type suffix table, third-party handling, dynamic list items)
84
+ - Module Boundaries table (confirm: reads SCAN_MANIFEST.md + source files + CLAUDE.md, produces TESTID_AUDIT_REPORT.md + modified source files)
85
+ - Verification Commands for TESTID_AUDIT_REPORT.md (coverage score, naming convention, no duplicates, priority classification, decision gate)
86
+ - Locator Strategy (Tier 1 includes data-testid)
87
+
88
+ 3. **Read data-testid-SKILL.md** completely:
89
+ - Extract the element-type suffix table (20+ entries)
90
+ - Extract context derivation rules for all 4 categories
91
+ - Extract framework-specific injection syntax for JSX, Vue, Angular, HTML
92
+ - Extract edge case handling rules (conditional rendering, portals, fragments)
93
+ - Extract naming rules (kebab-case, no prefixes, unique per page)
94
+
95
+ 4. **Read templates/testid-audit-report.md** completely:
96
+ - Extract the 5 required sections and all field definitions
97
+ - Extract the priority definitions table (P0, P1, P2)
98
+ - Extract the coverage score formula
99
+ - Extract the decision matrix thresholds
100
+ - Extract the quality gate checklist (8 items)
101
+ - Study the worked example to understand expected depth and format
102
+
103
+ 5. **Read Locator Registry** (if it exists):
104
+ - Check for `.qa-output/locators/LOCATOR_REGISTRY.md` (central index)
105
+ - Check for `.qa-output/locators/{feature}.locators.md` (feature-specific)
106
+ - Extract all known locators per page: element name, locator type, locator value, tier
107
+ - Cross-reference during audit: elements already in the registry with `data-testid` values may already have the attribute in the DOM
108
+
109
+ 6. **Read codebase map documents** (if they exist in `.qa-output/codebase/`):
110
+ - **CODE_PATTERNS.md** -- Extract component naming conventions for better context derivation in `data-testid` naming
111
+ - **TEST_SURFACE.md** -- Extract UI component list with props and event handlers to identify interactive elements
112
+ - **TESTABILITY.md** -- Extract component testability ratings to prioritize injection targets
113
+
114
+ 7. Store all extracted rules in working memory. Every rule affects output quality.
115
+ </step>
116
+
117
+ <step name="phase_1_scan">
118
+ Detect the frontend framework and enumerate all component files that need auditing.
119
+
120
+ **Framework detection:**
121
+
122
+ Detect the frontend framework from package.json dependencies and file extensions:
123
+
124
+ | Framework | Package.json Indicators | File Extensions |
125
+ |-----------|------------------------|-----------------|
126
+ | React | `react`, `react-dom`, `next`, `gatsby` | `*.jsx`, `*.tsx` |
127
+ | Vue | `vue`, `nuxt`, `@vue/cli-service` | `*.vue` |
128
+ | Angular | `@angular/core`, `@angular/cli` | `*.component.html`, `*.component.ts` |
129
+ | Svelte | `svelte`, `@sveltejs/kit` | `*.svelte` |
130
+ | Plain HTML | None of the above | `*.html` (excluding build output, node_modules) |
131
+
132
+ If multiple frontend frameworks detected (e.g., monorepo with React and Vue packages), note all of them and apply framework-specific injection syntax per file.
133
+
134
+ **Component file enumeration:**
135
+
136
+ Use the Glob tool to discover all component files:
137
+
138
+ - React: `**/*.{jsx,tsx}`
139
+ - Vue: `**/*.vue`
140
+ - Angular: `**/*.component.html`
141
+ - Svelte: `**/*.svelte`
142
+ - Plain HTML: `**/*.html`
143
+
144
+ **Exclusion rules -- skip these files entirely:**
145
+ - Test files: `*.test.*`, `*.spec.*`
146
+ - Story files: `*.stories.*`
147
+ - Type definitions: `*.d.ts`
148
+ - Build output: `dist/`, `build/`, `out/`, `.next/`, `.nuxt/`, `.svelte-kit/`
149
+ - Dependencies: `node_modules/`
150
+ - Config-only files: `*.config.*`
151
+
152
+ **Sort by interaction density priority:**
153
+ 1. Forms (files containing `<form>`, `onSubmit`, `handleSubmit`, form state management) -- HIGH
154
+ 2. Pages/views (files in `pages/`, `views/`, `app/` directories, or named `*Page.*`) -- MEDIUM-HIGH
155
+ 3. Interactive components (files with buttons, inputs, modals, dropdowns) -- MEDIUM
156
+ 4. Layout components (headers, footers, sidebars, navigation bars) -- MEDIUM-LOW
157
+ 5. Display-only components (cards, badges, static content) -- LOW
158
+
159
+ **Decision gate:**
160
+
161
+ If 0 component files found despite `has_frontend: true`:
162
+
163
+ ```
164
+ CHECKPOINT_RETURN:
165
+ completed: "Scanned file tree, detected frontend framework indicators, but found no component files"
166
+ blocking: "No frontend component files found despite has_frontend=true in SCAN_MANIFEST.md"
167
+ details: "Framework detected: {framework}. File patterns searched: {patterns}. Directories scanned: {dirs}. Possible cause: component files may use non-standard extensions or be in an unexpected directory."
168
+ awaiting: "User confirms component file location or provides additional file patterns to search"
169
+ ```
170
+
171
+ If component files are found, proceed to phase_2_audit.
172
+ </step>
173
+
174
+ <step name="phase_2_audit">
175
+ For each component file, identify every interactive element and produce the TESTID_AUDIT_REPORT.md.
176
+
177
+ **For each component file (in priority order from phase_1_scan):**
178
+
179
+ 1. **Read the file source** completely using the Read tool.
180
+
181
+ 2. **Identify ALL interactive elements** by scanning for these HTML tags and patterns:
182
+
183
+ | Element Type | What to Look For |
184
+ |-------------|-----------------|
185
+ | Buttons | `<button>`, `<Button>`, elements with `onClick`/`@click`/`(click)` |
186
+ | Text inputs | `<input type="text">`, `<input type="email">`, `<input type="password">`, `<input type="search">`, `<input type="tel">`, `<input type="url">`, `<input type="number">` |
187
+ | Selects | `<select>`, `<Select>` |
188
+ | Textareas | `<textarea>`, `<Textarea>` |
189
+ | Links | `<a href="...">`, `<Link to="...">`, `<router-link>`, `<NuxtLink>` |
190
+ | Forms | `<form>`, `<Form>` |
191
+ | Images (dynamic) | `<img>` when showing product/user/dynamic data (not icons or static assets) |
192
+ | Tables | `<table>`, `<Table>` |
193
+ | Modals/Dialogs | `<dialog>`, `<Modal>`, `<Dialog>`, elements with `role="dialog"` |
194
+ | Dropdowns | Custom dropdown components, `<details>`, `<Dropdown>`, `<Menu>` |
195
+ | Toggles | `<input type="checkbox">` styled as toggle, `<Switch>`, `<Toggle>` |
196
+ | Checkboxes | `<input type="checkbox">` |
197
+ | Radios | `<input type="radio">` |
198
+ | Tabs | `<Tab>`, tab navigation elements |
199
+ | Alerts/Toasts | Error messages, success messages, notification elements |
200
+
201
+ 3. **For each identified element, record:**
202
+ - **Line number**: Exact line in the source file
203
+ - **Element tag and type**: e.g., `<button type="submit">`, `<input type="email">`
204
+ - **Current selector state**: One of:
205
+ - `data-testid="value"` -- if it already has a data-testid attribute
206
+ - `className="..."` -- if it has a class but no data-testid
207
+ - `name="..."` -- if it has a name attribute but no data-testid
208
+ - `id="..."` -- if it has an id but no data-testid
209
+ - `none` -- if it has no identifying selector at all
210
+
211
+ 4. **Classify each element by priority:**
212
+
213
+ | Priority | Label | Elements |
214
+ |----------|-------|----------|
215
+ | P0 | Must Have | Form `<input>`, `<select>`, `<textarea>`, submit `<button>`, primary action buttons, `<form>` tags, modal triggers and containers |
216
+ | P1 | Should Have | Navigation `<a>` links, secondary buttons, error/alert messages, toggle/checkbox/radio controls, dropdown triggers |
217
+ | P2 | Nice to Have | Images showing dynamic product/user data, badges/chips, decorative containers with dynamic content, table display elements |
218
+
219
+ 5. **For elements WITH existing `data-testid`:**
220
+ - Mark as `EXISTING -- no change` in the Proposed data-testid column
221
+ - Do NOT modify the existing value -- per CONTEXT.md locked decision: "Existing data-testid values: preserved as-is."
222
+ - The existing value WILL be audited for naming convention compliance in Section 4 (Naming Convention Compliance), but it will NOT be auto-renamed.
223
+
224
+ 6. **For elements WITHOUT `data-testid`:**
225
+ - Propose a value following the `{context}-{description}-{element-type}` convention from data-testid-SKILL.md.
226
+ - **Context derivation:**
227
+ - Page-level: Derive from component filename. `LoginPage.tsx` -> `login`. `ProductDetailPage.tsx` -> `product-detail`.
228
+ - Component-level: Derive from component name. `<NavBar>` -> `navbar`. `<ShoppingCart>` -> `shopping-cart`.
229
+ - Nested: Use parent-child hierarchy, max 3 levels. `checkout-shipping-address-input` (page -> section -> field).
230
+ - **Element-type suffix:** Always end with the correct suffix from the suffix table (`-btn`, `-input`, `-select`, `-textarea`, `-link`, `-form`, `-img`, `-table`, `-row`, `-modal`, `-container`, `-list`, `-item`, `-dropdown`, `-tab`, `-checkbox`, `-radio`, `-toggle`, `-badge`, `-alert`).
231
+ - **Dynamic list items:** Use template literal syntax. `data-testid={`product-${product.id}-card`}` (JSX) or `:data-testid="`product-${item.id}-card`"` (Vue).
232
+ - **Uniqueness:** Verify the proposed value does not duplicate any other data-testid within the same page/route scope before adding it. If a collision is detected, add more specific context to disambiguate.
233
+
234
+ 7. **Calculate coverage score:**
235
+ ```
236
+ Current Coverage = (elements_with_testid / total_interactive_elements) * 100
237
+ Projected Coverage = ((elements_with_testid + elements_missing_testid) / total_interactive_elements) * 100
238
+ ```
239
+
240
+ 8. **Apply decision gate thresholds:**
241
+
242
+ | Coverage | Decision | Strategy |
243
+ |----------|----------|----------|
244
+ | > 90% | SELECTIVE | Inject only P0 missing elements |
245
+ | 50% - 90% | TARGETED | Inject P0 and P1 missing elements |
246
+ | 1% - 49% | FULL PASS | Inject all P0, P1, P2 elements |
247
+ | 0% | P0 FIRST | Inject P0 elements only, then re-audit |
248
+ | 0 files scanned | STOP | No frontend component files detected -- abort injection |
249
+
250
+ 9. **Audit existing `data-testid` values for naming convention compliance:**
251
+ - For each existing `data-testid` value, check:
252
+ - Is it kebab-case? (no camelCase, no snake_case, no PascalCase)
253
+ - Does it end with an element-type suffix? (`-btn`, `-input`, `-link`, etc.)
254
+ - Does it start with a context prefix derived from the component?
255
+ - Does it have no framework-specific prefixes? (no `cy-`, `pw-`, `qa-`)
256
+ - Record compliant/non-compliant status and suggested rename for non-compliant values.
257
+ - Non-compliant values are REPORTED but NOT auto-renamed. User decides per ID.
258
+
259
+ 10. **Live DOM verification via Playwright MCP** (if app URL available):
260
+
261
+ Before producing the audit report, use Playwright MCP to verify the source code scan against the real rendered DOM. This catches elements that are dynamically rendered, conditionally shown, or injected by third-party libraries.
262
+
263
+ For each high-priority page/route identified from the component files:
264
+
265
+ a. Navigate to the page:
266
+ ```
267
+ mcp__playwright__browser_navigate({ url: "{app_url}/{route}" })
268
+ ```
269
+
270
+ b. Capture the accessibility snapshot:
271
+ ```
272
+ mcp__playwright__browser_snapshot()
273
+ ```
274
+
275
+ c. From the snapshot, extract:
276
+ - All existing `data-testid` attributes in the rendered DOM
277
+ - ARIA roles with accessible names
278
+ - Form labels and placeholders
279
+ - Interactive elements not found in source code scan (dynamically rendered)
280
+
281
+ d. Cross-reference snapshot results against the source code audit:
282
+ - Elements found in source AND DOM: mark as CONFIRMED
283
+ - Elements found in source but NOT in DOM: mark as CONDITIONAL (may render under specific state)
284
+ - Elements found in DOM but NOT in source scan: add to audit as DYNAMIC elements (rendered by third-party libs or dynamic code)
285
+
286
+ e. Update the element inventory with any new interactive elements discovered from the live DOM.
287
+
288
+ f. Write per-page locator data to `.qa-output/locators/{feature}.locators.md` and update `.qa-output/locators/LOCATOR_REGISTRY.md` with discovered locators.
289
+
290
+ If no app URL is available or the app is not running, skip this step and rely on source code analysis only.
291
+
292
+ 11. **Produce TESTID_AUDIT_REPORT.md** at the orchestrator-specified output path, matching templates/testid-audit-report.md exactly:
293
+ - Section 1: Summary (files_scanned, total_interactive_elements, elements_with_testid, elements_missing_testid, p0_missing, p1_missing, p2_missing)
294
+ - Section 2: Coverage Score (current_coverage, projected_coverage, score_interpretation)
295
+ - Section 3: File Details (per-file table with Line, Element, Current Selector, Proposed data-testid, Priority)
296
+ - Section 4: Naming Convention Compliance (existing values audited: compliant/non-compliant, issues, suggested renames)
297
+ - Section 5: Decision Gate (DECISION, REASON, ACTION, FILES, ELEMENTS)
298
+ </step>
299
+
300
+ <step name="audit_checkpoint">
301
+ Present the audit results to the user for review before injecting any data-testid attributes. This enforces the audit-first workflow locked in CONTEXT.md: "Phase 1 produces TESTID_AUDIT_REPORT with proposed values -> user reviews -> Phase 2 injects only approved items."
302
+
303
+ Return this exact checkpoint structure:
304
+
305
+ ```
306
+ CHECKPOINT_RETURN:
307
+ completed: "Scanned {N} files, found {M} interactive elements, {X} missing data-testid"
308
+ blocking: "Need user approval before injecting data-testid attributes into source code"
309
+ details:
310
+ coverage_score: "{X}%"
311
+ decision: "{SELECTIVE|TARGETED|FULL PASS|P0 FIRST}"
312
+ p0_missing: {count}
313
+ p1_missing: {count}
314
+ p2_missing: {count}
315
+ non_compliant_existing: {count}
316
+ report_path: "{path to TESTID_AUDIT_REPORT.md}"
317
+ awaiting: "User reviews proposed data-testid values in TESTID_AUDIT_REPORT.md and approves injection. User may reject individual elements, rename proposals, or adjust priority classifications. User may also approve renaming non-compliant existing values."
318
+ ```
319
+
320
+ **If running in auto-advance mode:**
321
+ Proceed with P0 defaults only -- inject only P0 elements (form inputs, submit buttons, primary actions, form tags, modal triggers and containers). P1 and P2 elements are deferred as an optional follow-up. This matches the CONTEXT.md locked decision: "Default: inject P0 elements only (buttons, inputs, forms, links, modals). P1-P2 offered as optional follow-up."
322
+
323
+ **If user provides feedback:**
324
+ - **Approved as-is:** Proceed to phase_3_inject with all proposed elements.
325
+ - **Rejected elements:** Remove those elements from the injection list.
326
+ - **Renamed proposals:** Use the user's preferred names instead of the proposed names.
327
+ - **Approved existing renames:** Add those existing values to the injection list as renames.
328
+ - **Changed priorities:** Update priority classifications per user feedback.
329
+ - **Partial approval:** Inject only the approved elements.
330
+ </step>
331
+
332
+ <step name="phase_3_inject">
333
+ Inject approved data-testid attributes into source files on a separate branch.
334
+
335
+ **Per CONTEXT.md locked decision: "Injects on a separate branch: qa/testid-inject-{date}. Working copy stays clean. User merges if approved."**
336
+
337
+ 1. **Create the injection branch:**
338
+ ```bash
339
+ git checkout -b qa/testid-inject-$(date +%Y-%m-%d)
340
+ ```
341
+ This creates a dedicated branch so the main working copy remains clean. The user can review the changes and merge the branch if they approve.
342
+
343
+ 2. **Determine the injection list:**
344
+ - If user reviewed and approved: inject only approved elements.
345
+ - If auto-advance mode: inject only P0 elements (per CONTEXT.md default).
346
+ - Per CONTEXT.md: "Default: inject P0 elements only (buttons, inputs, forms, links, modals). P1-P2 offered as optional follow-up."
347
+
348
+ 3. **For each file with approved elements (process in the priority order from phase_1_scan):**
349
+
350
+ a. Read the current file content.
351
+ b. For each approved element in this file (in REVERSE line order -- bottom to top -- to preserve line numbers):
352
+ - Locate the element's opening tag at the recorded line number.
353
+ - Add `data-testid` as the LAST attribute before the closing `>` of the opening tag.
354
+ - **Framework-specific injection syntax:**
355
+
356
+ **JSX/TSX (React):**
357
+ ```jsx
358
+ // Static value
359
+ <button className="btn" onClick={handleSubmit} data-testid="checkout-submit-btn">Submit</button>
360
+
361
+ // Dynamic list items -- use template literals
362
+ <div key={item.id} className="card" data-testid={`product-${item.id}-card`}>{item.name}</div>
363
+
364
+ // Spread props -- add AFTER the spread
365
+ <Input {...field} placeholder="Email" data-testid="login-email-input" />
366
+ ```
367
+
368
+ **Vue (.vue template):**
369
+ ```html
370
+ <!-- Static value -->
371
+ <button class="btn" @click="handleSubmit" data-testid="checkout-submit-btn">Submit</button>
372
+
373
+ <!-- Dynamic list items -- use v-bind shorthand -->
374
+ <div v-for="item in items" :key="item.id" class="card" :data-testid="`product-${item.id}-card`">{{ item.name }}</div>
375
+ ```
376
+
377
+ **Angular (.component.html):**
378
+ ```html
379
+ <!-- Static value -->
380
+ <button class="btn" (click)="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
381
+
382
+ <!-- Dynamic list items -- use attribute binding -->
383
+ <div *ngFor="let item of items" class="card" [attr.data-testid]="'product-' + item.id + '-card'">{{ item.name }}</div>
384
+ ```
385
+
386
+ **Plain HTML:**
387
+ ```html
388
+ <!-- Static value only (no dynamic binding available) -->
389
+ <button class="btn" onclick="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
390
+ ```
391
+
392
+ - **Third-party component handling (in priority order):**
393
+
394
+ 1. **Props passthrough** (preferred) -- If the library supports passing `data-testid` as a prop:
395
+ ```jsx
396
+ <MuiButton variant="contained" onClick={submit} data-testid="checkout-pay-btn">Pay</MuiButton>
397
+ ```
398
+
399
+ 2. **Wrapper div** -- If the library does NOT support prop passthrough:
400
+ ```jsx
401
+ <div data-testid="checkout-pay-container">
402
+ <ThirdPartyButton>Pay</ThirdPartyButton>
403
+ </div>
404
+ ```
405
+
406
+ 3. **inputProps / slotProps** (MUI-specific) -- Use component-specific prop APIs:
407
+ ```jsx
408
+ <TextField inputProps={{ 'data-testid': 'login-email-input' }} />
409
+ <Autocomplete slotProps={{ input: { 'data-testid': 'search-query-input' } }} />
410
+ ```
411
+
412
+ c. **Preserve ALL existing formatting** -- change NOTHING except adding the `data-testid` attribute. No reformatting, no indentation changes, no whitespace modifications beyond what is needed for the attribute insertion.
413
+
414
+ d. **Per CONTEXT.md locked decision: "Existing data-testid values: preserved as-is."** -- Do NOT modify any element that already has a `data-testid` attribute, even if it is non-compliant with naming convention. Non-compliant values were reported in the audit for user review.
415
+
416
+ e. Write the modified file back to disk.
417
+
418
+ 4. **Handle user-approved renames of existing non-compliant values (only if user explicitly approved in the checkpoint):**
419
+ - For each approved rename: find the existing `data-testid="old-value"` and replace with `data-testid="new-value"`.
420
+ - Track these separately in the changelog as "RENAMED" (not "INJECTED").
421
+ </step>
422
+
423
+ <step name="phase_4_validate">
424
+ Validate all modified files to ensure injections are correct, unique, and non-interfering.
425
+
426
+ **1. Syntax check:**
427
+ Run the appropriate linter or compiler on each modified file to verify no syntax errors were introduced:
428
+ - React/TypeScript: `npx tsc --noEmit --jsx react-jsx {file}` or project-specific linter
429
+ - Vue: `npx vue-tsc --noEmit {file}` or project linter
430
+ - Angular: `npx ng lint` or project linter
431
+ - Plain HTML: Basic syntax validation (balanced tags, properly quoted attributes)
432
+ - Fallback: If the project has a configured linter (`npm run lint`), use that.
433
+
434
+ If syntax check fails on a file: revert the specific file to its pre-injection state, record the failure, and report the issue in the changelog. Do NOT leave a syntactically broken file.
435
+
436
+ **2. Uniqueness check:**
437
+ Scan all modified files plus existing files in the same page/route scope. Verify:
438
+ - No two elements on the same rendered page share a `data-testid` value.
439
+ - Dynamic template literals are structurally unique (e.g., `product-${item.id}-card` is unique by ID).
440
+ - If a duplicate is found: rename the newer injection to add more specific context.
441
+
442
+ **3. Convention compliance check:**
443
+ Verify every injected `data-testid` value follows the `{context}-{description}-{element-type}` pattern:
444
+ - Is kebab-case (no camelCase, no underscores, no periods)
445
+ - Ends with a valid element-type suffix from the suffix table
446
+ - Starts with a context prefix derived from the component/page name
447
+ - Max 3 levels of nesting in the context
448
+ - Dynamic values use template literals with unique keys
449
+
450
+ If any injected value fails compliance: fix the value to comply before finalizing.
451
+
452
+ **4. Non-interference check:**
453
+ Diff each modified file against its pre-injection version. Verify:
454
+ - The ONLY changes are `data-testid` attribute additions (or approved renames).
455
+ - No other code was modified (no formatting changes, no logic changes, no import changes).
456
+ - All original attributes, whitespace patterns, and code structure are preserved.
457
+
458
+ If the diff shows ANY change beyond data-testid additions: revert the file and re-inject more carefully.
459
+
460
+ **Validation summary:**
461
+ Track the results of all 4 checks per file:
462
+ - file_path
463
+ - syntax_check: PASS or FAIL (with error details)
464
+ - uniqueness_check: PASS or FAIL (with duplicate details)
465
+ - convention_check: PASS or FAIL (with non-compliant values)
466
+ - non_interference_check: PASS or FAIL (with unexpected changes)
467
+ </step>
468
+
469
+ <step name="produce_report">
470
+ Write the final reports and commit on the injection branch.
471
+
472
+ **1. Update TESTID_AUDIT_REPORT.md with post-injection results:**
473
+ If the report was already written in phase_2_audit, update it with:
474
+ - Final injection counts (elements injected vs. deferred)
475
+ - Updated coverage score (post-injection)
476
+ - Updated decision gate status
477
+
478
+ If the report was not yet written (e.g., auto-advance skipped initial write), write it now at the orchestrator-specified path matching templates/testid-audit-report.md exactly with all 5 sections.
479
+
480
+ **2. Write INJECTION_CHANGELOG.md** documenting every injection action:
481
+
482
+ ```markdown
483
+ # Injection Changelog
484
+
485
+ ## Summary
486
+ - Files modified: {N}
487
+ - Test IDs injected: {N}
488
+ - Test IDs already present (preserved): {N}
489
+ - Test IDs deferred (P1/P2 not approved): {N}
490
+ - Test IDs renamed (user-approved): {N}
491
+ - Validation failures (reverted): {N}
492
+
493
+ ## Changes Per File
494
+
495
+ ### {filename.ext} -- {ComponentName}
496
+
497
+ | Line | Element | data-testid Value | Action | Priority |
498
+ |------|---------|-------------------|--------|----------|
499
+ | {line} | {tag} | {value} | INJECTED | {P0/P1/P2} |
500
+ | {line} | {tag} | {value} | EXISTING (preserved) | {P0/P1/P2} |
501
+ | {line} | {tag} | {value} | DEFERRED | {P1/P2} |
502
+ | {line} | {tag} | {old} -> {new} | RENAMED | {P0/P1/P2} |
503
+ | {line} | {tag} | {value} | REVERTED (syntax error) | {P0/P1/P2} |
504
+
505
+ [... repeat for each modified file ...]
506
+
507
+ ## Validation Results
508
+
509
+ | File | Syntax | Uniqueness | Convention | Non-Interference |
510
+ |------|--------|------------|------------|-----------------|
511
+ | {file} | PASS | PASS | PASS | PASS |
512
+ [... per file ...]
513
+ ```
514
+
515
+ **3. Commit on the injection branch:**
516
+ ```bash
517
+ node bin/qaa-tools.cjs commit "qa(testid-injector): inject {N} data-testid attributes across {M} components" --files {modified_source_files} {report_path} {changelog_path}
518
+ ```
519
+
520
+ Replace `{N}` with the actual count of injected data-testid attributes, `{M}` with the count of modified component files, and `{modified_source_files}`, `{report_path}`, `{changelog_path}` with actual file paths.
521
+ </step>
522
+
523
+ <step name="return_results">
524
+ Return structured results to the orchestrator.
525
+
526
+ After writing reports and committing, return this exact structure:
527
+
528
+ ```
529
+ INJECTOR_COMPLETE:
530
+ report_path: "{TESTID_AUDIT_REPORT.md path}"
531
+ changelog_path: "{INJECTION_CHANGELOG.md path}"
532
+ branch: "qa/testid-inject-{YYYY-MM-DD}"
533
+ coverage_before: {X}%
534
+ coverage_after: {Y}%
535
+ elements_injected: {count}
536
+ elements_deferred: {count}
537
+ elements_existing_preserved: {count}
538
+ files_modified: {count}
539
+ non_compliant_reported: {count}
540
+ non_compliant_renamed: {count}
541
+ validation_passed: {true/false}
542
+ commit_hash: "{hash}"
543
+ ```
544
+
545
+ Field definitions:
546
+ - `report_path`: Full path to the TESTID_AUDIT_REPORT.md file
547
+ - `changelog_path`: Full path to the INJECTION_CHANGELOG.md file
548
+ - `branch`: Name of the injection branch (format: `qa/testid-inject-{YYYY-MM-DD}`)
549
+ - `coverage_before`: Coverage percentage before injection (from audit)
550
+ - `coverage_after`: Coverage percentage after injection
551
+ - `elements_injected`: Count of data-testid attributes actually injected
552
+ - `elements_deferred`: Count of elements not injected (P1/P2 deferred, user-rejected)
553
+ - `elements_existing_preserved`: Count of existing data-testid values left untouched
554
+ - `files_modified`: Count of source files that were modified
555
+ - `non_compliant_reported`: Count of existing non-compliant data-testid values reported in audit
556
+ - `non_compliant_renamed`: Count of non-compliant values renamed (only if user approved)
557
+ - `validation_passed`: Whether all 4 validation checks passed on all files
558
+ - `commit_hash`: Git commit hash on the injection branch
559
+
560
+ **Pipeline continuation:**
561
+ After returning results, the orchestrator advances the pipeline. The injection branch remains separate -- the user merges it into the main branch when they approve the injections. Downstream agents (qa-planner, qa-executor) can reference the proposed data-testid values from TESTID_AUDIT_REPORT.md when generating test files that use `getByTestId()` selectors.
562
+ </step>
563
+
564
+ </process>
565
+
566
+ <output>
567
+ The testid-injector agent produces these artifacts:
568
+
569
+ **Always produced:**
570
+ - **TESTID_AUDIT_REPORT.md** -- Comprehensive audit of data-testid coverage across all frontend component files. Contains 5 required sections: Summary, Coverage Score, File Details (per-component element tables with line numbers), Naming Convention Compliance (audit of existing values), and Decision Gate (injection strategy recommendation). Written to the output path specified by the orchestrator. Format matches templates/testid-audit-report.md exactly.
571
+
572
+ **Produced after injection approval:**
573
+ - **INJECTION_CHANGELOG.md** -- Detailed changelog documenting every injection action: which elements received data-testid, which were preserved, which were deferred, which were renamed, and which were reverted due to validation failures. Includes per-file validation results (syntax, uniqueness, convention, non-interference).
574
+ - **Modified source files** -- Frontend component files with `data-testid` attributes injected. All modifications are on a separate branch: `qa/testid-inject-{YYYY-MM-DD}`. Existing data-testid values are preserved as-is. Only approved elements are modified.
575
+
576
+ **Return to orchestrator:**
577
+
578
+ ```
579
+ INJECTOR_COMPLETE:
580
+ report_path: "{TESTID_AUDIT_REPORT.md path}"
581
+ changelog_path: "{INJECTION_CHANGELOG.md path}"
582
+ branch: "qa/testid-inject-{YYYY-MM-DD}"
583
+ coverage_before: {X}%
584
+ coverage_after: {Y}%
585
+ elements_injected: {count}
586
+ elements_deferred: {count}
587
+ elements_existing_preserved: {count}
588
+ files_modified: {count}
589
+ non_compliant_reported: {count}
590
+ non_compliant_renamed: {count}
591
+ validation_passed: {true/false}
592
+ commit_hash: "{hash}"
593
+ ```
594
+
595
+ **If skipped (has_frontend: false):**
596
+
597
+ ```
598
+ INJECTOR_SKIPPED:
599
+ reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
600
+ action: "Pipeline should skip testid-inject stage and proceed directly to plan"
601
+ ```
602
+ </output>
603
+
604
+ <quality_gate>
605
+ Before considering this agent's work complete, verify ALL of the following.
606
+
607
+ **From templates/testid-audit-report.md quality gate (all 8 items -- VERBATIM):**
608
+
609
+ - [ ] Every interactive element across all scanned files has an entry in the File Details section
610
+ - [ ] All proposed `data-testid` values follow the `{context}-{description}-{element-type}` convention
611
+ - [ ] No duplicate `data-testid` values exist within the same page/route scope
612
+ - [ ] Coverage Score formula is shown explicitly with the correct calculation
613
+ - [ ] Decision Gate recommendation matches the coverage score thresholds
614
+ - [ ] All existing `data-testid` values are audited in the Naming Convention Compliance section
615
+ - [ ] Priority assignments are consistent: form inputs and submit buttons are P0, navigation and feedback are P1, decorative elements are P2
616
+ - [ ] Line numbers are included for every element in every File Details table
617
+
618
+ **Additional injector-specific checks:**
619
+
620
+ - [ ] Injection happens on a separate branch (`qa/testid-inject-{YYYY-MM-DD}`)
621
+ - [ ] Existing `data-testid` values are preserved as-is (not modified, not renamed without explicit user approval)
622
+ - [ ] Only approved items are injected (audit-first workflow respected: audit produced -> user reviewed -> only approved elements injected)
623
+ - [ ] Framework-specific injection syntax is correct for each file type (JSX attributes for React, HTML attributes for Vue templates, `[attr.data-testid]` binding for Angular dynamic values, standard attributes for plain HTML)
624
+ - [ ] No source code changes beyond `data-testid` additions (non-interference check passed on all files)
625
+ - [ ] Dynamic list items use template literals with unique keys (e.g., `data-testid={`product-${item.id}-card`}` for JSX, `:data-testid="`product-${item.id}-card`"` for Vue)
626
+
627
+ If any check fails, fix the issue before considering the agent's work complete. Do not proceed with a failing quality gate.
628
+ </quality_gate>
629
+
630
+ <success_criteria>
631
+ The testid-injector agent has completed successfully when:
632
+
633
+ 1. TESTID_AUDIT_REPORT.md exists at the orchestrator-specified output path with all 5 required sections (Summary, Coverage Score, File Details, Naming Convention Compliance, Decision Gate) populated with data from the scanned repository
634
+ 2. Injection was performed on a separate branch named `qa/testid-inject-{YYYY-MM-DD}` -- the main working copy was not modified
635
+ 3. All existing `data-testid` values were preserved as-is (no modifications to existing values without explicit user approval)
636
+ 4. Only approved elements were injected (P0 only in auto-advance mode, or user-approved set after checkpoint review)
637
+ 5. All modified files pass syntax validation -- no syntax errors introduced by injection
638
+ 6. No duplicate `data-testid` values exist within any page/route scope
639
+ 7. INJECTION_CHANGELOG.md documents every injection action with file, line, element, value, and action status
640
+ 8. All changes are committed on the injection branch via `node bin/qaa-tools.cjs commit`
641
+ 9. Structured return values provided to orchestrator: report_path, changelog_path, branch name, coverage scores (before/after), element counts, validation status, commit hash
642
+ 10. All quality gate checks pass (8 template items + 6 injector-specific items)
643
+ </success_criteria>