@sudobility/testomniac_runner_service 0.1.58 → 0.1.60
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/analyzer/page-analyzer/generators/content.js +4 -4
- package/dist/analyzer/page-analyzer/generators/content.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/dialogs.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer/generators/dialogs.js +3 -3
- package/dist/analyzer/page-analyzer/generators/dialogs.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/e2e.js +2 -2
- package/dist/analyzer/page-analyzer/generators/e2e.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/forms.js +8 -8
- package/dist/analyzer/page-analyzer/generators/forms.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/hover-follow-up.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer/generators/hover-follow-up.js +3 -3
- package/dist/analyzer/page-analyzer/generators/hover-follow-up.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/keyboard-disclosure.js +2 -2
- package/dist/analyzer/page-analyzer/generators/keyboard-disclosure.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/navigation.js +4 -4
- package/dist/analyzer/page-analyzer/generators/navigation.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/render.js +1 -1
- package/dist/analyzer/page-analyzer/generators/render.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/scaffolds.js +10 -10
- package/dist/analyzer/page-analyzer/generators/scaffolds.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/semantic-journeys.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer/generators/semantic-journeys.js +2 -2
- package/dist/analyzer/page-analyzer/generators/semantic-journeys.js.map +1 -1
- package/dist/analyzer/page-analyzer/generators/variants.js +2 -2
- package/dist/analyzer/page-analyzer/generators/variants.js.map +1 -1
- package/dist/analyzer/page-analyzer/index.d.ts +9 -1
- package/dist/analyzer/page-analyzer/index.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer/index.js +92 -8
- package/dist/analyzer/page-analyzer/index.js.map +1 -1
- package/dist/orchestrator/test-element-executor.d.ts.map +1 -1
- package/dist/orchestrator/test-element-executor.js +21 -2
- package/dist/orchestrator/test-element-executor.js.map +1 -1
- package/dist/orchestrator/types.d.ts +1 -0
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -85,7 +85,7 @@ export class PageAnalyzer {
|
|
|
85
85
|
if (!surface)
|
|
86
86
|
return;
|
|
87
87
|
const existing = await context.api.getTestElementsByTestSurface(surface.id, true);
|
|
88
|
-
const
|
|
88
|
+
const desiredKeys = new Set(params.desiredKeys.map(key => key.trim()).filter(Boolean));
|
|
89
89
|
const obsoleteIds = existing
|
|
90
90
|
.filter(testElement => {
|
|
91
91
|
const isGenerated = Boolean(testElement.isGenerated);
|
|
@@ -98,7 +98,8 @@ export class PageAnalyzer {
|
|
|
98
98
|
(params.dependencyTestElementId ?? null)) {
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
const existingKey = this.getPersistedGeneratedKey(testElement);
|
|
102
|
+
return !existingKey || !desiredKeys.has(existingKey);
|
|
102
103
|
})
|
|
103
104
|
.map(testElement => testElement.id);
|
|
104
105
|
if (obsoleteIds.length === 0)
|
|
@@ -172,10 +173,11 @@ export class PageAnalyzer {
|
|
|
172
173
|
],
|
|
173
174
|
globalExpectations: [],
|
|
174
175
|
uid,
|
|
176
|
+
generatedKey: this.buildGeneratedKey("navigation", startingPageStateId, path),
|
|
175
177
|
};
|
|
176
178
|
}
|
|
177
179
|
buildHoverTestElement(item, startingPath, sizeClass, uid, startingPageStateId, dependencyTestElementId) {
|
|
178
|
-
const label =
|
|
180
|
+
const label = this.describeActionableItem(item);
|
|
179
181
|
return {
|
|
180
182
|
title: `Hover over ${label}`,
|
|
181
183
|
type: "interaction",
|
|
@@ -200,10 +202,11 @@ export class PageAnalyzer {
|
|
|
200
202
|
],
|
|
201
203
|
globalExpectations: [],
|
|
202
204
|
uid,
|
|
205
|
+
generatedKey: this.buildGeneratedKey("hover", startingPageStateId, dependencyTestElementId, item.stableKey ?? item.selector ?? label),
|
|
203
206
|
};
|
|
204
207
|
}
|
|
205
208
|
buildClickTestElement(item, startingPath, sizeClass, uid, startingPageStateId, dependencyTestElementId) {
|
|
206
|
-
const label =
|
|
209
|
+
const label = this.describeActionableItem(item);
|
|
207
210
|
return {
|
|
208
211
|
title: `Click ${label}`,
|
|
209
212
|
type: "interaction",
|
|
@@ -228,6 +231,7 @@ export class PageAnalyzer {
|
|
|
228
231
|
],
|
|
229
232
|
globalExpectations: [],
|
|
230
233
|
uid,
|
|
234
|
+
generatedKey: this.buildGeneratedKey("click", startingPageStateId, dependencyTestElementId, item.stableKey ?? item.selector ?? label),
|
|
231
235
|
};
|
|
232
236
|
}
|
|
233
237
|
isHoverOnly(testElement) {
|
|
@@ -245,6 +249,49 @@ export class PageAnalyzer {
|
|
|
245
249
|
const selector = item.selector;
|
|
246
250
|
return stableKey ?? selector ?? null;
|
|
247
251
|
}
|
|
252
|
+
withGeneratedKey(testElement, ...parts) {
|
|
253
|
+
return {
|
|
254
|
+
...testElement,
|
|
255
|
+
generatedKey: this.buildGeneratedKey(...parts),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
getGeneratedKey(testElement) {
|
|
259
|
+
return (testElement.generatedKey?.trim() || testElement.title).trim();
|
|
260
|
+
}
|
|
261
|
+
getPersistedGeneratedKey(testElement) {
|
|
262
|
+
const generatedKey = testElement.generatedKey?.trim();
|
|
263
|
+
if (generatedKey)
|
|
264
|
+
return generatedKey;
|
|
265
|
+
const title = testElement.title?.trim();
|
|
266
|
+
return title || null;
|
|
267
|
+
}
|
|
268
|
+
buildGeneratedKey(...parts) {
|
|
269
|
+
const normalized = parts
|
|
270
|
+
.map(part => (part == null ? "" : String(part).trim()))
|
|
271
|
+
.filter(Boolean);
|
|
272
|
+
const raw = normalized.join("||");
|
|
273
|
+
const digest = createHash("sha1").update(raw).digest("hex").slice(0, 16);
|
|
274
|
+
const prefix = normalized
|
|
275
|
+
.slice(0, 3)
|
|
276
|
+
.map(part => part
|
|
277
|
+
.toLowerCase()
|
|
278
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
279
|
+
.replace(/^-+|-+$/g, ""))
|
|
280
|
+
.filter(Boolean)
|
|
281
|
+
.join(":")
|
|
282
|
+
.slice(0, 80);
|
|
283
|
+
return prefix ? `${prefix}:${digest}` : digest;
|
|
284
|
+
}
|
|
285
|
+
buildStepSignature(steps) {
|
|
286
|
+
return steps
|
|
287
|
+
.map(step => [
|
|
288
|
+
step.action?.actionType ?? "",
|
|
289
|
+
step.action?.path ?? "",
|
|
290
|
+
step.action?.value ?? "",
|
|
291
|
+
step.action?.description ?? "",
|
|
292
|
+
].join("|"))
|
|
293
|
+
.join("||");
|
|
294
|
+
}
|
|
248
295
|
async ensureTargetPageState(context) {
|
|
249
296
|
const scaffoldIdsBySelector = await this.ensureScaffolds(context);
|
|
250
297
|
for (const item of context.actionableItems) {
|
|
@@ -402,6 +449,7 @@ export class PageAnalyzer {
|
|
|
402
449
|
],
|
|
403
450
|
globalExpectations: this.defaultFlowExpectations("Render page without runtime errors"),
|
|
404
451
|
uid,
|
|
452
|
+
generatedKey: this.buildGeneratedKey("render", startingPageStateId, pageId, currentPath),
|
|
405
453
|
};
|
|
406
454
|
}
|
|
407
455
|
buildFormTestElement(form, formLabel, formType, currentPath, sizeClass, uid, startingPageStateId, validValues) {
|
|
@@ -446,6 +494,7 @@ export class PageAnalyzer {
|
|
|
446
494
|
this.makeExpectation("field_error_clears_after_fix", `Validation errors on ${formLabel} should clear once the fields are corrected`),
|
|
447
495
|
],
|
|
448
496
|
uid,
|
|
497
|
+
generatedKey: this.buildGeneratedKey("form-positive", startingPageStateId, form.selector, formType),
|
|
449
498
|
};
|
|
450
499
|
}
|
|
451
500
|
buildNegativeFormTestElement(form, formLabel, formType, omittedField, currentPath, sizeClass, uid, startingPageStateId, validValues) {
|
|
@@ -468,6 +517,7 @@ export class PageAnalyzer {
|
|
|
468
517
|
}),
|
|
469
518
|
],
|
|
470
519
|
uid,
|
|
520
|
+
generatedKey: this.buildGeneratedKey("form-negative", startingPageStateId, form.selector, formType, omittedField.selector),
|
|
471
521
|
};
|
|
472
522
|
}
|
|
473
523
|
buildFormCorrectionTestElement(form, formLabel, formType, correctedField, currentPath, sizeClass, uid, startingPageStateId, validValues) {
|
|
@@ -512,6 +562,7 @@ export class PageAnalyzer {
|
|
|
512
562
|
this.makeExpectation("feedback_not_duplicated", `Form ${formLabel} should not show duplicate feedback after correction`),
|
|
513
563
|
],
|
|
514
564
|
uid,
|
|
565
|
+
generatedKey: this.buildGeneratedKey("form-correction", startingPageStateId, form.selector, formType, correctedField.selector),
|
|
515
566
|
};
|
|
516
567
|
}
|
|
517
568
|
buildPasswordTestElements(form, formLabel, formType, currentPath, sizeClass, uid, startingPageStateId, validValues, passwordRequirements) {
|
|
@@ -547,6 +598,7 @@ export class PageAnalyzer {
|
|
|
547
598
|
},
|
|
548
599
|
],
|
|
549
600
|
uid,
|
|
601
|
+
generatedKey: this.buildGeneratedKey("password", startingPageStateId, form.selector, formType, variant.description, variant.password),
|
|
550
602
|
};
|
|
551
603
|
});
|
|
552
604
|
}
|
|
@@ -565,6 +617,7 @@ export class PageAnalyzer {
|
|
|
565
617
|
})),
|
|
566
618
|
globalExpectations: this.defaultFlowExpectations(`Journey to ${currentPath} should complete without runtime errors`),
|
|
567
619
|
uid,
|
|
620
|
+
generatedKey: this.buildGeneratedKey("dependency-journey", startingPageStateId, currentPath, this.buildStepSignature(journeySteps)),
|
|
568
621
|
};
|
|
569
622
|
}
|
|
570
623
|
buildFormSteps(form, valuesBySelector, omittedSelector, postSubmitExpectations = []) {
|
|
@@ -845,6 +898,7 @@ export class PageAnalyzer {
|
|
|
845
898
|
this.makeExpectation(ExpectationType.LoadingCompletes, `Search results for ${formLabel} should finish loading`),
|
|
846
899
|
],
|
|
847
900
|
uid,
|
|
901
|
+
generatedKey: this.buildGeneratedKey("search", startingPageStateId, form.selector, searchField.selector),
|
|
848
902
|
},
|
|
849
903
|
{
|
|
850
904
|
title: `Search Empty State — ${formLabel}`,
|
|
@@ -867,6 +921,7 @@ export class PageAnalyzer {
|
|
|
867
921
|
this.makeExpectation(ExpectationType.LoadingCompletes, `No-result search for ${formLabel} should finish loading`),
|
|
868
922
|
],
|
|
869
923
|
uid,
|
|
924
|
+
generatedKey: this.buildGeneratedKey("search-empty", startingPageStateId, form.selector, searchField.selector),
|
|
870
925
|
},
|
|
871
926
|
{
|
|
872
927
|
title: `Search Recovery — ${formLabel}`,
|
|
@@ -890,6 +945,7 @@ export class PageAnalyzer {
|
|
|
890
945
|
this.makeExpectation(ExpectationType.LoadingCompletes, `Search recovery for ${formLabel} should finish loading`),
|
|
891
946
|
],
|
|
892
947
|
uid,
|
|
948
|
+
generatedKey: this.buildGeneratedKey("search-recovery", startingPageStateId, form.selector, searchField.selector),
|
|
893
949
|
},
|
|
894
950
|
];
|
|
895
951
|
const clearAction = actionableItems.find(item => this.isSearchClearItem(item));
|
|
@@ -916,6 +972,7 @@ export class PageAnalyzer {
|
|
|
916
972
|
this.makeExpectation(ExpectationType.ResultsRestored, `Clearing ${formLabel} should restore the initial results baseline`),
|
|
917
973
|
],
|
|
918
974
|
uid,
|
|
975
|
+
generatedKey: this.buildGeneratedKey("search-clear", startingPageStateId, form.selector, searchField.selector, clearAction.selector),
|
|
919
976
|
});
|
|
920
977
|
}
|
|
921
978
|
return tests;
|
|
@@ -1252,6 +1309,7 @@ export class PageAnalyzer {
|
|
|
1252
1309
|
steps,
|
|
1253
1310
|
globalExpectations: this.defaultFlowExpectations(`${title} should complete without runtime errors`),
|
|
1254
1311
|
uid: context.uid,
|
|
1312
|
+
generatedKey: this.buildGeneratedKey("semantic-journey", context.currentPageStateId, context.currentPath, this.buildStepSignature(steps)),
|
|
1255
1313
|
};
|
|
1256
1314
|
}
|
|
1257
1315
|
buildJourneyAction(item, description, expectations) {
|
|
@@ -1450,6 +1508,7 @@ export class PageAnalyzer {
|
|
|
1450
1508
|
],
|
|
1451
1509
|
globalExpectations: this.defaultFlowExpectations("Variant selection should complete without runtime errors"),
|
|
1452
1510
|
uid: context.uid,
|
|
1511
|
+
generatedKey: this.buildGeneratedKey("variant-selection", context.currentPageStateId, item.selector, plannedValue),
|
|
1453
1512
|
};
|
|
1454
1513
|
}
|
|
1455
1514
|
buildVariantPurchaseJourney(item, purchaseAction, context) {
|
|
@@ -1521,6 +1580,7 @@ export class PageAnalyzer {
|
|
|
1521
1580
|
],
|
|
1522
1581
|
globalExpectations: this.defaultFlowExpectations(`Variant purchase journey for ${label} should execute cleanly`),
|
|
1523
1582
|
uid: context.uid,
|
|
1583
|
+
generatedKey: this.buildGeneratedKey("variant-purchase", context.currentPageStateId, item.selector, plannedValue, purchaseAction.selector),
|
|
1524
1584
|
};
|
|
1525
1585
|
}
|
|
1526
1586
|
buildRequiredVariantGuardTestElement(item, requiredField, purchaseAction, context) {
|
|
@@ -1544,6 +1604,7 @@ export class PageAnalyzer {
|
|
|
1544
1604
|
],
|
|
1545
1605
|
globalExpectations: this.defaultFlowExpectations(`${label} should be enforced before ${purchaseLabel}`),
|
|
1546
1606
|
uid: context.uid,
|
|
1607
|
+
generatedKey: this.buildGeneratedKey("variant-guard", context.currentPageStateId, item.selector, requiredField.selector, purchaseAction.selector),
|
|
1547
1608
|
};
|
|
1548
1609
|
}
|
|
1549
1610
|
findRequiredVariantField(item, forms) {
|
|
@@ -1585,6 +1646,7 @@ export class PageAnalyzer {
|
|
|
1585
1646
|
],
|
|
1586
1647
|
globalExpectations: this.defaultFlowExpectations("Disclosure interaction should complete without runtime errors"),
|
|
1587
1648
|
uid,
|
|
1649
|
+
generatedKey: this.buildGeneratedKey("disclosure-click", startingPageStateId, item.stableKey ?? item.selector ?? label),
|
|
1588
1650
|
};
|
|
1589
1651
|
}
|
|
1590
1652
|
buildKeyboardActivateTestElement(item, key, titlePrefix, expectations, startingPath, sizeClass, uid, startingPageStateId) {
|
|
@@ -1630,6 +1692,7 @@ export class PageAnalyzer {
|
|
|
1630
1692
|
],
|
|
1631
1693
|
globalExpectations: this.defaultFlowExpectations("Keyboard activation should complete without runtime errors"),
|
|
1632
1694
|
uid,
|
|
1695
|
+
generatedKey: this.buildGeneratedKey("keyboard", startingPageStateId, key === " " ? "space" : key, item.stableKey ?? item.selector ?? label),
|
|
1633
1696
|
};
|
|
1634
1697
|
}
|
|
1635
1698
|
buildDialogCloseTestElement(item, startingPath, sizeClass, uid, startingPageStateId) {
|
|
@@ -1660,6 +1723,7 @@ export class PageAnalyzer {
|
|
|
1660
1723
|
],
|
|
1661
1724
|
globalExpectations: this.defaultFlowExpectations("Dialog should close cleanly"),
|
|
1662
1725
|
uid,
|
|
1726
|
+
generatedKey: this.buildGeneratedKey("dialog-close", startingPageStateId, item.stableKey ?? item.selector ?? label),
|
|
1663
1727
|
};
|
|
1664
1728
|
}
|
|
1665
1729
|
buildEscapeDialogTestElement(startingPath, sizeClass, uid, startingPageStateId) {
|
|
@@ -1689,6 +1753,7 @@ export class PageAnalyzer {
|
|
|
1689
1753
|
],
|
|
1690
1754
|
globalExpectations: this.defaultFlowExpectations("Dialog should close on Escape without runtime errors"),
|
|
1691
1755
|
uid,
|
|
1756
|
+
generatedKey: this.buildGeneratedKey("dialog-escape", startingPageStateId, startingPath),
|
|
1692
1757
|
};
|
|
1693
1758
|
}
|
|
1694
1759
|
shouldUseDirectControlInteraction(item) {
|
|
@@ -1706,7 +1771,7 @@ export class PageAnalyzer {
|
|
|
1706
1771
|
inputType === "checkbox");
|
|
1707
1772
|
}
|
|
1708
1773
|
buildControlInteractionTestElement(item, startingPath, sizeClass, uid, startingPageStateId) {
|
|
1709
|
-
const label =
|
|
1774
|
+
const label = this.describeActionableItem(item);
|
|
1710
1775
|
const role = (item.role ?? "").toLowerCase();
|
|
1711
1776
|
const inputType = (item.inputType ?? "").toLowerCase();
|
|
1712
1777
|
const isTab = role === "tab";
|
|
@@ -1791,6 +1856,7 @@ export class PageAnalyzer {
|
|
|
1791
1856
|
? `${label} should remain non-interactive despite appearing disabled`
|
|
1792
1857
|
: `${label} should react without runtime errors`),
|
|
1793
1858
|
uid,
|
|
1859
|
+
generatedKey: this.buildGeneratedKey("control", startingPageStateId, isImmutable ? "immutable" : "enabled", role || inputType || item.actionKind || "control", item.stableKey ?? item.selector ?? label),
|
|
1794
1860
|
};
|
|
1795
1861
|
}
|
|
1796
1862
|
buildImmutableControlExpectations(item, label) {
|
|
@@ -1873,12 +1939,30 @@ export class PageAnalyzer {
|
|
|
1873
1939
|
value.includes("disabled"));
|
|
1874
1940
|
}
|
|
1875
1941
|
describeActionableItem(item) {
|
|
1876
|
-
|
|
1942
|
+
const described = (item.accessibleName ||
|
|
1877
1943
|
item.textContent ||
|
|
1878
1944
|
String(item.attributes?._containerTitle ?? "") ||
|
|
1879
1945
|
String(item.attributes?.labelText ?? "") ||
|
|
1880
|
-
String(item.attributes?.placeholder ?? "")
|
|
1881
|
-
|
|
1946
|
+
String(item.attributes?.placeholder ?? "")).trim();
|
|
1947
|
+
if (described)
|
|
1948
|
+
return described;
|
|
1949
|
+
const selector = item.selector ?? "";
|
|
1950
|
+
if (selector.includes("data-tmnc-id")) {
|
|
1951
|
+
const role = item.role?.trim();
|
|
1952
|
+
const inputType = item.inputType?.trim();
|
|
1953
|
+
if (role)
|
|
1954
|
+
return role;
|
|
1955
|
+
if (inputType)
|
|
1956
|
+
return inputType;
|
|
1957
|
+
if (item.actionKind === "navigate")
|
|
1958
|
+
return "link";
|
|
1959
|
+
if (item.actionKind === "fill")
|
|
1960
|
+
return "input";
|
|
1961
|
+
if (item.actionKind === "select")
|
|
1962
|
+
return "select";
|
|
1963
|
+
return "control";
|
|
1964
|
+
}
|
|
1965
|
+
return selector || item.actionKind || "control";
|
|
1882
1966
|
}
|
|
1883
1967
|
semanticText(item) {
|
|
1884
1968
|
return [
|