@ia-qa/self-healing 0.10.3 → 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/README.md +60 -0
- package/TUTORIAL.md +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -151,6 +151,66 @@ Only if all four fail does it error, listing the three fixes. `map_app` exposes
|
|
|
151
151
|
```
|
|
152
152
|
If the selector fails, the helper re-scans the live page, matches the element by role + accessible name (exact, then fuzzy Dice ≥ 0.6 — or your own `llmResolver`), retries on the healed selector, and logs a warning telling you to update the test and re-map.
|
|
153
153
|
|
|
154
|
+
## Page Object Models — one file to keep in sync
|
|
155
|
+
|
|
156
|
+
A POM already does what this tool wants: it lifts every selector out of the tests and into **one file**. That is also the one file drift keeps breaking. `map` → `diff` → `fix` treats it like any other test file — the selector is a quoted string literal, so `fix` rewrites it in place.
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
// login.page.ts — the only place a selector is written
|
|
160
|
+
export class LoginPage {
|
|
161
|
+
readonly emailSelector = '#email';
|
|
162
|
+
readonly passwordSelector = '#password';
|
|
163
|
+
readonly submitSelector = 'button#login';
|
|
164
|
+
// used everywhere as page.fill(this.emailSelector, …)
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
A developer reworks the login form: `button#login` becomes `button.btn-primary`. The whole suite goes red through this one file. Heal it:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npx ia-qa-heal map # capture the new contract
|
|
172
|
+
npx ia-qa-heal diff # 🔧 healable button "Log in" button#login → button.btn-primary
|
|
173
|
+
npx ia-qa-heal ingest # inventory the POM's selector literals (optional — lets fix find the file itself)
|
|
174
|
+
npx ia-qa-heal fix .ia-qa/baseline/login.json .ia-qa/mapping/login.json login.page.ts
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```diff
|
|
178
|
+
export class LoginPage {
|
|
179
|
+
readonly emailSelector = '#email';
|
|
180
|
+
readonly passwordSelector = '#password';
|
|
181
|
+
- readonly submitSelector = 'button#login';
|
|
182
|
+
+ readonly submitSelector = 'button.btn-primary';
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
One line changes and every test that goes through `LoginPage` is fixed at once — the POM is exactly the leverage `fix` is built for. Review with `git diff`, run your suite, commit. Nothing was committed for you.
|
|
187
|
+
|
|
188
|
+
**One naming detail.** `ingest` recognises a POM property as a selector when its name contains `selector`/`Selector` (`submitSelector`, above) or when the value is a framework call it already knows (`this.page.locator('#login')`). That is what lists the file in `.ia-qa/usage.json`, so `diff` can annotate it and `fix` can find it with no path given. A plainly-named property (`loginButton = '#login'`) is invisible to that inventory — but `fix` still rewrites its literal when you pass the POM file on the command line, because the rewrite is keyed on the string, not the property name.
|
|
189
|
+
|
|
190
|
+
## In CI
|
|
191
|
+
|
|
192
|
+
`diff` returns an exit code, so a pipeline can gate on drift — `0` = PASS/FIX, `1` = BLOCK, `2` = bad input:
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
# .github/workflows/selector-drift.yml
|
|
196
|
+
name: Selector drift
|
|
197
|
+
on: [pull_request]
|
|
198
|
+
jobs:
|
|
199
|
+
drift:
|
|
200
|
+
runs-on: ubuntu-latest
|
|
201
|
+
steps:
|
|
202
|
+
- uses: actions/checkout@v4
|
|
203
|
+
- uses: actions/setup-node@v4
|
|
204
|
+
with: { node-version: '20' }
|
|
205
|
+
- run: npm ci
|
|
206
|
+
- run: npx playwright install --with-deps chromium
|
|
207
|
+
- run: npm start & # your app on its usual port
|
|
208
|
+
- run: npx ia-qa-heal map # re-capture into .ia-qa/mapping/
|
|
209
|
+
- run: npx ia-qa-heal diff # 0 = PASS/FIX · 1 = BLOCK · 2 = bad input
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`diff` with no arguments compares the committed `.ia-qa/baseline/` against what `map` just re-captured — which is why the baseline has to be in git. Add `--report drift-report.html` to attach a branded HTML report to the build, and `--strict` to fail on FIX too. The full workflow (report upload, artifact, `--strict`) is in **[TUTORIAL.md → Putting it in CI](TUTORIAL.md#8-putting-it-in-ci)**.
|
|
213
|
+
|
|
154
214
|
## Map artifacts
|
|
155
215
|
|
|
156
216
|
Beyond one contract per page, every `map` run rebuilds two views of the whole app. Both are derived entirely from the mappings on disk (no extra page visit) and rebuilt on every run, including `map <page>`, so they never drift out of date.
|
package/TUTORIAL.md
CHANGED
|
@@ -463,6 +463,9 @@ No. This tool brings its own browser. One install, not two.
|
|
|
463
463
|
**Cypress or Playwright or Selenium?**
|
|
464
464
|
All of them, and any language. The `fix` command replaces the selector wherever it appears as a quoted string — that's the same in JavaScript, Python, Java, C#, Ruby.
|
|
465
465
|
|
|
466
|
+
**I use a Page Object Model — does that work?**
|
|
467
|
+
That's the best case. A POM keeps every selector in one file, so a broken selector is one property to fix, not a hunt across the suite. `fix` rewrites the selector string right there in the POM, and every test that uses it is fixed at once. (Tip: if your selector properties are named `…Selector`, `ia-qa-heal ingest` inventories them too, so `fix` finds the file on its own — otherwise just pass the POM file to `fix`.)
|
|
468
|
+
|
|
466
469
|
**Why is my "renamed" element not fixed automatically?**
|
|
467
470
|
Because the selector still works — your test isn't broken. But the button now says something different, which might be a real change worth failing on. Only a human knows.
|
|
468
471
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ia-qa/self-healing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Local-first self-healing for UI tests: a local MCP server + CLI that map your app's pages to a role/name/selector contract, diff selector drift (PASS/FIX/BLOCK), and apply deterministic fixes to Cypress/Playwright/Selenium tests. Runs on your machine — nothing leaves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"self-healing",
|