@ia-qa/self-healing 1.7.26 → 1.8.2

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.
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.computePageDepth = computePageDepth;
37
+ exports.collectUnattributable = collectUnattributable;
38
+ exports.computeTestDepth = computeTestDepth;
39
+ exports.readTestDepth = readTestDepth;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const config_1 = require("./config");
43
+ const ingest_1 = require("./ingest");
44
+ const resolution_1 = require("./resolution");
45
+ const nameLocators_1 = require("./nameLocators");
46
+ const exercised_1 = require("./exercised");
47
+ /** Does this name-anchored site designate an element of this role? */
48
+ function siteMatchesRole(site, role) {
49
+ const roles = (0, nameLocators_1.candidateRoles)(site);
50
+ return roles !== null && roles.includes(role);
51
+ }
52
+ /**
53
+ * The contract selectors a test literal provably reaches, from one page's resolution.
54
+ *
55
+ * `bound` only. An `anchored` binding names an identity selector for an element the contract
56
+ * does **not** hold — it is a repair target, not evidence that a contracted element is
57
+ * covered — and `ambiguous` is a coin flip the suite created. Counting either as coverage
58
+ * would inflate the one number this file exists to state honestly.
59
+ */
60
+ function boundSelectors(resolution) {
61
+ const out = new Set();
62
+ if (!resolution)
63
+ return out;
64
+ for (const binding of Object.values(resolution.bindings)) {
65
+ if (binding.status === 'bound' && binding.selector)
66
+ out.add(binding.selector);
67
+ }
68
+ return out;
69
+ }
70
+ function computePageDepth(mapping, usage, resolution) {
71
+ const bound = boundSelectors(resolution);
72
+ const files = new Set();
73
+ let named = 0;
74
+ for (const el of mapping.elements ?? []) {
75
+ let hit = false;
76
+ // A test writing the contract's own selector, and a test writing a different string
77
+ // that a browser proved reaches this element. The second is the common case in a
78
+ // legacy Page Object suite, and the whole reason `_resolved/` exists.
79
+ const literalSites = usage?.selectors?.[el.selector];
80
+ if (literalSites?.length) {
81
+ hit = true;
82
+ for (const s of literalSites)
83
+ files.add(s.file);
84
+ }
85
+ if (bound.has(el.selector))
86
+ hit = true;
87
+ // Name-anchored locators, credited only when the call's role can be this element's.
88
+ // `getByRole('button', {name:'Save'})` does not cover a link also called Save.
89
+ const nameSites = usage?.names?.[(0, nameLocators_1.normalizeName)(el.name)];
90
+ if (nameSites?.length) {
91
+ for (const site of nameSites) {
92
+ if (!(0, nameLocators_1.judgeable)(site) || !siteMatchesRole(site, el.role))
93
+ continue;
94
+ hit = true;
95
+ files.add(site.file);
96
+ }
97
+ }
98
+ if (hit)
99
+ named += 1;
100
+ }
101
+ return {
102
+ page: mapping.page,
103
+ elements: (mapping.elements ?? []).length,
104
+ named,
105
+ files: Array.from(files).sort(),
106
+ ...(mapping.exploredDepth != null ? { exploredDepth: mapping.exploredDepth } : {}),
107
+ };
108
+ }
109
+ /**
110
+ * Which literals in the inventory cannot be attributed to any element, deduplicated by
111
+ * source position — one line of a test file is one finding, however many pages it fails to
112
+ * match.
113
+ */
114
+ function collectUnattributable(usage) {
115
+ if (!usage?.names)
116
+ return [];
117
+ const seen = new Set();
118
+ const out = [];
119
+ for (const sites of Object.values(usage.names)) {
120
+ for (const site of sites) {
121
+ if ((0, nameLocators_1.judgeable)(site))
122
+ continue;
123
+ const key = `${site.file}:${site.line}`;
124
+ if (seen.has(key))
125
+ continue;
126
+ seen.add(key);
127
+ out.push({ text: site.text, file: site.file, line: site.line, shape: site.shape });
128
+ }
129
+ }
130
+ return out.sort((a, b) => (a.file === b.file ? a.line - b.line : a.file.localeCompare(b.file)));
131
+ }
132
+ function computeTestDepth(mappings, usage, resolutions) {
133
+ const measurable = !!usage && (Object.keys(usage.selectors ?? {}).length > 0 || Object.keys(usage.names ?? {}).length > 0);
134
+ const pages = mappings
135
+ .map((m) => computePageDepth(m, usage, resolutions.get(m.page) ?? null))
136
+ .sort((a, b) => a.page.localeCompare(b.page));
137
+ return {
138
+ measurable,
139
+ pages,
140
+ totals: {
141
+ pages: pages.length,
142
+ elements: pages.reduce((s, p) => s + p.elements, 0),
143
+ named: pages.reduce((s, p) => s + p.named, 0),
144
+ },
145
+ unattributable: collectUnattributable(usage),
146
+ shallowPages: pages.filter((p) => p.exploredDepth == null).length,
147
+ };
148
+ }
149
+ /**
150
+ * The same computation, reading `.ia-qa/` from disk.
151
+ *
152
+ * Kept apart from `computeTestDepth` so the rules above stay testable without a filesystem,
153
+ * and exported so `@ia-qa/qa-discovery` computes depth with **this** implementation rather
154
+ * than a second one — the coverage map and the healing summary must never be able to
155
+ * disagree about the same two files.
156
+ */
157
+ function readTestDepth(dir = (0, config_1.mappingDir)(), resolved = (0, config_1.resolvedDir)()) {
158
+ const mappings = [];
159
+ for (const page of (0, exercised_1.contractPageNames)(dir)) {
160
+ try {
161
+ mappings.push(JSON.parse(fs.readFileSync(path.join(dir, `${page}.json`), 'utf8')));
162
+ }
163
+ catch {
164
+ // An unreadable contract is one page missing from the denominator, never a crash:
165
+ // the same restraint `map` applies per page. It is reported by nothing here because
166
+ // every other verb that reads the same directory already reports it.
167
+ }
168
+ }
169
+ const resolutions = new Map();
170
+ for (const r of (0, resolution_1.loadAllResolutions)(resolved))
171
+ resolutions.set(r.page, r);
172
+ return computeTestDepth(mappings, (0, ingest_1.loadUsage)(), resolutions);
173
+ }
174
+ //# sourceMappingURL=testDepth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testDepth.js","sourceRoot":"","sources":["../src/testDepth.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ia-qa/self-healing",
3
- "version": "1.7.26",
3
+ "version": "1.8.2",
4
4
  "description": "Your Playwright, Cypress or Selenium tests break when a selector moves — this finds the element again and rewrites the test. Deterministic: no LLM decides whether your build passes. Runs entirely on your machine, with a local MCP server for agents.",
5
5
  "keywords": [
6
6
  "self-healing",