qaa-agent 1.0.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.
- package/.claude/commands/create-test.md +40 -0
- package/.claude/commands/qa-analyze.md +60 -0
- package/.claude/commands/qa-audit.md +37 -0
- package/.claude/commands/qa-blueprint.md +54 -0
- package/.claude/commands/qa-fix.md +36 -0
- package/.claude/commands/qa-from-ticket.md +88 -0
- package/.claude/commands/qa-gap.md +54 -0
- package/.claude/commands/qa-pom.md +36 -0
- package/.claude/commands/qa-pyramid.md +37 -0
- package/.claude/commands/qa-report.md +38 -0
- package/.claude/commands/qa-start.md +33 -0
- package/.claude/commands/qa-testid.md +54 -0
- package/.claude/commands/qa-validate.md +54 -0
- package/.claude/commands/update-test.md +58 -0
- package/.claude/settings.json +19 -0
- package/.claude/skills/qa-bug-detective/SKILL.md +122 -0
- package/.claude/skills/qa-repo-analyzer/SKILL.md +88 -0
- package/.claude/skills/qa-self-validator/SKILL.md +109 -0
- package/.claude/skills/qa-template-engine/SKILL.md +113 -0
- package/.claude/skills/qa-testid-injector/SKILL.md +93 -0
- package/.claude/skills/qa-workflow-documenter/SKILL.md +87 -0
- package/CLAUDE.md +543 -0
- package/README.md +418 -0
- package/agents/qa-pipeline-orchestrator.md +1217 -0
- package/agents/qaa-analyzer.md +508 -0
- package/agents/qaa-bug-detective.md +444 -0
- package/agents/qaa-executor.md +618 -0
- package/agents/qaa-planner.md +374 -0
- package/agents/qaa-scanner.md +422 -0
- package/agents/qaa-testid-injector.md +583 -0
- package/agents/qaa-validator.md +450 -0
- package/bin/install.cjs +176 -0
- package/bin/lib/commands.cjs +709 -0
- package/bin/lib/config.cjs +307 -0
- package/bin/lib/core.cjs +497 -0
- package/bin/lib/frontmatter.cjs +299 -0
- package/bin/lib/init.cjs +989 -0
- package/bin/lib/milestone.cjs +241 -0
- package/bin/lib/model-profiles.cjs +60 -0
- package/bin/lib/phase.cjs +911 -0
- package/bin/lib/roadmap.cjs +306 -0
- package/bin/lib/state.cjs +748 -0
- package/bin/lib/template.cjs +222 -0
- package/bin/lib/verify.cjs +842 -0
- package/bin/qaa-tools.cjs +607 -0
- package/package.json +34 -0
- package/templates/failure-classification.md +391 -0
- package/templates/gap-analysis.md +409 -0
- package/templates/pr-template.md +48 -0
- package/templates/qa-analysis.md +381 -0
- package/templates/qa-audit-report.md +465 -0
- package/templates/qa-repo-blueprint.md +636 -0
- package/templates/scan-manifest.md +312 -0
- package/templates/test-inventory.md +582 -0
- package/templates/testid-audit-report.md +354 -0
- package/templates/validation-report.md +243 -0
|
@@ -0,0 +1,583 @@
|
|
|
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
|
+
Note: Read ALL files in full. Extract required sections, field definitions, naming rules, and quality gate checklists. These define your behavioral contract.
|
|
46
|
+
</required_reading>
|
|
47
|
+
|
|
48
|
+
<process>
|
|
49
|
+
|
|
50
|
+
<step name="read_inputs" priority="first">
|
|
51
|
+
Read all required input files before any scanning, auditing, or injection work.
|
|
52
|
+
|
|
53
|
+
1. **Read SCAN_MANIFEST.md** completely (path from orchestrator's files_to_read):
|
|
54
|
+
- Extract `has_frontend` flag from the Decision Gate section.
|
|
55
|
+
- **If `has_frontend: false`:** STOP immediately. Do NOT proceed with any scanning or auditing. Return this message to the orchestrator:
|
|
56
|
+
```
|
|
57
|
+
INJECTOR_SKIPPED:
|
|
58
|
+
reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
|
|
59
|
+
action: "Pipeline should skip testid-inject stage and proceed directly to plan"
|
|
60
|
+
```
|
|
61
|
+
- If `has_frontend: true`: continue.
|
|
62
|
+
- Extract the component file list from the File List section -- collect file paths, component names, types, and interaction density ratings.
|
|
63
|
+
- Extract framework detection from Project Detection section (framework name, component_pattern).
|
|
64
|
+
- Note the package manager and build tool for later validation step.
|
|
65
|
+
|
|
66
|
+
2. **Read CLAUDE.md** -- Focus on:
|
|
67
|
+
- data-testid Convention section (full naming pattern, context derivation, element-type suffix table, third-party handling, dynamic list items)
|
|
68
|
+
- Module Boundaries table (confirm: reads SCAN_MANIFEST.md + source files + CLAUDE.md, produces TESTID_AUDIT_REPORT.md + modified source files)
|
|
69
|
+
- Verification Commands for TESTID_AUDIT_REPORT.md (coverage score, naming convention, no duplicates, priority classification, decision gate)
|
|
70
|
+
- Locator Strategy (Tier 1 includes data-testid)
|
|
71
|
+
|
|
72
|
+
3. **Read data-testid-SKILL.md** completely:
|
|
73
|
+
- Extract the element-type suffix table (20+ entries)
|
|
74
|
+
- Extract context derivation rules for all 4 categories
|
|
75
|
+
- Extract framework-specific injection syntax for JSX, Vue, Angular, HTML
|
|
76
|
+
- Extract edge case handling rules (conditional rendering, portals, fragments)
|
|
77
|
+
- Extract naming rules (kebab-case, no prefixes, unique per page)
|
|
78
|
+
|
|
79
|
+
4. **Read templates/testid-audit-report.md** completely:
|
|
80
|
+
- Extract the 5 required sections and all field definitions
|
|
81
|
+
- Extract the priority definitions table (P0, P1, P2)
|
|
82
|
+
- Extract the coverage score formula
|
|
83
|
+
- Extract the decision matrix thresholds
|
|
84
|
+
- Extract the quality gate checklist (8 items)
|
|
85
|
+
- Study the worked example to understand expected depth and format
|
|
86
|
+
|
|
87
|
+
5. Store all extracted rules in working memory. Every rule affects output quality.
|
|
88
|
+
</step>
|
|
89
|
+
|
|
90
|
+
<step name="phase_1_scan">
|
|
91
|
+
Detect the frontend framework and enumerate all component files that need auditing.
|
|
92
|
+
|
|
93
|
+
**Framework detection:**
|
|
94
|
+
|
|
95
|
+
Detect the frontend framework from package.json dependencies and file extensions:
|
|
96
|
+
|
|
97
|
+
| Framework | Package.json Indicators | File Extensions |
|
|
98
|
+
|-----------|------------------------|-----------------|
|
|
99
|
+
| React | `react`, `react-dom`, `next`, `gatsby` | `*.jsx`, `*.tsx` |
|
|
100
|
+
| Vue | `vue`, `nuxt`, `@vue/cli-service` | `*.vue` |
|
|
101
|
+
| Angular | `@angular/core`, `@angular/cli` | `*.component.html`, `*.component.ts` |
|
|
102
|
+
| Svelte | `svelte`, `@sveltejs/kit` | `*.svelte` |
|
|
103
|
+
| Plain HTML | None of the above | `*.html` (excluding build output, node_modules) |
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
**Component file enumeration:**
|
|
108
|
+
|
|
109
|
+
Use the Glob tool to discover all component files:
|
|
110
|
+
|
|
111
|
+
- React: `**/*.{jsx,tsx}`
|
|
112
|
+
- Vue: `**/*.vue`
|
|
113
|
+
- Angular: `**/*.component.html`
|
|
114
|
+
- Svelte: `**/*.svelte`
|
|
115
|
+
- Plain HTML: `**/*.html`
|
|
116
|
+
|
|
117
|
+
**Exclusion rules -- skip these files entirely:**
|
|
118
|
+
- Test files: `*.test.*`, `*.spec.*`
|
|
119
|
+
- Story files: `*.stories.*`
|
|
120
|
+
- Type definitions: `*.d.ts`
|
|
121
|
+
- Build output: `dist/`, `build/`, `out/`, `.next/`, `.nuxt/`, `.svelte-kit/`
|
|
122
|
+
- Dependencies: `node_modules/`
|
|
123
|
+
- Config-only files: `*.config.*`
|
|
124
|
+
|
|
125
|
+
**Sort by interaction density priority:**
|
|
126
|
+
1. Forms (files containing `<form>`, `onSubmit`, `handleSubmit`, form state management) -- HIGH
|
|
127
|
+
2. Pages/views (files in `pages/`, `views/`, `app/` directories, or named `*Page.*`) -- MEDIUM-HIGH
|
|
128
|
+
3. Interactive components (files with buttons, inputs, modals, dropdowns) -- MEDIUM
|
|
129
|
+
4. Layout components (headers, footers, sidebars, navigation bars) -- MEDIUM-LOW
|
|
130
|
+
5. Display-only components (cards, badges, static content) -- LOW
|
|
131
|
+
|
|
132
|
+
**Decision gate:**
|
|
133
|
+
|
|
134
|
+
If 0 component files found despite `has_frontend: true`:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
CHECKPOINT_RETURN:
|
|
138
|
+
completed: "Scanned file tree, detected frontend framework indicators, but found no component files"
|
|
139
|
+
blocking: "No frontend component files found despite has_frontend=true in SCAN_MANIFEST.md"
|
|
140
|
+
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."
|
|
141
|
+
awaiting: "User confirms component file location or provides additional file patterns to search"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
If component files are found, proceed to phase_2_audit.
|
|
145
|
+
</step>
|
|
146
|
+
|
|
147
|
+
<step name="phase_2_audit">
|
|
148
|
+
For each component file, identify every interactive element and produce the TESTID_AUDIT_REPORT.md.
|
|
149
|
+
|
|
150
|
+
**For each component file (in priority order from phase_1_scan):**
|
|
151
|
+
|
|
152
|
+
1. **Read the file source** completely using the Read tool.
|
|
153
|
+
|
|
154
|
+
2. **Identify ALL interactive elements** by scanning for these HTML tags and patterns:
|
|
155
|
+
|
|
156
|
+
| Element Type | What to Look For |
|
|
157
|
+
|-------------|-----------------|
|
|
158
|
+
| Buttons | `<button>`, `<Button>`, elements with `onClick`/`@click`/`(click)` |
|
|
159
|
+
| Text inputs | `<input type="text">`, `<input type="email">`, `<input type="password">`, `<input type="search">`, `<input type="tel">`, `<input type="url">`, `<input type="number">` |
|
|
160
|
+
| Selects | `<select>`, `<Select>` |
|
|
161
|
+
| Textareas | `<textarea>`, `<Textarea>` |
|
|
162
|
+
| Links | `<a href="...">`, `<Link to="...">`, `<router-link>`, `<NuxtLink>` |
|
|
163
|
+
| Forms | `<form>`, `<Form>` |
|
|
164
|
+
| Images (dynamic) | `<img>` when showing product/user/dynamic data (not icons or static assets) |
|
|
165
|
+
| Tables | `<table>`, `<Table>` |
|
|
166
|
+
| Modals/Dialogs | `<dialog>`, `<Modal>`, `<Dialog>`, elements with `role="dialog"` |
|
|
167
|
+
| Dropdowns | Custom dropdown components, `<details>`, `<Dropdown>`, `<Menu>` |
|
|
168
|
+
| Toggles | `<input type="checkbox">` styled as toggle, `<Switch>`, `<Toggle>` |
|
|
169
|
+
| Checkboxes | `<input type="checkbox">` |
|
|
170
|
+
| Radios | `<input type="radio">` |
|
|
171
|
+
| Tabs | `<Tab>`, tab navigation elements |
|
|
172
|
+
| Alerts/Toasts | Error messages, success messages, notification elements |
|
|
173
|
+
|
|
174
|
+
3. **For each identified element, record:**
|
|
175
|
+
- **Line number**: Exact line in the source file
|
|
176
|
+
- **Element tag and type**: e.g., `<button type="submit">`, `<input type="email">`
|
|
177
|
+
- **Current selector state**: One of:
|
|
178
|
+
- `data-testid="value"` -- if it already has a data-testid attribute
|
|
179
|
+
- `className="..."` -- if it has a class but no data-testid
|
|
180
|
+
- `name="..."` -- if it has a name attribute but no data-testid
|
|
181
|
+
- `id="..."` -- if it has an id but no data-testid
|
|
182
|
+
- `none` -- if it has no identifying selector at all
|
|
183
|
+
|
|
184
|
+
4. **Classify each element by priority:**
|
|
185
|
+
|
|
186
|
+
| Priority | Label | Elements |
|
|
187
|
+
|----------|-------|----------|
|
|
188
|
+
| P0 | Must Have | Form `<input>`, `<select>`, `<textarea>`, submit `<button>`, primary action buttons, `<form>` tags, modal triggers and containers |
|
|
189
|
+
| P1 | Should Have | Navigation `<a>` links, secondary buttons, error/alert messages, toggle/checkbox/radio controls, dropdown triggers |
|
|
190
|
+
| P2 | Nice to Have | Images showing dynamic product/user data, badges/chips, decorative containers with dynamic content, table display elements |
|
|
191
|
+
|
|
192
|
+
5. **For elements WITH existing `data-testid`:**
|
|
193
|
+
- Mark as `EXISTING -- no change` in the Proposed data-testid column
|
|
194
|
+
- Do NOT modify the existing value -- per CONTEXT.md locked decision: "Existing data-testid values: preserved as-is."
|
|
195
|
+
- The existing value WILL be audited for naming convention compliance in Section 4 (Naming Convention Compliance), but it will NOT be auto-renamed.
|
|
196
|
+
|
|
197
|
+
6. **For elements WITHOUT `data-testid`:**
|
|
198
|
+
- Propose a value following the `{context}-{description}-{element-type}` convention from data-testid-SKILL.md.
|
|
199
|
+
- **Context derivation:**
|
|
200
|
+
- Page-level: Derive from component filename. `LoginPage.tsx` -> `login`. `ProductDetailPage.tsx` -> `product-detail`.
|
|
201
|
+
- Component-level: Derive from component name. `<NavBar>` -> `navbar`. `<ShoppingCart>` -> `shopping-cart`.
|
|
202
|
+
- Nested: Use parent-child hierarchy, max 3 levels. `checkout-shipping-address-input` (page -> section -> field).
|
|
203
|
+
- **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`).
|
|
204
|
+
- **Dynamic list items:** Use template literal syntax. `data-testid={`product-${product.id}-card`}` (JSX) or `:data-testid="`product-${item.id}-card`"` (Vue).
|
|
205
|
+
- **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.
|
|
206
|
+
|
|
207
|
+
7. **Calculate coverage score:**
|
|
208
|
+
```
|
|
209
|
+
Current Coverage = (elements_with_testid / total_interactive_elements) * 100
|
|
210
|
+
Projected Coverage = ((elements_with_testid + elements_missing_testid) / total_interactive_elements) * 100
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
8. **Apply decision gate thresholds:**
|
|
214
|
+
|
|
215
|
+
| Coverage | Decision | Strategy |
|
|
216
|
+
|----------|----------|----------|
|
|
217
|
+
| > 90% | SELECTIVE | Inject only P0 missing elements |
|
|
218
|
+
| 50% - 90% | TARGETED | Inject P0 and P1 missing elements |
|
|
219
|
+
| 1% - 49% | FULL PASS | Inject all P0, P1, P2 elements |
|
|
220
|
+
| 0% | P0 FIRST | Inject P0 elements only, then re-audit |
|
|
221
|
+
| 0 files scanned | STOP | No frontend component files detected -- abort injection |
|
|
222
|
+
|
|
223
|
+
9. **Audit existing `data-testid` values for naming convention compliance:**
|
|
224
|
+
- For each existing `data-testid` value, check:
|
|
225
|
+
- Is it kebab-case? (no camelCase, no snake_case, no PascalCase)
|
|
226
|
+
- Does it end with an element-type suffix? (`-btn`, `-input`, `-link`, etc.)
|
|
227
|
+
- Does it start with a context prefix derived from the component?
|
|
228
|
+
- Does it have no framework-specific prefixes? (no `cy-`, `pw-`, `qa-`)
|
|
229
|
+
- Record compliant/non-compliant status and suggested rename for non-compliant values.
|
|
230
|
+
- Non-compliant values are REPORTED but NOT auto-renamed. User decides per ID.
|
|
231
|
+
|
|
232
|
+
10. **Produce TESTID_AUDIT_REPORT.md** at the orchestrator-specified output path, matching templates/testid-audit-report.md exactly:
|
|
233
|
+
- Section 1: Summary (files_scanned, total_interactive_elements, elements_with_testid, elements_missing_testid, p0_missing, p1_missing, p2_missing)
|
|
234
|
+
- Section 2: Coverage Score (current_coverage, projected_coverage, score_interpretation)
|
|
235
|
+
- Section 3: File Details (per-file table with Line, Element, Current Selector, Proposed data-testid, Priority)
|
|
236
|
+
- Section 4: Naming Convention Compliance (existing values audited: compliant/non-compliant, issues, suggested renames)
|
|
237
|
+
- Section 5: Decision Gate (DECISION, REASON, ACTION, FILES, ELEMENTS)
|
|
238
|
+
</step>
|
|
239
|
+
|
|
240
|
+
<step name="audit_checkpoint">
|
|
241
|
+
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."
|
|
242
|
+
|
|
243
|
+
Return this exact checkpoint structure:
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
CHECKPOINT_RETURN:
|
|
247
|
+
completed: "Scanned {N} files, found {M} interactive elements, {X} missing data-testid"
|
|
248
|
+
blocking: "Need user approval before injecting data-testid attributes into source code"
|
|
249
|
+
details:
|
|
250
|
+
coverage_score: "{X}%"
|
|
251
|
+
decision: "{SELECTIVE|TARGETED|FULL PASS|P0 FIRST}"
|
|
252
|
+
p0_missing: {count}
|
|
253
|
+
p1_missing: {count}
|
|
254
|
+
p2_missing: {count}
|
|
255
|
+
non_compliant_existing: {count}
|
|
256
|
+
report_path: "{path to TESTID_AUDIT_REPORT.md}"
|
|
257
|
+
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."
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**If running in auto-advance mode:**
|
|
261
|
+
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."
|
|
262
|
+
|
|
263
|
+
**If user provides feedback:**
|
|
264
|
+
- **Approved as-is:** Proceed to phase_3_inject with all proposed elements.
|
|
265
|
+
- **Rejected elements:** Remove those elements from the injection list.
|
|
266
|
+
- **Renamed proposals:** Use the user's preferred names instead of the proposed names.
|
|
267
|
+
- **Approved existing renames:** Add those existing values to the injection list as renames.
|
|
268
|
+
- **Changed priorities:** Update priority classifications per user feedback.
|
|
269
|
+
- **Partial approval:** Inject only the approved elements.
|
|
270
|
+
</step>
|
|
271
|
+
|
|
272
|
+
<step name="phase_3_inject">
|
|
273
|
+
Inject approved data-testid attributes into source files on a separate branch.
|
|
274
|
+
|
|
275
|
+
**Per CONTEXT.md locked decision: "Injects on a separate branch: qa/testid-inject-{date}. Working copy stays clean. User merges if approved."**
|
|
276
|
+
|
|
277
|
+
1. **Create the injection branch:**
|
|
278
|
+
```bash
|
|
279
|
+
git checkout -b qa/testid-inject-$(date +%Y-%m-%d)
|
|
280
|
+
```
|
|
281
|
+
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.
|
|
282
|
+
|
|
283
|
+
2. **Determine the injection list:**
|
|
284
|
+
- If user reviewed and approved: inject only approved elements.
|
|
285
|
+
- If auto-advance mode: inject only P0 elements (per CONTEXT.md default).
|
|
286
|
+
- Per CONTEXT.md: "Default: inject P0 elements only (buttons, inputs, forms, links, modals). P1-P2 offered as optional follow-up."
|
|
287
|
+
|
|
288
|
+
3. **For each file with approved elements (process in the priority order from phase_1_scan):**
|
|
289
|
+
|
|
290
|
+
a. Read the current file content.
|
|
291
|
+
b. For each approved element in this file (in REVERSE line order -- bottom to top -- to preserve line numbers):
|
|
292
|
+
- Locate the element's opening tag at the recorded line number.
|
|
293
|
+
- Add `data-testid` as the LAST attribute before the closing `>` of the opening tag.
|
|
294
|
+
- **Framework-specific injection syntax:**
|
|
295
|
+
|
|
296
|
+
**JSX/TSX (React):**
|
|
297
|
+
```jsx
|
|
298
|
+
// Static value
|
|
299
|
+
<button className="btn" onClick={handleSubmit} data-testid="checkout-submit-btn">Submit</button>
|
|
300
|
+
|
|
301
|
+
// Dynamic list items -- use template literals
|
|
302
|
+
<div key={item.id} className="card" data-testid={`product-${item.id}-card`}>{item.name}</div>
|
|
303
|
+
|
|
304
|
+
// Spread props -- add AFTER the spread
|
|
305
|
+
<Input {...field} placeholder="Email" data-testid="login-email-input" />
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Vue (.vue template):**
|
|
309
|
+
```html
|
|
310
|
+
<!-- Static value -->
|
|
311
|
+
<button class="btn" @click="handleSubmit" data-testid="checkout-submit-btn">Submit</button>
|
|
312
|
+
|
|
313
|
+
<!-- Dynamic list items -- use v-bind shorthand -->
|
|
314
|
+
<div v-for="item in items" :key="item.id" class="card" :data-testid="`product-${item.id}-card`">{{ item.name }}</div>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Angular (.component.html):**
|
|
318
|
+
```html
|
|
319
|
+
<!-- Static value -->
|
|
320
|
+
<button class="btn" (click)="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
|
|
321
|
+
|
|
322
|
+
<!-- Dynamic list items -- use attribute binding -->
|
|
323
|
+
<div *ngFor="let item of items" class="card" [attr.data-testid]="'product-' + item.id + '-card'">{{ item.name }}</div>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Plain HTML:**
|
|
327
|
+
```html
|
|
328
|
+
<!-- Static value only (no dynamic binding available) -->
|
|
329
|
+
<button class="btn" onclick="handleSubmit()" data-testid="checkout-submit-btn">Submit</button>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- **Third-party component handling (in priority order):**
|
|
333
|
+
|
|
334
|
+
1. **Props passthrough** (preferred) -- If the library supports passing `data-testid` as a prop:
|
|
335
|
+
```jsx
|
|
336
|
+
<MuiButton variant="contained" onClick={submit} data-testid="checkout-pay-btn">Pay</MuiButton>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
2. **Wrapper div** -- If the library does NOT support prop passthrough:
|
|
340
|
+
```jsx
|
|
341
|
+
<div data-testid="checkout-pay-container">
|
|
342
|
+
<ThirdPartyButton>Pay</ThirdPartyButton>
|
|
343
|
+
</div>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
3. **inputProps / slotProps** (MUI-specific) -- Use component-specific prop APIs:
|
|
347
|
+
```jsx
|
|
348
|
+
<TextField inputProps={{ 'data-testid': 'login-email-input' }} />
|
|
349
|
+
<Autocomplete slotProps={{ input: { 'data-testid': 'search-query-input' } }} />
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
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.
|
|
353
|
+
|
|
354
|
+
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.
|
|
355
|
+
|
|
356
|
+
e. Write the modified file back to disk.
|
|
357
|
+
|
|
358
|
+
4. **Handle user-approved renames of existing non-compliant values (only if user explicitly approved in the checkpoint):**
|
|
359
|
+
- For each approved rename: find the existing `data-testid="old-value"` and replace with `data-testid="new-value"`.
|
|
360
|
+
- Track these separately in the changelog as "RENAMED" (not "INJECTED").
|
|
361
|
+
</step>
|
|
362
|
+
|
|
363
|
+
<step name="phase_4_validate">
|
|
364
|
+
Validate all modified files to ensure injections are correct, unique, and non-interfering.
|
|
365
|
+
|
|
366
|
+
**1. Syntax check:**
|
|
367
|
+
Run the appropriate linter or compiler on each modified file to verify no syntax errors were introduced:
|
|
368
|
+
- React/TypeScript: `npx tsc --noEmit --jsx react-jsx {file}` or project-specific linter
|
|
369
|
+
- Vue: `npx vue-tsc --noEmit {file}` or project linter
|
|
370
|
+
- Angular: `npx ng lint` or project linter
|
|
371
|
+
- Plain HTML: Basic syntax validation (balanced tags, properly quoted attributes)
|
|
372
|
+
- Fallback: If the project has a configured linter (`npm run lint`), use that.
|
|
373
|
+
|
|
374
|
+
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.
|
|
375
|
+
|
|
376
|
+
**2. Uniqueness check:**
|
|
377
|
+
Scan all modified files plus existing files in the same page/route scope. Verify:
|
|
378
|
+
- No two elements on the same rendered page share a `data-testid` value.
|
|
379
|
+
- Dynamic template literals are structurally unique (e.g., `product-${item.id}-card` is unique by ID).
|
|
380
|
+
- If a duplicate is found: rename the newer injection to add more specific context.
|
|
381
|
+
|
|
382
|
+
**3. Convention compliance check:**
|
|
383
|
+
Verify every injected `data-testid` value follows the `{context}-{description}-{element-type}` pattern:
|
|
384
|
+
- Is kebab-case (no camelCase, no underscores, no periods)
|
|
385
|
+
- Ends with a valid element-type suffix from the suffix table
|
|
386
|
+
- Starts with a context prefix derived from the component/page name
|
|
387
|
+
- Max 3 levels of nesting in the context
|
|
388
|
+
- Dynamic values use template literals with unique keys
|
|
389
|
+
|
|
390
|
+
If any injected value fails compliance: fix the value to comply before finalizing.
|
|
391
|
+
|
|
392
|
+
**4. Non-interference check:**
|
|
393
|
+
Diff each modified file against its pre-injection version. Verify:
|
|
394
|
+
- The ONLY changes are `data-testid` attribute additions (or approved renames).
|
|
395
|
+
- No other code was modified (no formatting changes, no logic changes, no import changes).
|
|
396
|
+
- All original attributes, whitespace patterns, and code structure are preserved.
|
|
397
|
+
|
|
398
|
+
If the diff shows ANY change beyond data-testid additions: revert the file and re-inject more carefully.
|
|
399
|
+
|
|
400
|
+
**Validation summary:**
|
|
401
|
+
Track the results of all 4 checks per file:
|
|
402
|
+
- file_path
|
|
403
|
+
- syntax_check: PASS or FAIL (with error details)
|
|
404
|
+
- uniqueness_check: PASS or FAIL (with duplicate details)
|
|
405
|
+
- convention_check: PASS or FAIL (with non-compliant values)
|
|
406
|
+
- non_interference_check: PASS or FAIL (with unexpected changes)
|
|
407
|
+
</step>
|
|
408
|
+
|
|
409
|
+
<step name="produce_report">
|
|
410
|
+
Write the final reports and commit on the injection branch.
|
|
411
|
+
|
|
412
|
+
**1. Update TESTID_AUDIT_REPORT.md with post-injection results:**
|
|
413
|
+
If the report was already written in phase_2_audit, update it with:
|
|
414
|
+
- Final injection counts (elements injected vs. deferred)
|
|
415
|
+
- Updated coverage score (post-injection)
|
|
416
|
+
- Updated decision gate status
|
|
417
|
+
|
|
418
|
+
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.
|
|
419
|
+
|
|
420
|
+
**2. Write INJECTION_CHANGELOG.md** documenting every injection action:
|
|
421
|
+
|
|
422
|
+
```markdown
|
|
423
|
+
# Injection Changelog
|
|
424
|
+
|
|
425
|
+
## Summary
|
|
426
|
+
- Files modified: {N}
|
|
427
|
+
- Test IDs injected: {N}
|
|
428
|
+
- Test IDs already present (preserved): {N}
|
|
429
|
+
- Test IDs deferred (P1/P2 not approved): {N}
|
|
430
|
+
- Test IDs renamed (user-approved): {N}
|
|
431
|
+
- Validation failures (reverted): {N}
|
|
432
|
+
|
|
433
|
+
## Changes Per File
|
|
434
|
+
|
|
435
|
+
### {filename.ext} -- {ComponentName}
|
|
436
|
+
|
|
437
|
+
| Line | Element | data-testid Value | Action | Priority |
|
|
438
|
+
|------|---------|-------------------|--------|----------|
|
|
439
|
+
| {line} | {tag} | {value} | INJECTED | {P0/P1/P2} |
|
|
440
|
+
| {line} | {tag} | {value} | EXISTING (preserved) | {P0/P1/P2} |
|
|
441
|
+
| {line} | {tag} | {value} | DEFERRED | {P1/P2} |
|
|
442
|
+
| {line} | {tag} | {old} -> {new} | RENAMED | {P0/P1/P2} |
|
|
443
|
+
| {line} | {tag} | {value} | REVERTED (syntax error) | {P0/P1/P2} |
|
|
444
|
+
|
|
445
|
+
[... repeat for each modified file ...]
|
|
446
|
+
|
|
447
|
+
## Validation Results
|
|
448
|
+
|
|
449
|
+
| File | Syntax | Uniqueness | Convention | Non-Interference |
|
|
450
|
+
|------|--------|------------|------------|-----------------|
|
|
451
|
+
| {file} | PASS | PASS | PASS | PASS |
|
|
452
|
+
[... per file ...]
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**3. Commit on the injection branch:**
|
|
456
|
+
```bash
|
|
457
|
+
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}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
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.
|
|
461
|
+
</step>
|
|
462
|
+
|
|
463
|
+
<step name="return_results">
|
|
464
|
+
Return structured results to the orchestrator.
|
|
465
|
+
|
|
466
|
+
After writing reports and committing, return this exact structure:
|
|
467
|
+
|
|
468
|
+
```
|
|
469
|
+
INJECTOR_COMPLETE:
|
|
470
|
+
report_path: "{TESTID_AUDIT_REPORT.md path}"
|
|
471
|
+
changelog_path: "{INJECTION_CHANGELOG.md path}"
|
|
472
|
+
branch: "qa/testid-inject-{YYYY-MM-DD}"
|
|
473
|
+
coverage_before: {X}%
|
|
474
|
+
coverage_after: {Y}%
|
|
475
|
+
elements_injected: {count}
|
|
476
|
+
elements_deferred: {count}
|
|
477
|
+
elements_existing_preserved: {count}
|
|
478
|
+
files_modified: {count}
|
|
479
|
+
non_compliant_reported: {count}
|
|
480
|
+
non_compliant_renamed: {count}
|
|
481
|
+
validation_passed: {true/false}
|
|
482
|
+
commit_hash: "{hash}"
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Field definitions:
|
|
486
|
+
- `report_path`: Full path to the TESTID_AUDIT_REPORT.md file
|
|
487
|
+
- `changelog_path`: Full path to the INJECTION_CHANGELOG.md file
|
|
488
|
+
- `branch`: Name of the injection branch (format: `qa/testid-inject-{YYYY-MM-DD}`)
|
|
489
|
+
- `coverage_before`: Coverage percentage before injection (from audit)
|
|
490
|
+
- `coverage_after`: Coverage percentage after injection
|
|
491
|
+
- `elements_injected`: Count of data-testid attributes actually injected
|
|
492
|
+
- `elements_deferred`: Count of elements not injected (P1/P2 deferred, user-rejected)
|
|
493
|
+
- `elements_existing_preserved`: Count of existing data-testid values left untouched
|
|
494
|
+
- `files_modified`: Count of source files that were modified
|
|
495
|
+
- `non_compliant_reported`: Count of existing non-compliant data-testid values reported in audit
|
|
496
|
+
- `non_compliant_renamed`: Count of non-compliant values renamed (only if user approved)
|
|
497
|
+
- `validation_passed`: Whether all 4 validation checks passed on all files
|
|
498
|
+
- `commit_hash`: Git commit hash on the injection branch
|
|
499
|
+
|
|
500
|
+
**Pipeline continuation:**
|
|
501
|
+
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.
|
|
502
|
+
</step>
|
|
503
|
+
|
|
504
|
+
</process>
|
|
505
|
+
|
|
506
|
+
<output>
|
|
507
|
+
The testid-injector agent produces these artifacts:
|
|
508
|
+
|
|
509
|
+
**Always produced:**
|
|
510
|
+
- **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.
|
|
511
|
+
|
|
512
|
+
**Produced after injection approval:**
|
|
513
|
+
- **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).
|
|
514
|
+
- **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.
|
|
515
|
+
|
|
516
|
+
**Return to orchestrator:**
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
INJECTOR_COMPLETE:
|
|
520
|
+
report_path: "{TESTID_AUDIT_REPORT.md path}"
|
|
521
|
+
changelog_path: "{INJECTION_CHANGELOG.md path}"
|
|
522
|
+
branch: "qa/testid-inject-{YYYY-MM-DD}"
|
|
523
|
+
coverage_before: {X}%
|
|
524
|
+
coverage_after: {Y}%
|
|
525
|
+
elements_injected: {count}
|
|
526
|
+
elements_deferred: {count}
|
|
527
|
+
elements_existing_preserved: {count}
|
|
528
|
+
files_modified: {count}
|
|
529
|
+
non_compliant_reported: {count}
|
|
530
|
+
non_compliant_renamed: {count}
|
|
531
|
+
validation_passed: {true/false}
|
|
532
|
+
commit_hash: "{hash}"
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**If skipped (has_frontend: false):**
|
|
536
|
+
|
|
537
|
+
```
|
|
538
|
+
INJECTOR_SKIPPED:
|
|
539
|
+
reason: "No frontend components detected (has_frontend: false in SCAN_MANIFEST.md)"
|
|
540
|
+
action: "Pipeline should skip testid-inject stage and proceed directly to plan"
|
|
541
|
+
```
|
|
542
|
+
</output>
|
|
543
|
+
|
|
544
|
+
<quality_gate>
|
|
545
|
+
Before considering this agent's work complete, verify ALL of the following.
|
|
546
|
+
|
|
547
|
+
**From templates/testid-audit-report.md quality gate (all 8 items -- VERBATIM):**
|
|
548
|
+
|
|
549
|
+
- [ ] Every interactive element across all scanned files has an entry in the File Details section
|
|
550
|
+
- [ ] All proposed `data-testid` values follow the `{context}-{description}-{element-type}` convention
|
|
551
|
+
- [ ] No duplicate `data-testid` values exist within the same page/route scope
|
|
552
|
+
- [ ] Coverage Score formula is shown explicitly with the correct calculation
|
|
553
|
+
- [ ] Decision Gate recommendation matches the coverage score thresholds
|
|
554
|
+
- [ ] All existing `data-testid` values are audited in the Naming Convention Compliance section
|
|
555
|
+
- [ ] Priority assignments are consistent: form inputs and submit buttons are P0, navigation and feedback are P1, decorative elements are P2
|
|
556
|
+
- [ ] Line numbers are included for every element in every File Details table
|
|
557
|
+
|
|
558
|
+
**Additional injector-specific checks:**
|
|
559
|
+
|
|
560
|
+
- [ ] Injection happens on a separate branch (`qa/testid-inject-{YYYY-MM-DD}`)
|
|
561
|
+
- [ ] Existing `data-testid` values are preserved as-is (not modified, not renamed without explicit user approval)
|
|
562
|
+
- [ ] Only approved items are injected (audit-first workflow respected: audit produced -> user reviewed -> only approved elements injected)
|
|
563
|
+
- [ ] 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)
|
|
564
|
+
- [ ] No source code changes beyond `data-testid` additions (non-interference check passed on all files)
|
|
565
|
+
- [ ] 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)
|
|
566
|
+
|
|
567
|
+
If any check fails, fix the issue before considering the agent's work complete. Do not proceed with a failing quality gate.
|
|
568
|
+
</quality_gate>
|
|
569
|
+
|
|
570
|
+
<success_criteria>
|
|
571
|
+
The testid-injector agent has completed successfully when:
|
|
572
|
+
|
|
573
|
+
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
|
|
574
|
+
2. Injection was performed on a separate branch named `qa/testid-inject-{YYYY-MM-DD}` -- the main working copy was not modified
|
|
575
|
+
3. All existing `data-testid` values were preserved as-is (no modifications to existing values without explicit user approval)
|
|
576
|
+
4. Only approved elements were injected (P0 only in auto-advance mode, or user-approved set after checkpoint review)
|
|
577
|
+
5. All modified files pass syntax validation -- no syntax errors introduced by injection
|
|
578
|
+
6. No duplicate `data-testid` values exist within any page/route scope
|
|
579
|
+
7. INJECTION_CHANGELOG.md documents every injection action with file, line, element, value, and action status
|
|
580
|
+
8. All changes are committed on the injection branch via `node bin/qaa-tools.cjs commit`
|
|
581
|
+
9. Structured return values provided to orchestrator: report_path, changelog_path, branch name, coverage scores (before/after), element counts, validation status, commit hash
|
|
582
|
+
10. All quality gate checks pass (8 template items + 6 injector-specific items)
|
|
583
|
+
</success_criteria>
|