@qa-ai-stlc/explorer 0.2.0 → 0.4.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/dist/build-selector-registry.d.ts +51 -0
- package/dist/build-selector-registry.d.ts.map +1 -0
- package/dist/build-selector-registry.js +0 -0
- package/dist/build-selector-registry.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/page-elements.d.ts.map +1 -1
- package/dist/page-elements.js +98 -7
- package/dist/page-elements.js.map +1 -1
- package/dist/stability-scoring.d.ts +19 -0
- package/dist/stability-scoring.d.ts.map +1 -0
- package/dist/stability-scoring.js +82 -0
- package/dist/stability-scoring.js.map +1 -0
- package/dist/synthesize-locators.d.ts +6 -0
- package/dist/synthesize-locators.d.ts.map +1 -0
- package/dist/synthesize-locators.js +74 -0
- package/dist/synthesize-locators.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type BrowserLauncher, type Clock, type ViewportSize } from '@qa-ai-stlc/core';
|
|
2
|
+
import { type PageModelSet, type SelectorElement, type SelectorRegistry } from '@qa-ai-stlc/schemas';
|
|
3
|
+
import { type ExplorerIdentity } from './identity.js';
|
|
4
|
+
import { type LocatorPolicy } from './synthesize-locators.js';
|
|
5
|
+
export interface BuildSelectorRegistryOptions {
|
|
6
|
+
readonly pageModelSet: PageModelSet;
|
|
7
|
+
readonly browserLauncher: BrowserLauncher;
|
|
8
|
+
/** Signs in before re-navigating to score candidates. Omit to score anonymously. */
|
|
9
|
+
readonly identity?: ExplorerIdentity;
|
|
10
|
+
readonly policy?: LocatorPolicy;
|
|
11
|
+
readonly viewports?: readonly ViewportSize[];
|
|
12
|
+
readonly clock?: Clock;
|
|
13
|
+
}
|
|
14
|
+
export interface BuildSelectorRegistryResult {
|
|
15
|
+
readonly registry: SelectorRegistry;
|
|
16
|
+
/** Every non-GET request safe mode intercepted and cancelled; always 0 unless something is broken. */
|
|
17
|
+
readonly blockedRequestCount: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds a `SelectorRegistry` from a `PageModelSet` produced by `analyzePages()` (development
|
|
21
|
+
* plan section 6.3 steps 4-6): synthesizes locator candidates for every interactive element under
|
|
22
|
+
* the configured policy, scores the first (primary) candidate's stability in a fresh live pass
|
|
23
|
+
* over the same URLs, and assigns each element a stable id. Every entry's `source` is `'crawl'` -
|
|
24
|
+
* the only source this pipeline produces (`static`/`manual` come from other tasks).
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildSelectorRegistry(options: BuildSelectorRegistryOptions): Promise<BuildSelectorRegistryResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Merges a freshly built registry onto a previously stored one, keeping history (development plan
|
|
29
|
+
* section 6.3.6): every element the fresh crawl found replaces its previous entry outright
|
|
30
|
+
* (un-deprecating it, if it had been). An element the fresh crawl did not find is kept rather than
|
|
31
|
+
* deleted, with `deprecatedAt` set to `generatedAt` the first time it goes missing; once
|
|
32
|
+
* deprecated, its `deprecatedAt` is never overwritten by a later run that still does not find it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function mergeSelectorRegistry(previous: SelectorRegistry, fresh: SelectorRegistry, generatedAt: string): SelectorRegistry;
|
|
35
|
+
export interface DegradedSelectorElement {
|
|
36
|
+
readonly elementId: string;
|
|
37
|
+
readonly previousScore: number;
|
|
38
|
+
readonly currentScore: number;
|
|
39
|
+
}
|
|
40
|
+
export interface SelectorRegistryDiff {
|
|
41
|
+
readonly added: readonly SelectorElement[];
|
|
42
|
+
readonly removed: readonly SelectorElement[];
|
|
43
|
+
readonly degraded: readonly DegradedSelectorElement[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Compares two crawls' registries by `elementId`: elements only the current crawl found, elements
|
|
47
|
+
* only the previous crawl found, and elements both found where the current stability score is
|
|
48
|
+
* lower than before.
|
|
49
|
+
*/
|
|
50
|
+
export declare function diffSelectorRegistry(previous: SelectorRegistry, current: SelectorRegistry): SelectorRegistryDiff;
|
|
51
|
+
//# sourceMappingURL=build-selector-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-selector-registry.d.ts","sourceRoot":"","sources":["../src/build-selector-registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC9G,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAG3E,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE3F,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,sGAAsG;IACtG,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAoBD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,2BAA2B,CAAC,CAoDtC;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,gBAAgB,EACvB,WAAW,EAAE,MAAM,GAClB,gBAAgB,CAalB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACvD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,oBAAoB,CAoBtB"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-selector-registry.js","sourceRoot":"","sources":["../src/build-selector-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './accessibility-tree.js';
|
|
|
2
2
|
export * from './allowlist.js';
|
|
3
3
|
export * from './analyze-page.js';
|
|
4
4
|
export * from './analyze-pages.js';
|
|
5
|
+
export * from './build-selector-registry.js';
|
|
5
6
|
export * from './crawl.js';
|
|
6
7
|
export * from './extract-links.js';
|
|
7
8
|
export * from './identity.js';
|
|
@@ -9,4 +10,6 @@ export * from './normalize.js';
|
|
|
9
10
|
export * from './page-elements.js';
|
|
10
11
|
export * from './request-log.js';
|
|
11
12
|
export * from './safe-mode.js';
|
|
13
|
+
export * from './stability-scoring.js';
|
|
14
|
+
export * from './synthesize-locators.js';
|
|
12
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './accessibility-tree.js';
|
|
|
4
4
|
export * from './allowlist.js';
|
|
5
5
|
export * from './analyze-page.js';
|
|
6
6
|
export * from './analyze-pages.js';
|
|
7
|
+
export * from './build-selector-registry.js';
|
|
7
8
|
export * from './crawl.js';
|
|
8
9
|
export * from './extract-links.js';
|
|
9
10
|
export * from './identity.js';
|
|
@@ -11,4 +12,6 @@ export * from './normalize.js';
|
|
|
11
12
|
export * from './page-elements.js';
|
|
12
13
|
export * from './request-log.js';
|
|
13
14
|
export * from './safe-mode.js';
|
|
15
|
+
export * from './stability-scoring.js';
|
|
16
|
+
export * from './synthesize-locators.js';
|
|
14
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAEtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-elements.d.ts","sourceRoot":"","sources":["../src/page-elements.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EACV,MAAM,EACN,IAAI,EAEJ,kBAAkB,EAElB,KAAK,EACN,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"page-elements.d.ts","sourceRoot":"","sources":["../src/page-elements.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EACV,MAAM,EACN,IAAI,EAEJ,kBAAkB,EAElB,KAAK,EACN,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AA2C9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAkPD,qGAAqG;AACrG,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAuCxG"}
|
package/dist/page-elements.js
CHANGED
|
@@ -17,7 +17,7 @@ function isInteractiveElementKind(value) {
|
|
|
17
17
|
* globals unavailable to the rest of this package.
|
|
18
18
|
*/
|
|
19
19
|
async function readRawPageElements(page) {
|
|
20
|
-
/* v8 ignore next
|
|
20
|
+
/* v8 ignore next 90 -- runs in the browser's own V8 instance, invisible to Node coverage */
|
|
21
21
|
const result = await page.evaluate(() => {
|
|
22
22
|
function accessibleName(element) {
|
|
23
23
|
const ariaLabel = element.getAttribute('aria-label');
|
|
@@ -27,6 +27,63 @@ async function readRawPageElements(page) {
|
|
|
27
27
|
const text = element.textContent.trim();
|
|
28
28
|
return text.length > 0 ? text : undefined;
|
|
29
29
|
}
|
|
30
|
+
// A small, explicit table rather than full ARIA role computation: locator synthesis only
|
|
31
|
+
// needs a role plausible enough for `getByRole`, and the five kinds below are the only ones
|
|
32
|
+
// this extractor recognizes in the first place.
|
|
33
|
+
function computeRole(element, kind) {
|
|
34
|
+
const explicit = element.getAttribute('role');
|
|
35
|
+
if (explicit !== null && explicit.trim().length > 0) {
|
|
36
|
+
return explicit;
|
|
37
|
+
}
|
|
38
|
+
if (kind === 'textarea') {
|
|
39
|
+
return 'textbox';
|
|
40
|
+
}
|
|
41
|
+
if (kind === 'select') {
|
|
42
|
+
return 'combobox';
|
|
43
|
+
}
|
|
44
|
+
if (kind === 'input') {
|
|
45
|
+
const type = (element.getAttribute('type') ?? 'text').toLowerCase();
|
|
46
|
+
if (type === 'checkbox' || type === 'radio') {
|
|
47
|
+
return type;
|
|
48
|
+
}
|
|
49
|
+
if (type === 'button' || type === 'submit' || type === 'reset') {
|
|
50
|
+
return 'button';
|
|
51
|
+
}
|
|
52
|
+
return 'textbox';
|
|
53
|
+
}
|
|
54
|
+
return kind === 'button' || kind === 'link' ? kind : undefined;
|
|
55
|
+
}
|
|
56
|
+
// `for`/`id` association first, then an ancestor `<label>` that wraps the field.
|
|
57
|
+
function labelText(element) {
|
|
58
|
+
const id = element.getAttribute('id');
|
|
59
|
+
if (id !== null && id.length > 0) {
|
|
60
|
+
const associated = document.querySelector(`label[for="${CSS.escape(id)}"]`);
|
|
61
|
+
const text = associated?.textContent.trim();
|
|
62
|
+
if (text !== undefined && text.length > 0) {
|
|
63
|
+
return text;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const wrapping = element.closest('label')?.textContent.trim();
|
|
67
|
+
return wrapping !== undefined && wrapping.length > 0 ? wrapping : undefined;
|
|
68
|
+
}
|
|
69
|
+
// Position among same-tag siblings, so a CSS fallback candidate can be built without a live
|
|
70
|
+
// page: `tagName:nth-of-type(nthOfType)` scoped to the element's own parent.
|
|
71
|
+
function nthOfType(element) {
|
|
72
|
+
const parent = element.parentElement;
|
|
73
|
+
if (parent === null) {
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
let index = 0;
|
|
77
|
+
for (const sibling of parent.children) {
|
|
78
|
+
if (sibling.tagName === element.tagName) {
|
|
79
|
+
index += 1;
|
|
80
|
+
if (sibling === element) {
|
|
81
|
+
return index;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
30
87
|
const kindByTagName = {
|
|
31
88
|
a: 'link',
|
|
32
89
|
button: 'button',
|
|
@@ -34,11 +91,21 @@ async function readRawPageElements(page) {
|
|
|
34
91
|
select: 'select',
|
|
35
92
|
textarea: 'textarea',
|
|
36
93
|
};
|
|
37
|
-
const interactiveElements = Array.from(document.querySelectorAll('button, a[href], input, select, textarea')).map((element) =>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
94
|
+
const interactiveElements = Array.from(document.querySelectorAll('button, a[href], input, select, textarea')).map((element) => {
|
|
95
|
+
const tagName = element.tagName.toLowerCase();
|
|
96
|
+
const kind = kindByTagName[tagName] ?? tagName;
|
|
97
|
+
return {
|
|
98
|
+
kind,
|
|
99
|
+
accessibleName: accessibleName(element),
|
|
100
|
+
testId: element.getAttribute('data-testid') ?? undefined,
|
|
101
|
+
role: computeRole(element, kind),
|
|
102
|
+
label: labelText(element),
|
|
103
|
+
placeholder: element.getAttribute('placeholder') ?? undefined,
|
|
104
|
+
htmlId: element.getAttribute('id') ?? undefined,
|
|
105
|
+
tagName,
|
|
106
|
+
nthOfType: nthOfType(element),
|
|
107
|
+
};
|
|
108
|
+
});
|
|
42
109
|
const forms = Array.from(document.querySelectorAll('form')).map((form) => ({
|
|
43
110
|
action: form.getAttribute('action') ?? undefined,
|
|
44
111
|
method: (form.getAttribute('method') ?? 'get').toLowerCase(),
|
|
@@ -74,7 +141,7 @@ function normalizeInteractiveElement(raw, limits, onTruncated) {
|
|
|
74
141
|
if (!isInteractiveElementKind(raw.kind)) {
|
|
75
142
|
return undefined;
|
|
76
143
|
}
|
|
77
|
-
const element = { kind: raw.kind };
|
|
144
|
+
const element = { kind: raw.kind, tagName: raw.tagName, nthOfType: raw.nthOfType };
|
|
78
145
|
if (raw.accessibleName !== undefined) {
|
|
79
146
|
const { text, truncated } = truncateText(raw.accessibleName, limits);
|
|
80
147
|
element.accessibleName = text;
|
|
@@ -85,6 +152,30 @@ function normalizeInteractiveElement(raw, limits, onTruncated) {
|
|
|
85
152
|
if (raw.testId !== undefined) {
|
|
86
153
|
element.testId = raw.testId;
|
|
87
154
|
}
|
|
155
|
+
if (raw.role !== undefined) {
|
|
156
|
+
element.role = raw.role;
|
|
157
|
+
}
|
|
158
|
+
if (raw.label !== undefined) {
|
|
159
|
+
const { text, truncated } = truncateText(raw.label, limits);
|
|
160
|
+
element.label = text;
|
|
161
|
+
if (truncated) {
|
|
162
|
+
onTruncated();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (raw.placeholder !== undefined) {
|
|
166
|
+
const { text, truncated } = truncateText(raw.placeholder, limits);
|
|
167
|
+
element.placeholder = text;
|
|
168
|
+
if (truncated) {
|
|
169
|
+
onTruncated();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (raw.htmlId !== undefined) {
|
|
173
|
+
const { text, truncated } = truncateText(raw.htmlId, limits);
|
|
174
|
+
element.htmlId = text;
|
|
175
|
+
if (truncated) {
|
|
176
|
+
onTruncated();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
88
179
|
return element;
|
|
89
180
|
}
|
|
90
181
|
function normalizeForm(raw) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-elements.js","sourceRoot":"","sources":["../src/page-elements.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,sCAAsC;AAWtC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAwB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"page-elements.js","sourceRoot":"","sources":["../src/page-elements.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AuthPage, PageLocator, ViewportSize } from '@qa-ai-stlc/core';
|
|
2
|
+
import type { LocatorCandidate } from '@qa-ai-stlc/schemas';
|
|
3
|
+
export interface StabilityScoringOptions {
|
|
4
|
+
/** Viewport sizes checked after uniqueness and reload survival; defaults to desktop/tablet/mobile. */
|
|
5
|
+
readonly viewports?: readonly ViewportSize[];
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_VIEWPORTS: readonly ViewportSize[];
|
|
8
|
+
/** Resolves one of P1-08's `LocatorCandidate` values to a live `PageLocator`, by strategy. */
|
|
9
|
+
export declare function resolveCandidateLocator(page: AuthPage, candidate: LocatorCandidate): PageLocator;
|
|
10
|
+
/**
|
|
11
|
+
* Verifies one locator candidate against the current live page: uniqueness now, then survival
|
|
12
|
+
* across a reload and across each configured viewport size (development plan section 6.3.5).
|
|
13
|
+
* Uniqueness is a hard gate — a candidate that does not resolve to exactly one element right now
|
|
14
|
+
* cannot be called stable, so reload/viewport are never checked against a candidate that has
|
|
15
|
+
* already failed. The page's original viewport size is restored before returning, so scoring one
|
|
16
|
+
* element's candidate does not affect the next.
|
|
17
|
+
*/
|
|
18
|
+
export declare function scoreLocatorStability(page: AuthPage, candidate: LocatorCandidate, options?: StabilityScoringOptions): Promise<number>;
|
|
19
|
+
//# sourceMappingURL=stability-scoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stability-scoring.d.ts","sourceRoot":"","sources":["../src/stability-scoring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,uBAAuB;IACtC,sGAAsG;IACtG,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;CAC9C;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,YAAY,EAIpD,CAAC;AAkCF,8FAA8F;AAC9F,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,GAAG,WAAW,CAmBhG;AAOD;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,gBAAgB,EAC3B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,MAAM,CAAC,CA0BjB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright The QA-AI-STLC Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { QaError } from '@qa-ai-stlc/core';
|
|
4
|
+
export const DEFAULT_VIEWPORTS = [
|
|
5
|
+
{ width: 1280, height: 720 },
|
|
6
|
+
{ width: 768, height: 1024 },
|
|
7
|
+
{ width: 375, height: 667 },
|
|
8
|
+
];
|
|
9
|
+
function parseRoleCandidateValue(value) {
|
|
10
|
+
let parsed;
|
|
11
|
+
try {
|
|
12
|
+
parsed = JSON.parse(value);
|
|
13
|
+
}
|
|
14
|
+
catch (cause) {
|
|
15
|
+
throw new QaError('locator-candidate-invalid', `Role locator candidate value is not valid JSON: "${value}".`, { cause });
|
|
16
|
+
}
|
|
17
|
+
if (typeof parsed !== 'object' ||
|
|
18
|
+
parsed === null ||
|
|
19
|
+
typeof parsed.role !== 'string') {
|
|
20
|
+
throw new QaError('locator-candidate-invalid', `Role locator candidate value has no "role" string: "${value}".`);
|
|
21
|
+
}
|
|
22
|
+
const record = parsed;
|
|
23
|
+
return typeof record.name === 'string'
|
|
24
|
+
? { role: record.role, name: record.name }
|
|
25
|
+
: { role: record.role };
|
|
26
|
+
}
|
|
27
|
+
/** Resolves one of P1-08's `LocatorCandidate` values to a live `PageLocator`, by strategy. */
|
|
28
|
+
export function resolveCandidateLocator(page, candidate) {
|
|
29
|
+
switch (candidate.strategy) {
|
|
30
|
+
case 'role': {
|
|
31
|
+
const { role, name } = parseRoleCandidateValue(candidate.value);
|
|
32
|
+
return page.getByRole(role, name === undefined ? undefined : { name });
|
|
33
|
+
}
|
|
34
|
+
case 'testId':
|
|
35
|
+
return page.getByTestId(candidate.value);
|
|
36
|
+
case 'label':
|
|
37
|
+
return page.getByLabel(candidate.value);
|
|
38
|
+
case 'placeholder':
|
|
39
|
+
return page.getByPlaceholder(candidate.value);
|
|
40
|
+
case 'text':
|
|
41
|
+
return page.getByText(candidate.value);
|
|
42
|
+
case 'css':
|
|
43
|
+
return page.locator(candidate.value);
|
|
44
|
+
default:
|
|
45
|
+
throw new QaError('locator-strategy-unknown', `Unknown locator strategy "${candidate.strategy}".`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function isUniqueMatch(page, candidate) {
|
|
49
|
+
const count = await resolveCandidateLocator(page, candidate).count();
|
|
50
|
+
return count === 1;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Verifies one locator candidate against the current live page: uniqueness now, then survival
|
|
54
|
+
* across a reload and across each configured viewport size (development plan section 6.3.5).
|
|
55
|
+
* Uniqueness is a hard gate — a candidate that does not resolve to exactly one element right now
|
|
56
|
+
* cannot be called stable, so reload/viewport are never checked against a candidate that has
|
|
57
|
+
* already failed. The page's original viewport size is restored before returning, so scoring one
|
|
58
|
+
* element's candidate does not affect the next.
|
|
59
|
+
*/
|
|
60
|
+
export async function scoreLocatorStability(page, candidate, options = {}) {
|
|
61
|
+
if (!(await isUniqueMatch(page, candidate))) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
const viewports = options.viewports ?? DEFAULT_VIEWPORTS;
|
|
65
|
+
const originalViewport = page.viewportSize();
|
|
66
|
+
let survivedChecks = 0;
|
|
67
|
+
await page.reload();
|
|
68
|
+
if (await isUniqueMatch(page, candidate)) {
|
|
69
|
+
survivedChecks += 1;
|
|
70
|
+
}
|
|
71
|
+
for (const viewport of viewports) {
|
|
72
|
+
await page.setViewportSize(viewport);
|
|
73
|
+
if (await isUniqueMatch(page, candidate)) {
|
|
74
|
+
survivedChecks += 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (originalViewport !== null) {
|
|
78
|
+
await page.setViewportSize(originalViewport);
|
|
79
|
+
}
|
|
80
|
+
return survivedChecks / (1 + viewports.length);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=stability-scoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stability-scoring.js","sourceRoot":"","sources":["../src/stability-scoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InteractiveElement, LocatorCandidate } from '@qa-ai-stlc/schemas';
|
|
2
|
+
export declare const LOCATOR_POLICIES: readonly ["playwright-default", "testid-first", "strict-no-css"];
|
|
3
|
+
export type LocatorPolicy = (typeof LOCATOR_POLICIES)[number];
|
|
4
|
+
/** Generates locator candidates for one interactive element, ordered by the given policy. */
|
|
5
|
+
export declare function synthesizeLocatorCandidates(element: InteractiveElement, policy: LocatorPolicy): LocatorCandidate[];
|
|
6
|
+
//# sourceMappingURL=synthesize-locators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesize-locators.d.ts","sourceRoot":"","sources":["../src/synthesize-locators.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEhF,eAAO,MAAM,gBAAgB,kEAAmE,CAAC;AACjG,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAyE9D,6FAA6F;AAC7F,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,aAAa,GACpB,gBAAgB,EAAE,CAapB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright The QA-AI-STLC Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
export const LOCATOR_POLICIES = ['playwright-default', 'testid-first', 'strict-no-css'];
|
|
4
|
+
// A CSS `id` is untrusted, page-derived text: it can contain anything, including characters that
|
|
5
|
+
// are not valid unescaped in a CSS identifier. Rather than escaping, an id outside this safe
|
|
6
|
+
// pattern falls back to the nth-of-type candidate below.
|
|
7
|
+
const CSS_SAFE_ID = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
8
|
+
function buildRoleCandidate(element) {
|
|
9
|
+
const name = element.accessibleName ?? element.label;
|
|
10
|
+
if (element.role === undefined || name === undefined) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
return { strategy: 'role', value: JSON.stringify({ role: element.role, name }), fragile: false };
|
|
14
|
+
}
|
|
15
|
+
function buildTestIdCandidate(element) {
|
|
16
|
+
return element.testId === undefined
|
|
17
|
+
? undefined
|
|
18
|
+
: { strategy: 'testId', value: element.testId, fragile: false };
|
|
19
|
+
}
|
|
20
|
+
function buildLabelCandidate(element) {
|
|
21
|
+
return element.label === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: { strategy: 'label', value: element.label, fragile: false };
|
|
24
|
+
}
|
|
25
|
+
function buildPlaceholderCandidate(element) {
|
|
26
|
+
return element.placeholder === undefined
|
|
27
|
+
? undefined
|
|
28
|
+
: { strategy: 'placeholder', value: element.placeholder, fragile: false };
|
|
29
|
+
}
|
|
30
|
+
function buildTextCandidate(element) {
|
|
31
|
+
return element.accessibleName === undefined
|
|
32
|
+
? undefined
|
|
33
|
+
: { strategy: 'text', value: element.accessibleName, fragile: false };
|
|
34
|
+
}
|
|
35
|
+
// The last-resort candidate: always present, always flagged fragile, since a CSS selector breaks
|
|
36
|
+
// under refactors that Playwright's role/label/testid locators survive (development plan 6.3.4).
|
|
37
|
+
function buildCssCandidate(element) {
|
|
38
|
+
const value = element.htmlId !== undefined && CSS_SAFE_ID.test(element.htmlId)
|
|
39
|
+
? `#${element.htmlId}`
|
|
40
|
+
: `${element.tagName}:nth-of-type(${String(element.nthOfType)})`;
|
|
41
|
+
return { strategy: 'css', value, fragile: true };
|
|
42
|
+
}
|
|
43
|
+
const NON_CSS_BUILDERS = {
|
|
44
|
+
role: buildRoleCandidate,
|
|
45
|
+
testId: buildTestIdCandidate,
|
|
46
|
+
label: buildLabelCandidate,
|
|
47
|
+
placeholder: buildPlaceholderCandidate,
|
|
48
|
+
text: buildTextCandidate,
|
|
49
|
+
};
|
|
50
|
+
// Order follows Playwright's own guidance (development plan 6.3.4): role with an accessible name
|
|
51
|
+
// first, then test ID, then label/placeholder, then text, with CSS always last. `testid-first`
|
|
52
|
+
// swaps the first two for teams that mandate stable test IDs; `strict-no-css` drops the fragile
|
|
53
|
+
// fallback entirely, so an element with none of the other signals gets zero candidates.
|
|
54
|
+
const POLICY_ORDER = {
|
|
55
|
+
'playwright-default': ['role', 'testId', 'label', 'placeholder', 'text', 'css'],
|
|
56
|
+
'testid-first': ['testId', 'role', 'label', 'placeholder', 'text', 'css'],
|
|
57
|
+
'strict-no-css': ['role', 'testId', 'label', 'placeholder', 'text'],
|
|
58
|
+
};
|
|
59
|
+
/** Generates locator candidates for one interactive element, ordered by the given policy. */
|
|
60
|
+
export function synthesizeLocatorCandidates(element, policy) {
|
|
61
|
+
const candidates = [];
|
|
62
|
+
for (const strategy of POLICY_ORDER[policy]) {
|
|
63
|
+
if (strategy === 'css') {
|
|
64
|
+
candidates.push(buildCssCandidate(element));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const candidate = NON_CSS_BUILDERS[strategy](element);
|
|
68
|
+
if (candidate !== undefined) {
|
|
69
|
+
candidates.push(candidate);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return candidates;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=synthesize-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesize-locators.js","sourceRoot":"","sources":["../src/synthesize-locators.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qa-ai-stlc/explorer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The crawler: route discovery in safe mode, redacted request logging, and the route map every later explorer phase builds on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"clean": "node ../../scripts/clean-dir.mjs dist"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@qa-ai-stlc/core": "0.
|
|
32
|
-
"@qa-ai-stlc/schemas": "0.
|
|
31
|
+
"@qa-ai-stlc/core": "0.3.0",
|
|
32
|
+
"@qa-ai-stlc/schemas": "0.4.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@qa-ai-stlc/test-utils": "0.0.0"
|