# Specialist Testid Inserter

> Inserts stable test ids into production components for each selector gap named by a test plan, following the per-framework insertion policy and never renaming existing ids. Use when a test plan or page object lists selector gaps that block E2E generation.

- Skill: `hoangnguyen0403/specialist-testid-inserter` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add hoangnguyen0403/specialist-testid-inserter`
- Raw SKILL.md: https://api.skillmd.com/api/skills/hoangnguyen0403/specialist-testid-inserter/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: HoangNguyen0403 (https://skillmd.com/u/hoangnguyen0403)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/hoangnguyen0403/specialist-testid-inserter

---

# Specialist: Test-ID Inserter

## **Priority: P1 (HIGH)**

## Role

Close every `SELECTOR_GAPS` entry for one slug by adding the missing id to the leaf element in the production component, per `quality-engineering-selector-stability`.

## Budget

- One slug per invocation; at most 12 tool calls.
- Read: the test plan's `Selector Gaps`, the page object's gap list, and one component file per gap.
- Write: only the component file that owns each gap; one attribute per gap; no other edits.
- Interactive mode: return `APPROVAL: required` with every file before writing; write only after approval.
- Emit `APPROVAL: granted` once the operator approves the file list, `APPROVAL: not_needed` when no production file changes.
- Autonomous mode: write only when the packet carries `approved_production_edits: true`; otherwise return `APPROVAL: required` with the file list and no edits.
- No production logic changes, no styling, no Git, no sub-agents.
- Return `BLOCKED` when a gap names an element that cannot be located in any component, or when the framework has no insertion snippet.

## Steps

1. Parse gaps into `<screen>-<element>-<role>` ids (e.g. `checkout-submit-button`); reject any that break the naming rule.
2. Locate the leaf interactive or assertable element for each gap; never a layout wrapper.
3. Check for an existing id on that element; if present under another name, report `SKIPPED (existing id: <name>)` and never rename.
4. Apply the framework snippet from `insertion-policy.md` (`data-testid`, `testID`, `Semantics(identifier:)`, `.accessibilityIdentifier`, `Modifier.testTag`).
5. Run the repo's typecheck or lint on changed files; report unresolved gaps as `SKIPPED`.

## Output

```text
INSERTED: [id -> file:line, ...]
SKIPPED: [id (reason), ...]
FILES: [path, ...]
APPROVAL: required | granted | not_needed
CHECK: CLEAN | FAILED
BLOCKED: [reason, if any]
```

## Anti-Patterns

- Renaming an existing id to match the convention: ids are a public contract; report and skip.
- Adding ids to wrappers "so the whole block is reachable".
- Using `accessibilityLabel` or `contentDescription` as the test id.
- Tagging by visible text or a CSS path as a fallback when no leaf element can be located: that is `BLOCKED`, not an insertion.
- Writing to production files in autonomous mode without `approved_production_edits: true`.

