@ia-qa/self-healing 1.7.14 → 1.7.15
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 +12 -0
- package/SPEC-selector-resolution.md +18 -0
- package/dist/captureMerge.js +45 -0
- package/dist/captureMerge.js.map +1 -1
- package/dist/cypress/capture.js +7 -5
- package/dist/cypress/capture.js.map +1 -1
- package/dist/discovery/safety.js +1 -2
- package/dist/discovery/safety.js.map +1 -1
- package/dist/pageName.d.ts +36 -1
- package/dist/pageName.js +91 -11
- package/dist/pageName.js.map +1 -1
- package/dist/playwright/capture.js +6 -4
- package/dist/playwright/capture.js.map +1 -1
- package/dist/selenium/capture.js +7 -4
- package/dist/selenium/capture.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -368,6 +368,18 @@ and they never fail your tests. Each worker writes its own shard to
|
|
|
368
368
|
page contracts `map` produces — byte-compatible, named from `config.pages` so they pair with
|
|
369
369
|
your baseline.
|
|
370
370
|
|
|
371
|
+
**One suite, several applications.** A page name is a filename, so two URLs sharing one name
|
|
372
|
+
claim to be the same page — and five products each with a `/login` are not. A URL on a host
|
|
373
|
+
other than your `baseUrl` is therefore named `<host>--<path>`
|
|
374
|
+
(`partner.example.com--login`), never `login`. Single-host suites are unaffected: the prefix
|
|
375
|
+
only appears where two applications would otherwise have overwritten each other's contract, and
|
|
376
|
+
`www.`/apex and `http`/`https` count as the same host. To choose the name yourself, declare the
|
|
377
|
+
page with its **absolute** URL:
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{ "name": "partner-login", "url": "https://partner.example.com/login" }
|
|
381
|
+
```
|
|
382
|
+
|
|
371
383
|
**Any other framework or language.** The shard format *is* the interface; the helpers above are
|
|
372
384
|
sugar over it. Run the extractor in the page (`extract.js` in this package, also a copy-paste
|
|
373
385
|
DevTools snippet on ia-qa.com) and drop a JSON file into `.ia-qa/mapping/.capture/`:
|
|
@@ -297,6 +297,24 @@ Requirements when it is built:
|
|
|
297
297
|
silently compared against one captured by `map`. Same reasoning as `run`'s
|
|
298
298
|
source-mismatch warning.
|
|
299
299
|
|
|
300
|
+
### 7.1 `map --deep` reaches states, and resolution deliberately does not follow it
|
|
301
|
+
|
|
302
|
+
`--deep` (see CLAUDE.md) opens menus, tabs and dialogs and contracts what they reveal. It would
|
|
303
|
+
be easy to assume selector resolution comes along — it does not, and the restraint is deliberate.
|
|
304
|
+
`resolvePageSelectors` runs against the **loaded** state, before exploration starts, because
|
|
305
|
+
exploration ends with the page in whatever state its walk finished in. Resolving after it would
|
|
306
|
+
probe the suite's selectors against an open modal and report a *working* binding as broken —
|
|
307
|
+
the one error this package treats as worse than the drift it heals.
|
|
308
|
+
|
|
309
|
+
So a deep contract holds elements with **no binding row**. That is `unresolved`-shaped, and §2.2
|
|
310
|
+
already governs it: silence is never evidence of absence. What it costs is real and worth stating
|
|
311
|
+
— the highest-value finding here, a selector that now reaches a *different* element, cannot be
|
|
312
|
+
made about anything behind a menu.
|
|
313
|
+
|
|
314
|
+
Closing that gap is phase 2's job, not a patch to `map`: the states `--deep` reaches are the same
|
|
315
|
+
states the shards see for free, and resolution belongs where the page is already standing in one.
|
|
316
|
+
Do not "fix" it by moving `resolvePageSelectors` after `explorePage`.
|
|
317
|
+
|
|
300
318
|
---
|
|
301
319
|
|
|
302
320
|
## 8. What this feature is not
|
package/dist/captureMerge.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.mergeCapturesAnnounced = mergeCapturesAnnounced;
|
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const config_1 = require("./config");
|
|
43
|
+
const pageName_1 = require("./pageName");
|
|
43
44
|
const aom_1 = require("./aom");
|
|
44
45
|
const markdown_1 = require("./markdown");
|
|
45
46
|
const union_1 = require("./browser/union");
|
|
@@ -58,6 +59,39 @@ exports.CAPTURE_DIRNAME = '.capture';
|
|
|
58
59
|
function captureDir(cwd = (0, config_1.baseDir)()) {
|
|
59
60
|
return path.join((0, config_1.mappingDir)(cwd), exports.CAPTURE_DIRNAME);
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* One contract, two applications — say so instead of writing it.
|
|
64
|
+
*
|
|
65
|
+
* A page name is an identity claim, and `resolvePageName` keeps it honest by putting
|
|
66
|
+
* the host in the name whenever the URL is not the app's own. That needs a `baseUrl`,
|
|
67
|
+
* so it needs a config; without one every host's `/login` still resolves to `login`,
|
|
68
|
+
* and this merge would union five products into one contract, then diff it against
|
|
69
|
+
* whichever one it happened to hold last — a permanent phantom drift on a suite that
|
|
70
|
+
* is green, offered to `fix` as a rename.
|
|
71
|
+
*
|
|
72
|
+
* We cannot pick the namespace here (there is no declared app to be foreign *to*, and
|
|
73
|
+
* inventing one from whichever host appeared most would make the names depend on
|
|
74
|
+
* worker scheduling). So we name the collision and the remedy, rather than let silence
|
|
75
|
+
* read as "checked, fine". The remedy differs by cause, and the cause is *checked*, not
|
|
76
|
+
* assumed: with a config in place these names cannot come from this version's capture,
|
|
77
|
+
* so they came from a stale `.capture/` or a hand-written shard.
|
|
78
|
+
*/
|
|
79
|
+
function warnHostCollisions(byPage, configured) {
|
|
80
|
+
for (const [name, { hosts }] of byPage) {
|
|
81
|
+
if (hosts.size < 2)
|
|
82
|
+
continue;
|
|
83
|
+
const remedy = configured
|
|
84
|
+
? ` This version names an off-\`baseUrl\` page \`<host>--<path>\`, so these shards were ` +
|
|
85
|
+
`written by an older version or by hand. Delete \`${config_1.CONFIG_DIR}/mapping/.capture/\`, re-run ` +
|
|
86
|
+
`the suite, and declare any page you want named yourself in "pages" with its absolute URL.`
|
|
87
|
+
: ` There is no ${config_1.CONFIG_DIR}/config.json here, so nothing names the app these pages ` +
|
|
88
|
+
`belong to; with a "baseUrl", every other host is prefixed into the page name instead. ` +
|
|
89
|
+
`Run \`ia-qa-heal init\`, or declare each one in "pages" with its absolute URL.`;
|
|
90
|
+
console.warn(`⚠ Page "${name}" was captured from ${hosts.size} different hosts this run ` +
|
|
91
|
+
`(${Array.from(hosts).join(', ')}) — they are sharing one contract, so its diff is not ` +
|
|
92
|
+
`meaningful.\n${remedy}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
61
95
|
function mergeCaptures(cwd = (0, config_1.baseDir)()) {
|
|
62
96
|
const dir = captureDir(cwd);
|
|
63
97
|
if (!fs.existsSync(dir))
|
|
@@ -84,9 +118,17 @@ function mergeCaptures(cwd = (0, config_1.baseDir)()) {
|
|
|
84
118
|
if (!p?.page || !Array.isArray(p.elements))
|
|
85
119
|
continue;
|
|
86
120
|
const prev = byPage.get(p.page);
|
|
121
|
+
const hosts = prev ? prev.hosts : new Set();
|
|
122
|
+
try {
|
|
123
|
+
hosts.add((0, pageName_1.foldHost)(new URL(p.url)));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
/* an unparseable URL says nothing about which app this was */
|
|
127
|
+
}
|
|
87
128
|
byPage.set(p.page, {
|
|
88
129
|
url: p.url,
|
|
89
130
|
elements: prev ? (0, union_1.unionElements)(prev.elements, p.elements) : p.elements,
|
|
131
|
+
hosts,
|
|
90
132
|
});
|
|
91
133
|
}
|
|
92
134
|
}
|
|
@@ -94,12 +136,15 @@ function mergeCaptures(cwd = (0, config_1.baseDir)()) {
|
|
|
94
136
|
// here at the merge — one place covering the Playwright, Cypress and Selenium
|
|
95
137
|
// hooks at once. No config, no patterns: live capture without one stays as-is.
|
|
96
138
|
let patterns = [];
|
|
139
|
+
let configured = false;
|
|
97
140
|
try {
|
|
98
141
|
patterns = (0, volatile_1.parseVolatilePatterns)((0, config_1.loadConfig)(cwd).volatile);
|
|
142
|
+
configured = true;
|
|
99
143
|
}
|
|
100
144
|
catch {
|
|
101
145
|
/* config optional for a merge */
|
|
102
146
|
}
|
|
147
|
+
warnHostCollisions(byPage, configured);
|
|
103
148
|
const capturedAt = new Date().toISOString();
|
|
104
149
|
const outDir = (0, config_1.mappingDir)(cwd);
|
|
105
150
|
const pages = [];
|
package/dist/captureMerge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captureMerge.js","sourceRoot":"","sources":["../src/captureMerge.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"captureMerge.js","sourceRoot":"","sources":["../src/captureMerge.ts"],"names":[],"mappings":"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"}
|
package/dist/cypress/capture.js
CHANGED
|
@@ -82,8 +82,8 @@ function workerId() {
|
|
|
82
82
|
function flush(root, shardId, pages) {
|
|
83
83
|
try {
|
|
84
84
|
const shardPages = [];
|
|
85
|
-
pages.forEach((c
|
|
86
|
-
shardPages.push({ page:
|
|
85
|
+
pages.forEach((c) => {
|
|
86
|
+
shardPages.push({ page: c.page, url: c.url, elements: c.elements });
|
|
87
87
|
});
|
|
88
88
|
if (shardPages.length === 0)
|
|
89
89
|
return;
|
|
@@ -96,7 +96,7 @@ function flush(root, shardId, pages) {
|
|
|
96
96
|
if (armed()) {
|
|
97
97
|
const root = configRoot();
|
|
98
98
|
const shardId = workerId();
|
|
99
|
-
const pages = new Map(); //
|
|
99
|
+
const pages = new Map(); // captureKey() -> { page, url, elements }
|
|
100
100
|
let config = null;
|
|
101
101
|
// Optional: pairs captured contracts with the names in config.pages and skips
|
|
102
102
|
// steps-views. Absent config is fine — the name falls back to a slug of the URL.
|
|
@@ -122,8 +122,10 @@ if (armed()) {
|
|
|
122
122
|
const res = (0, pageName_1.resolvePageName)(url, config);
|
|
123
123
|
if (res.kind === 'steps')
|
|
124
124
|
return; // shared URL — map's job, not capture's
|
|
125
|
-
const
|
|
126
|
-
pages.
|
|
125
|
+
const key = (0, pageName_1.captureKey)(res.name, url);
|
|
126
|
+
const prev = pages.get(key);
|
|
127
|
+
pages.set(key, {
|
|
128
|
+
page: res.name,
|
|
127
129
|
url: url,
|
|
128
130
|
elements: prev ? (0, union_1.unionElements)(prev.elements, els) : els,
|
|
129
131
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/cypress/capture.js"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,gDAAmD;AACnD,4CAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/cypress/capture.js"],"names":[],"mappings":"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"}
|
package/dist/discovery/safety.js
CHANGED
|
@@ -45,8 +45,7 @@ const DOWNLOAD_EXT_RE = /\.(?:pdf|zip|gz|tar|rar|7z|csv|xlsx?|docx?|pptx?|png|jp
|
|
|
45
45
|
* and port stay significant: `http` vs `https` is a real difference, not a `www.`.
|
|
46
46
|
*/
|
|
47
47
|
function siteKey(u, strictHost = false) {
|
|
48
|
-
|
|
49
|
-
return `${u.protocol}//${host}`;
|
|
48
|
+
return `${u.protocol}//${(0, pageName_1.foldHost)(u, strictHost)}`;
|
|
50
49
|
}
|
|
51
50
|
/**
|
|
52
51
|
* Classify a URL against `baseUrl`, returning *why* it was rejected — so a caller
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/discovery/safety.ts"],"names":[],"mappings":";;;AAqDA,
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/discovery/safety.ts"],"names":[],"mappings":"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"}
|
package/dist/pageName.d.ts
CHANGED
|
@@ -6,8 +6,43 @@ import type { IaQaConfig } from './config';
|
|
|
6
6
|
* same page differently produce contracts that never meet: every page becomes a
|
|
7
7
|
* phantom lost/new pair and the diff is garbage. The healer, `map`, and run-time
|
|
8
8
|
* capture all funnel through here for exactly that reason.
|
|
9
|
+
*
|
|
10
|
+
* A page name is a **filename**, so it is also an identity claim: two URLs that
|
|
11
|
+
* resolve to the same name are asserting they are the same page. A pathname alone
|
|
12
|
+
* cannot carry that claim across hosts — five products with a `/login` are five
|
|
13
|
+
* different pages, and naming them all `login` made whichever the suite happened
|
|
14
|
+
* to visit last overwrite the others. The host is therefore part of the name
|
|
15
|
+
* whenever it is not the app's own (see `hostPrefix`).
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* A URL's host with a leading `www.` folded away — the key that answers "is this
|
|
19
|
+
* the same site?".
|
|
20
|
+
*
|
|
21
|
+
* Comparing raw hosts makes an apex `baseUrl` and a `www.` URL (or the `www.`→apex
|
|
22
|
+
* 301 that is the single most common way the two differ in the wild) look like two
|
|
23
|
+
* different applications. `discovery/safety.ts` builds its crawl-permission key on
|
|
24
|
+
* top of this; page naming uses the host alone, because `http` vs `https` on one
|
|
25
|
+
* host is never two applications — and renaming every contract over a protocol
|
|
26
|
+
* upgrade would be the phantom drift this file exists to prevent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function foldHost(u: URL, strictHost?: boolean): string;
|
|
29
|
+
/**
|
|
30
|
+
* Slug a URL into a page name. `baseUrl` is optional only because the discovery
|
|
31
|
+
* paths already filter to one host before they get here; every capture path passes
|
|
32
|
+
* it, and without it two hosts sharing a pathname collide into one contract.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pageNameFromUrl(url: string, baseUrl?: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* The key a capture buffers a page under while a test run is in flight.
|
|
37
|
+
*
|
|
38
|
+
* The resolved name *and* the host it was seen on. With a config the two are
|
|
39
|
+
* already one-to-one — the name carries the host — so this is a no-op there. Without
|
|
40
|
+
* one, `resolvePageName` has no `baseUrl` to namespace against, and keying by name
|
|
41
|
+
* alone would union two applications' `/login` inside a single worker, where nothing
|
|
42
|
+
* downstream could ever see that it happened. Keeping them apart costs nothing and
|
|
43
|
+
* lets the merge say so out loud (`captureMerge.ts`).
|
|
9
44
|
*/
|
|
10
|
-
export declare function
|
|
45
|
+
export declare function captureKey(name: string, url: string): string;
|
|
11
46
|
export type PageNameResolution =
|
|
12
47
|
/** The URL is a configured page — use the name its contract already has. */
|
|
13
48
|
{
|
package/dist/pageName.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.foldHost = foldHost;
|
|
3
4
|
exports.pageNameFromUrl = pageNameFromUrl;
|
|
5
|
+
exports.captureKey = captureKey;
|
|
4
6
|
exports.resolvePageName = resolvePageName;
|
|
5
7
|
/**
|
|
6
8
|
* URL → logical page name, the one resolver every capture path must share.
|
|
@@ -9,30 +11,108 @@ exports.resolvePageName = resolvePageName;
|
|
|
9
11
|
* same page differently produce contracts that never meet: every page becomes a
|
|
10
12
|
* phantom lost/new pair and the diff is garbage. The healer, `map`, and run-time
|
|
11
13
|
* capture all funnel through here for exactly that reason.
|
|
14
|
+
*
|
|
15
|
+
* A page name is a **filename**, so it is also an identity claim: two URLs that
|
|
16
|
+
* resolve to the same name are asserting they are the same page. A pathname alone
|
|
17
|
+
* cannot carry that claim across hosts — five products with a `/login` are five
|
|
18
|
+
* different pages, and naming them all `login` made whichever the suite happened
|
|
19
|
+
* to visit last overwrite the others. The host is therefore part of the name
|
|
20
|
+
* whenever it is not the app's own (see `hostPrefix`).
|
|
12
21
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
/**
|
|
23
|
+
* A URL's host with a leading `www.` folded away — the key that answers "is this
|
|
24
|
+
* the same site?".
|
|
25
|
+
*
|
|
26
|
+
* Comparing raw hosts makes an apex `baseUrl` and a `www.` URL (or the `www.`→apex
|
|
27
|
+
* 301 that is the single most common way the two differ in the wild) look like two
|
|
28
|
+
* different applications. `discovery/safety.ts` builds its crawl-permission key on
|
|
29
|
+
* top of this; page naming uses the host alone, because `http` vs `https` on one
|
|
30
|
+
* host is never two applications — and renaming every contract over a protocol
|
|
31
|
+
* upgrade would be the phantom drift this file exists to prevent.
|
|
32
|
+
*/
|
|
33
|
+
function foldHost(u, strictHost = false) {
|
|
34
|
+
return strictHost ? u.host : u.host.replace(/^www\./i, '');
|
|
35
|
+
}
|
|
36
|
+
function parseUrl(url) {
|
|
15
37
|
try {
|
|
16
|
-
|
|
38
|
+
return new URL(url);
|
|
17
39
|
}
|
|
18
40
|
catch {
|
|
19
|
-
|
|
41
|
+
return null;
|
|
20
42
|
}
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
}
|
|
44
|
+
/** Trailing slashes and query strings do not make another page. */
|
|
45
|
+
function normalizePath(pathname) {
|
|
46
|
+
return pathname.replace(/\/+$/, '') || '/';
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The `host--` part of a name, or '' when the URL belongs to the app itself.
|
|
50
|
+
*
|
|
51
|
+
* Empty for every single-host suite, which is what keeps existing contracts
|
|
52
|
+
* byte-identical: the prefix only appears where a collision was previously
|
|
53
|
+
* possible. Sanitized to what `mappingPath` allows, so the name a diff pairs on
|
|
54
|
+
* and the filename it lands in stay the same string.
|
|
55
|
+
*/
|
|
56
|
+
function hostPrefix(here, baseUrl) {
|
|
57
|
+
if (!baseUrl)
|
|
58
|
+
return '';
|
|
59
|
+
const base = parseUrl(baseUrl);
|
|
60
|
+
if (!base || foldHost(base) === foldHost(here))
|
|
61
|
+
return '';
|
|
62
|
+
return here.host.replace(/[^a-zA-Z0-9.-]/g, '-') + '--';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Slug a URL into a page name. `baseUrl` is optional only because the discovery
|
|
66
|
+
* paths already filter to one host before they get here; every capture path passes
|
|
67
|
+
* it, and without it two hosts sharing a pathname collide into one contract.
|
|
68
|
+
*/
|
|
69
|
+
function pageNameFromUrl(url, baseUrl) {
|
|
70
|
+
const parsed = parseUrl(url);
|
|
71
|
+
const pathname = parsed ? parsed.pathname : '/';
|
|
72
|
+
const slug = pathname.replace(/^\/+|\/+$/g, '').replace(/\//g, '-') || 'home';
|
|
73
|
+
return parsed ? hostPrefix(parsed, baseUrl) + slug : slug;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The key a capture buffers a page under while a test run is in flight.
|
|
77
|
+
*
|
|
78
|
+
* The resolved name *and* the host it was seen on. With a config the two are
|
|
79
|
+
* already one-to-one — the name carries the host — so this is a no-op there. Without
|
|
80
|
+
* one, `resolvePageName` has no `baseUrl` to namespace against, and keying by name
|
|
81
|
+
* alone would union two applications' `/login` inside a single worker, where nothing
|
|
82
|
+
* downstream could ever see that it happened. Keeping them apart costs nothing and
|
|
83
|
+
* lets the merge say so out loud (`captureMerge.ts`).
|
|
84
|
+
*/
|
|
85
|
+
function captureKey(name, url) {
|
|
86
|
+
const parsed = parseUrl(url);
|
|
87
|
+
return parsed ? `${name}\u0000${foldHost(parsed)}` : name;
|
|
23
88
|
}
|
|
24
89
|
function resolvePageName(url, config) {
|
|
25
90
|
if (!config)
|
|
26
91
|
return { kind: 'unconfigured', name: pageNameFromUrl(url) };
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
92
|
+
const here = parseUrl(url);
|
|
93
|
+
if (!here)
|
|
94
|
+
return { kind: 'unconfigured', name: pageNameFromUrl(url) };
|
|
95
|
+
const currentPath = normalizePath(here.pathname);
|
|
96
|
+
// Host *and* path: a configured `/login` names this app's login page, never the
|
|
97
|
+
// one on the partner portal the suite also drives. A target declared with an
|
|
98
|
+
// absolute URL on another host is how a multi-app suite names those explicitly.
|
|
99
|
+
const sameTarget = (p) => {
|
|
100
|
+
let target;
|
|
101
|
+
try {
|
|
102
|
+
target = new URL(p.url, config.baseUrl);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return foldHost(target) === foldHost(here) && normalizePath(target.pathname) === currentPath;
|
|
108
|
+
};
|
|
109
|
+
const match = config.pages.find((p) => !p.steps?.length && sameTarget(p));
|
|
30
110
|
if (match)
|
|
31
111
|
return { kind: 'configured', name: match.name };
|
|
32
|
-
const behindSteps = config.pages.filter((p) => p.steps?.length &&
|
|
112
|
+
const behindSteps = config.pages.filter((p) => p.steps?.length && sameTarget(p));
|
|
33
113
|
if (behindSteps.length > 0) {
|
|
34
114
|
return { kind: 'steps', candidates: behindSteps.map((p) => p.name) };
|
|
35
115
|
}
|
|
36
|
-
return { kind: 'unconfigured', name: pageNameFromUrl(url) };
|
|
116
|
+
return { kind: 'unconfigured', name: pageNameFromUrl(url, config.baseUrl) };
|
|
37
117
|
}
|
|
38
118
|
//# sourceMappingURL=pageName.js.map
|
package/dist/pageName.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageName.js","sourceRoot":"","sources":["../src/pageName.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"pageName.js","sourceRoot":"","sources":["../src/pageName.ts"],"names":[],"mappings":"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"}
|
|
@@ -91,8 +91,10 @@ async function capturePage(page) {
|
|
|
91
91
|
const elements = await (0, aom_1.extractInteractiveElements)(page);
|
|
92
92
|
if (elements.length === 0)
|
|
93
93
|
return;
|
|
94
|
-
const
|
|
95
|
-
state.pages.
|
|
94
|
+
const key = (0, pageName_1.captureKey)(resolved.name, url);
|
|
95
|
+
const prev = state.pages.get(key);
|
|
96
|
+
state.pages.set(key, {
|
|
97
|
+
page: resolved.name,
|
|
96
98
|
url,
|
|
97
99
|
elements: prev ? (0, captureMerge_1.unionElements)(prev.elements, elements) : elements,
|
|
98
100
|
});
|
|
@@ -108,8 +110,8 @@ function writeShard() {
|
|
|
108
110
|
const dir = (0, captureMerge_1.captureDir)();
|
|
109
111
|
fs.mkdirSync(dir, { recursive: true });
|
|
110
112
|
const worker = process.env.TEST_WORKER_INDEX ?? String(process.pid);
|
|
111
|
-
const pages = Array.from(state.pages, (
|
|
112
|
-
page:
|
|
113
|
+
const pages = Array.from(state.pages.values(), (c) => ({
|
|
114
|
+
page: c.page,
|
|
113
115
|
url: c.url,
|
|
114
116
|
elements: c.elements,
|
|
115
117
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/playwright/capture.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,wCAEC;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/playwright/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/selenium/capture.js
CHANGED
|
@@ -67,6 +67,7 @@ exports.CAPTURE_ENV = 'IAQA_CAPTURE';
|
|
|
67
67
|
function captureEnabled() {
|
|
68
68
|
return process.env[exports.CAPTURE_ENV] === '1';
|
|
69
69
|
}
|
|
70
|
+
/** Keyed by `captureKey()`, not by page name — see there. */
|
|
70
71
|
const pages = new Map();
|
|
71
72
|
let cfg = null;
|
|
72
73
|
let cfgLoaded = false;
|
|
@@ -89,8 +90,8 @@ function writeShard() {
|
|
|
89
90
|
const dir = (0, captureMerge_1.captureDir)();
|
|
90
91
|
fs.mkdirSync(dir, { recursive: true });
|
|
91
92
|
const worker = process.env.TEST_WORKER_INDEX ?? String(process.pid);
|
|
92
|
-
const shardPages = Array.from(pages, (
|
|
93
|
-
page:
|
|
93
|
+
const shardPages = Array.from(pages.values(), (c) => ({
|
|
94
|
+
page: c.page,
|
|
94
95
|
url: c.url,
|
|
95
96
|
elements: c.elements,
|
|
96
97
|
}));
|
|
@@ -125,8 +126,10 @@ async function capture(driver) {
|
|
|
125
126
|
const elements = (await driver.executeScript(extract_1.extractInPage)) || [];
|
|
126
127
|
if (elements.length === 0)
|
|
127
128
|
return;
|
|
128
|
-
const
|
|
129
|
-
pages.
|
|
129
|
+
const key = (0, pageName_1.captureKey)(resolved.name, url);
|
|
130
|
+
const prev = pages.get(key);
|
|
131
|
+
pages.set(key, {
|
|
132
|
+
page: resolved.name,
|
|
130
133
|
url,
|
|
131
134
|
elements: prev ? (0, captureMerge_1.unionElements)(prev.elements, elements) : elements,
|
|
132
135
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/selenium/capture.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,wCAEC;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/selenium/capture.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,wCAEC;AA4DD,0BAsBC;AApHD,uCAAyB;AACzB,2CAA6B;AAC7B,gDAAmD;AAEnD,sCAAmD;AACnD,0CAA0D;AAC1D,kDAA4D;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AAEU,QAAA,WAAW,GAAG,cAAc,CAAC;AAE1C,SAAgB,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAW,CAAC,KAAK,GAAG,CAAC;AAC1C,CAAC;AAYD,6DAA6D;AAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoE,CAAC;AAC1F,IAAI,GAAG,GAAsB,IAAI,CAAC;AAClC,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,SAAS,MAAM;IACb,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,IAAA,mBAAU,GAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,GAAG,IAAI,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAC7B,MAAM,GAAG,GAAG,IAAA,yBAAU,GAAE,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC,CAAC;QACJ,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,MAAM,OAAO,CAAC,EACpC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACrD,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,OAAO,CAAC,MAAwB;IACpD,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QACzC,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,aAAa;YAAE,OAAO;QAC1C,MAAM,QAAQ,GAAG,IAAA,0BAAe,EAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,8EAA8E;QAC9E,qDAAqD;QACrD,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO;QACtC,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAkB,uBAAa,CAAC,CAAC,IAAI,EAAE,CAAC;QACpF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAClC,MAAM,GAAG,GAAG,IAAA,qBAAU,EAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YACb,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG;YACH,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,IAAA,4BAAa,EAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ;SACnE,CAAC,CAAC;QACH,UAAU,EAAE,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;IAC9D,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ia-qa/self-healing",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.15",
|
|
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",
|