@sudobility/testomniac_runner_service 0.1.44 → 0.1.46
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.d.ts +74 -1
- package/dist/analyzer/page-analyzer.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer.js +1491 -6
- package/dist/analyzer/page-analyzer.js.map +1 -1
- package/dist/browser/control-snapshot.d.ts +4 -0
- package/dist/browser/control-snapshot.d.ts.map +1 -0
- package/dist/browser/control-snapshot.js +181 -0
- package/dist/browser/control-snapshot.js.map +1 -0
- package/dist/browser/dom-snapshot.d.ts.map +1 -1
- package/dist/browser/dom-snapshot.js +8 -0
- package/dist/browser/dom-snapshot.js.map +1 -1
- package/dist/browser/ui-snapshot.d.ts +9 -0
- package/dist/browser/ui-snapshot.d.ts.map +1 -0
- package/dist/browser/ui-snapshot.js +53 -0
- package/dist/browser/ui-snapshot.js.map +1 -0
- package/dist/expertise/content-expertise.d.ts +1 -0
- package/dist/expertise/content-expertise.d.ts.map +1 -1
- package/dist/expertise/content-expertise.js +38 -0
- package/dist/expertise/content-expertise.js.map +1 -1
- package/dist/expertise/tester/commerce-checks.d.ts +18 -0
- package/dist/expertise/tester/commerce-checks.d.ts.map +1 -0
- package/dist/expertise/tester/commerce-checks.js +158 -0
- package/dist/expertise/tester/commerce-checks.js.map +1 -0
- package/dist/expertise/tester/control-state.d.ts +31 -0
- package/dist/expertise/tester/control-state.d.ts.map +1 -0
- package/dist/expertise/tester/control-state.js +46 -0
- package/dist/expertise/tester/control-state.js.map +1 -0
- package/dist/expertise/tester/core-checks.d.ts +5 -0
- package/dist/expertise/tester/core-checks.d.ts.map +1 -0
- package/dist/expertise/tester/core-checks.js +46 -0
- package/dist/expertise/tester/core-checks.js.map +1 -0
- package/dist/expertise/tester/dialog-feedback-checks.d.ts +13 -0
- package/dist/expertise/tester/dialog-feedback-checks.d.ts.map +1 -0
- package/dist/expertise/tester/dialog-feedback-checks.js +82 -0
- package/dist/expertise/tester/dialog-feedback-checks.js.map +1 -0
- package/dist/expertise/tester/form-checks.d.ts +8 -0
- package/dist/expertise/tester/form-checks.d.ts.map +1 -0
- package/dist/expertise/tester/form-checks.js +50 -0
- package/dist/expertise/tester/form-checks.js.map +1 -0
- package/dist/expertise/tester/keyboard-disclosure-checks.d.ts +7 -0
- package/dist/expertise/tester/keyboard-disclosure-checks.d.ts.map +1 -0
- package/dist/expertise/tester/keyboard-disclosure-checks.js +46 -0
- package/dist/expertise/tester/keyboard-disclosure-checks.js.map +1 -0
- package/dist/expertise/tester/navigation-checks.d.ts +8 -0
- package/dist/expertise/tester/navigation-checks.d.ts.map +1 -0
- package/dist/expertise/tester/navigation-checks.js +64 -0
- package/dist/expertise/tester/navigation-checks.js.map +1 -0
- package/dist/expertise/tester/page-behavior-checks.d.ts +17 -0
- package/dist/expertise/tester/page-behavior-checks.d.ts.map +1 -0
- package/dist/expertise/tester/page-behavior-checks.js +144 -0
- package/dist/expertise/tester/page-behavior-checks.js.map +1 -0
- package/dist/expertise/tester/persistence-checks.d.ts +12 -0
- package/dist/expertise/tester/persistence-checks.d.ts.map +1 -0
- package/dist/expertise/tester/persistence-checks.js +109 -0
- package/dist/expertise/tester/persistence-checks.js.map +1 -0
- package/dist/expertise/tester/selection-control-checks.d.ts +7 -0
- package/dist/expertise/tester/selection-control-checks.d.ts.map +1 -0
- package/dist/expertise/tester/selection-control-checks.js +128 -0
- package/dist/expertise/tester/selection-control-checks.js.map +1 -0
- package/dist/expertise/tester/text-input-checks.d.ts +8 -0
- package/dist/expertise/tester/text-input-checks.d.ts.map +1 -0
- package/dist/expertise/tester/text-input-checks.js +194 -0
- package/dist/expertise/tester/text-input-checks.js.map +1 -0
- package/dist/expertise/tester/validation-checks.d.ts +10 -0
- package/dist/expertise/tester/validation-checks.d.ts.map +1 -0
- package/dist/expertise/tester/validation-checks.js +59 -0
- package/dist/expertise/tester/validation-checks.js.map +1 -0
- package/dist/expertise/tester-expertise.d.ts +0 -3
- package/dist/expertise/tester-expertise.d.ts.map +1 -1
- package/dist/expertise/tester-expertise.js +69 -49
- package/dist/expertise/tester-expertise.js.map +1 -1
- package/dist/expertise/types.d.ts +12 -1
- package/dist/expertise/types.d.ts.map +1 -1
- package/dist/extractors/form-extractor.d.ts +19 -0
- package/dist/extractors/form-extractor.d.ts.map +1 -1
- package/dist/extractors/form-extractor.js +271 -42
- package/dist/extractors/form-extractor.js.map +1 -1
- package/dist/orchestrator/test-element-executor.d.ts.map +1 -1
- package/dist/orchestrator/test-element-executor.js +74 -9
- package/dist/orchestrator/test-element-executor.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function checkUrlUnchanged(expectation, context) {
|
|
2
|
+
const startingPath = context.startingPath ?? "";
|
|
3
|
+
const currentUrl = context.currentUrl ?? "";
|
|
4
|
+
if (!startingPath || !currentUrl) {
|
|
5
|
+
return {
|
|
6
|
+
expected: expectation.description,
|
|
7
|
+
observed: "URL comparison context was unavailable",
|
|
8
|
+
result: "warning",
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
if (!currentUrl.includes(startingPath)) {
|
|
12
|
+
return {
|
|
13
|
+
expected: expectation.description,
|
|
14
|
+
observed: `URL changed unexpectedly to ${currentUrl}`,
|
|
15
|
+
result: "error",
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
expected: expectation.description,
|
|
20
|
+
observed: `URL remained on ${currentUrl}`,
|
|
21
|
+
result: "pass",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function checkNavigationOrStateChanged(expectation, context) {
|
|
25
|
+
const initialUrl = context.initialUrl ?? "";
|
|
26
|
+
const currentUrl = context.currentUrl ?? "";
|
|
27
|
+
if (initialUrl && currentUrl && initialUrl !== currentUrl) {
|
|
28
|
+
return {
|
|
29
|
+
expected: expectation.description,
|
|
30
|
+
observed: `URL changed from ${initialUrl} to ${currentUrl}`,
|
|
31
|
+
result: "pass",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (normalizeHtml(context.initialHtml) !== normalizeHtml(context.html)) {
|
|
35
|
+
return {
|
|
36
|
+
expected: expectation.description,
|
|
37
|
+
observed: "DOM changed after interaction",
|
|
38
|
+
result: "pass",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const controlChanged = context.finalControlStates.some(finalState => {
|
|
42
|
+
const initialState = context.initialControlStates.find(candidate => candidate.selector === finalState.selector);
|
|
43
|
+
return (!initialState ||
|
|
44
|
+
initialState.value !== finalState.value ||
|
|
45
|
+
initialState.checked !== finalState.checked ||
|
|
46
|
+
initialState.selected !== finalState.selected);
|
|
47
|
+
});
|
|
48
|
+
if (controlChanged) {
|
|
49
|
+
return {
|
|
50
|
+
expected: expectation.description,
|
|
51
|
+
observed: "Control state changed after interaction",
|
|
52
|
+
result: "pass",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
expected: expectation.description,
|
|
57
|
+
observed: "No URL, DOM, or control-state change was detected",
|
|
58
|
+
result: "error",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function normalizeHtml(html) {
|
|
62
|
+
return html.replace(/\s+/g, " ").trim();
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=navigation-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/navigation-checks.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAC/B,WAAoC,EACpC,OAAyB;IAEzB,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAE5C,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,wCAAwC;YAClD,MAAM,EAAE,SAAS;SAClB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACvC,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,+BAA+B,UAAU,EAAE;YACrD,MAAM,EAAE,OAAO;SAChB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,WAAW;QACjC,QAAQ,EAAE,mBAAmB,UAAU,EAAE;QACzC,MAAM,EAAE,MAAM;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,WAAoC,EACpC,OAAyB;IAEzB,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IAE5C,IAAI,UAAU,IAAI,UAAU,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;QAC1D,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,oBAAoB,UAAU,OAAO,UAAU,EAAE;YAC3D,MAAM,EAAE,MAAM;SACf,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACvE,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,+BAA+B;YACzC,MAAM,EAAE,MAAM;SACf,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;QAClE,MAAM,YAAY,GAAG,OAAO,CAAC,oBAAoB,CAAC,IAAI,CACpD,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,CACxD,CAAC;QACF,OAAO,CACL,CAAC,YAAY;YACb,YAAY,CAAC,KAAK,KAAK,UAAU,CAAC,KAAK;YACvC,YAAY,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO;YAC3C,YAAY,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,CAC9C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,yCAAyC;YACnD,MAAM,EAAE,MAAM;SACf,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,WAAW;QACjC,QAAQ,EAAE,mDAAmD;QAC7D,MAAM,EAAE,OAAO;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExpertiseContext, Outcome } from "../types";
|
|
2
|
+
export declare function checkPageResponsive(expectation: {
|
|
3
|
+
description: string;
|
|
4
|
+
}, context: ExpertiseContext): Outcome;
|
|
5
|
+
export declare function checkLoadingCompletes(expectation: {
|
|
6
|
+
description: string;
|
|
7
|
+
}, context: ExpertiseContext): Outcome;
|
|
8
|
+
export declare function checkModalOpened(expectation: {
|
|
9
|
+
description: string;
|
|
10
|
+
}, context: ExpertiseContext): Outcome;
|
|
11
|
+
export declare function checkMediaLoaded(expectation: {
|
|
12
|
+
description: string;
|
|
13
|
+
}, context: ExpertiseContext): Outcome;
|
|
14
|
+
export declare function checkVideoPlayable(expectation: {
|
|
15
|
+
description: string;
|
|
16
|
+
}, context: ExpertiseContext): Outcome;
|
|
17
|
+
//# sourceMappingURL=page-behavior-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-behavior-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/page-behavior-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAsBT;AAED,wBAAgB,qBAAqB,CACnC,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAuBT;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAiBT;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAqCT;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA4BT"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export function checkPageResponsive(expectation, context) {
|
|
2
|
+
if (!context.html || !context.currentUrl) {
|
|
3
|
+
return {
|
|
4
|
+
expected: expectation.description,
|
|
5
|
+
observed: "No stable page snapshot was available after interaction",
|
|
6
|
+
result: "error",
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (looksLikeFatalPage(context.html)) {
|
|
10
|
+
return {
|
|
11
|
+
expected: expectation.description,
|
|
12
|
+
observed: "Page appears to be in a fatal or crashed state",
|
|
13
|
+
result: "error",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
expected: expectation.description,
|
|
18
|
+
observed: "Page remained responsive enough to produce a stable snapshot",
|
|
19
|
+
result: "pass",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function checkLoadingCompletes(expectation, context) {
|
|
23
|
+
const text = stripHtml(context.html).toLowerCase();
|
|
24
|
+
const loadingMatches = [
|
|
25
|
+
"loading...",
|
|
26
|
+
"adding to cart...",
|
|
27
|
+
"please wait",
|
|
28
|
+
"processing...",
|
|
29
|
+
"submitting...",
|
|
30
|
+
].filter(token => text.includes(token));
|
|
31
|
+
if (loadingMatches.length > 0 && text.length < 4000) {
|
|
32
|
+
return {
|
|
33
|
+
expected: expectation.description,
|
|
34
|
+
observed: `Page still shows loading state markers: ${loadingMatches.join(", ")}`,
|
|
35
|
+
result: "error",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
expected: expectation.description,
|
|
40
|
+
observed: "No obvious persistent loading state was detected",
|
|
41
|
+
result: "pass",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function checkModalOpened(expectation, context) {
|
|
45
|
+
const initialCount = countModalSignals(context.initialHtml);
|
|
46
|
+
const finalCount = countModalSignals(context.html);
|
|
47
|
+
if (finalCount > initialCount) {
|
|
48
|
+
return {
|
|
49
|
+
expected: expectation.description,
|
|
50
|
+
observed: `Modal/dialog signals increased from ${initialCount} to ${finalCount}`,
|
|
51
|
+
result: "pass",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
expected: expectation.description,
|
|
56
|
+
observed: "No new modal or dialog signal was detected",
|
|
57
|
+
result: "error",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function checkMediaLoaded(expectation, context) {
|
|
61
|
+
const mediaErrors = context.networkLogs.filter(log => {
|
|
62
|
+
const type = (log.contentType ?? "").toLowerCase();
|
|
63
|
+
return (log.status >= 400 &&
|
|
64
|
+
(type.startsWith("image/") ||
|
|
65
|
+
type.startsWith("video/") ||
|
|
66
|
+
/\.(png|jpe?g|gif|webp|svg|mp4|webm|mov)(\?|$)/i.test(log.url)));
|
|
67
|
+
});
|
|
68
|
+
if (mediaErrors.length > 0) {
|
|
69
|
+
return {
|
|
70
|
+
expected: expectation.description,
|
|
71
|
+
observed: `Media request failed: ${mediaErrors[0].url} (${mediaErrors[0].status})`,
|
|
72
|
+
result: "error",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const text = stripHtml(context.html).toLowerCase();
|
|
76
|
+
if (text.includes("broken image") ||
|
|
77
|
+
text.includes("failed to load image") ||
|
|
78
|
+
text.includes("image not available")) {
|
|
79
|
+
return {
|
|
80
|
+
expected: expectation.description,
|
|
81
|
+
observed: "Page text indicates the media did not load correctly",
|
|
82
|
+
result: "error",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
expected: expectation.description,
|
|
87
|
+
observed: "No obvious media load failure was detected",
|
|
88
|
+
result: "pass",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export function checkVideoPlayable(expectation, context) {
|
|
92
|
+
const text = stripHtml(context.html).toLowerCase();
|
|
93
|
+
if (text.includes("your browser does not support the video tag")) {
|
|
94
|
+
return {
|
|
95
|
+
expected: expectation.description,
|
|
96
|
+
observed: "Video fallback text indicates the player did not initialize correctly",
|
|
97
|
+
result: "error",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const videoErrors = context.networkLogs.filter(log => {
|
|
101
|
+
const type = (log.contentType ?? "").toLowerCase();
|
|
102
|
+
return log.status >= 400 && type.startsWith("video/");
|
|
103
|
+
});
|
|
104
|
+
if (videoErrors.length > 0) {
|
|
105
|
+
return {
|
|
106
|
+
expected: expectation.description,
|
|
107
|
+
observed: `Video request failed: ${videoErrors[0].url} (${videoErrors[0].status})`,
|
|
108
|
+
result: "error",
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
expected: expectation.description,
|
|
113
|
+
observed: "No obvious video playback failure was detected",
|
|
114
|
+
result: "pass",
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function stripHtml(html) {
|
|
118
|
+
return html
|
|
119
|
+
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
|
120
|
+
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
|
121
|
+
.replace(/<[^>]+>/g, " ")
|
|
122
|
+
.replace(/\s+/g, " ")
|
|
123
|
+
.trim();
|
|
124
|
+
}
|
|
125
|
+
function countModalSignals(html) {
|
|
126
|
+
const patterns = [
|
|
127
|
+
/role=["']dialog["']/gi,
|
|
128
|
+
/role=["']alertdialog["']/gi,
|
|
129
|
+
/aria-modal=["']true["']/gi,
|
|
130
|
+
/\bmodal\b/gi,
|
|
131
|
+
/\blightbox\b/gi,
|
|
132
|
+
/\boverlay\b/gi,
|
|
133
|
+
];
|
|
134
|
+
return patterns.reduce((count, pattern) => count + (html.match(pattern)?.length ?? 0), 0);
|
|
135
|
+
}
|
|
136
|
+
function looksLikeFatalPage(html) {
|
|
137
|
+
const lower = stripHtml(html).toLowerCase();
|
|
138
|
+
return (lower.includes("this page isn’t working") ||
|
|
139
|
+
lower.includes("this page isn't working") ||
|
|
140
|
+
lower.includes("aw, snap") ||
|
|
141
|
+
lower.includes("application error") ||
|
|
142
|
+
lower.includes("something went wrong"));
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=page-behavior-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-behavior-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/page-behavior-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ExpertiseContext, Outcome } from "../types";
|
|
2
|
+
export declare function checkStatePersistsAfterReload(expectation: {
|
|
3
|
+
description: string;
|
|
4
|
+
expectedTextTokens?: string[];
|
|
5
|
+
}, context: ExpertiseContext): Outcome;
|
|
6
|
+
export declare function checkBackNavigationRestoresState(expectation: {
|
|
7
|
+
description: string;
|
|
8
|
+
}, context: ExpertiseContext): Outcome;
|
|
9
|
+
export declare function checkForwardNavigationReappliesState(expectation: {
|
|
10
|
+
description: string;
|
|
11
|
+
}, context: ExpertiseContext): Outcome;
|
|
12
|
+
//# sourceMappingURL=persistence-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/persistence-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAiCT;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA8BT;AAED,wBAAgB,oCAAoC,CAClD,WAAW,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA8BT"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export function checkStatePersistsAfterReload(expectation, context) {
|
|
2
|
+
const tokens = expectation.expectedTextTokens?.length
|
|
3
|
+
? expectation.expectedTextTokens
|
|
4
|
+
: ["cart", "bag", "basket", "filter", "sort", "qty", "quantity"];
|
|
5
|
+
const initialSignals = extractTokenSignals(context.initialHtml, tokens);
|
|
6
|
+
const finalSignals = extractTokenSignals(context.html, tokens);
|
|
7
|
+
if (initialSignals.length === 0 || finalSignals.length === 0) {
|
|
8
|
+
return {
|
|
9
|
+
expected: expectation.description,
|
|
10
|
+
observed: "Could not extract comparable persisted-state signals from page content",
|
|
11
|
+
result: "warning",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const missing = initialSignals.filter(signal => !finalSignals.includes(signal));
|
|
15
|
+
if (missing.length > 0) {
|
|
16
|
+
return {
|
|
17
|
+
expected: expectation.description,
|
|
18
|
+
observed: `Expected persisted signals were missing after reload: ${missing.join(", ")}`,
|
|
19
|
+
result: "error",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
expected: expectation.description,
|
|
24
|
+
observed: "Key visible state signals persisted after reload",
|
|
25
|
+
result: "pass",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function checkBackNavigationRestoresState(expectation, context) {
|
|
29
|
+
if (!context.initialUrl || !context.currentUrl) {
|
|
30
|
+
return {
|
|
31
|
+
expected: expectation.description,
|
|
32
|
+
observed: "Navigation context was unavailable",
|
|
33
|
+
result: "warning",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (context.initialUrl === context.currentUrl) {
|
|
37
|
+
return {
|
|
38
|
+
expected: expectation.description,
|
|
39
|
+
observed: `Back navigation returned to ${context.currentUrl}`,
|
|
40
|
+
result: "pass",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (normalizeHtml(context.initialHtml) === normalizeHtml(context.html)) {
|
|
44
|
+
return {
|
|
45
|
+
expected: expectation.description,
|
|
46
|
+
observed: "Back navigation restored the prior DOM state",
|
|
47
|
+
result: "pass",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
expected: expectation.description,
|
|
52
|
+
observed: `Back navigation did not restore the prior state (${context.initialUrl} -> ${context.currentUrl})`,
|
|
53
|
+
result: "error",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function checkForwardNavigationReappliesState(expectation, context) {
|
|
57
|
+
if (!context.initialUrl || !context.currentUrl) {
|
|
58
|
+
return {
|
|
59
|
+
expected: expectation.description,
|
|
60
|
+
observed: "Navigation context was unavailable",
|
|
61
|
+
result: "warning",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (context.initialUrl !== context.currentUrl) {
|
|
65
|
+
return {
|
|
66
|
+
expected: expectation.description,
|
|
67
|
+
observed: `Forward navigation reapplied a different state (${context.initialUrl} -> ${context.currentUrl})`,
|
|
68
|
+
result: "pass",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (normalizeHtml(context.initialHtml) !== normalizeHtml(context.html)) {
|
|
72
|
+
return {
|
|
73
|
+
expected: expectation.description,
|
|
74
|
+
observed: "Forward navigation changed the DOM state",
|
|
75
|
+
result: "pass",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
expected: expectation.description,
|
|
80
|
+
observed: "Forward navigation did not reapply a distinct state",
|
|
81
|
+
result: "error",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function extractTokenSignals(html, tokens) {
|
|
85
|
+
const text = stripHtml(html).toLowerCase();
|
|
86
|
+
const matches = [];
|
|
87
|
+
for (const token of tokens) {
|
|
88
|
+
const regex = new RegExp(`(?:${escapeRegex(token)})\\D{0,18}(\\d{1,4}|[a-z0-9_-]{2,30})`, "gi");
|
|
89
|
+
for (const match of text.matchAll(regex)) {
|
|
90
|
+
matches.push(`${token}:${match[1]}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return Array.from(new Set(matches));
|
|
94
|
+
}
|
|
95
|
+
function stripHtml(html) {
|
|
96
|
+
return html
|
|
97
|
+
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
|
98
|
+
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
|
99
|
+
.replace(/<[^>]+>/g, " ")
|
|
100
|
+
.replace(/\s+/g, " ")
|
|
101
|
+
.trim();
|
|
102
|
+
}
|
|
103
|
+
function normalizeHtml(html) {
|
|
104
|
+
return html.replace(/\s+/g, " ").trim();
|
|
105
|
+
}
|
|
106
|
+
function escapeRegex(value) {
|
|
107
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=persistence-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/persistence-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExpertiseContext, Outcome } from "../types";
|
|
2
|
+
export declare function checkSelectionState(expectation: {
|
|
3
|
+
description: string;
|
|
4
|
+
targetPath?: string;
|
|
5
|
+
expectNoChange?: boolean;
|
|
6
|
+
}, context: ExpertiseContext): Outcome;
|
|
7
|
+
//# sourceMappingURL=selection-control-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-control-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/selection-control-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAO1D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAqET"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { classifyControlKind, findControlBySelector, findControlPeers, } from "./control-state";
|
|
2
|
+
export function checkSelectionState(expectation, context) {
|
|
3
|
+
const initial = findControlBySelector(context.initialControlStates, expectation.targetPath);
|
|
4
|
+
const final = findControlBySelector(context.finalControlStates, expectation.targetPath);
|
|
5
|
+
if (!final) {
|
|
6
|
+
return {
|
|
7
|
+
expected: expectation.description,
|
|
8
|
+
observed: `Target control not found for selector ${expectation.targetPath ?? "(unknown)"}`,
|
|
9
|
+
result: "error",
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (expectation.expectNoChange || final.disabled) {
|
|
13
|
+
if (!initial) {
|
|
14
|
+
return {
|
|
15
|
+
expected: expectation.description,
|
|
16
|
+
observed: "Disabled control was not present in the initial snapshot",
|
|
17
|
+
result: "error",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (initial.checked !== final.checked ||
|
|
21
|
+
initial.selected !== final.selected ||
|
|
22
|
+
initial.value !== final.value) {
|
|
23
|
+
return {
|
|
24
|
+
expected: expectation.description,
|
|
25
|
+
observed: "Disabled control changed state after interaction",
|
|
26
|
+
result: "error",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
expected: expectation.description,
|
|
31
|
+
observed: expectation.expectNoChange
|
|
32
|
+
? "Control did not respond to interaction"
|
|
33
|
+
: "Disabled control did not respond to interaction",
|
|
34
|
+
result: "pass",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const kind = classifyControlKind(final);
|
|
38
|
+
switch (kind) {
|
|
39
|
+
case "radio":
|
|
40
|
+
return checkRadioSelection(expectation.description, final, context);
|
|
41
|
+
case "checkbox":
|
|
42
|
+
case "switch":
|
|
43
|
+
return checkCheckboxSelection(expectation.description, initial, final, context);
|
|
44
|
+
case "tab":
|
|
45
|
+
return checkTabSelection(expectation.description, final, context);
|
|
46
|
+
default:
|
|
47
|
+
return {
|
|
48
|
+
expected: expectation.description,
|
|
49
|
+
observed: `Control kind "${kind}" does not support selection assertions`,
|
|
50
|
+
result: "warning",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function checkRadioSelection(description, final, context) {
|
|
55
|
+
const peers = findControlPeers(context.finalControlStates, final);
|
|
56
|
+
const checkedPeers = peers.filter(peer => peer.checked || peer.selected);
|
|
57
|
+
if (!(final.checked || final.selected)) {
|
|
58
|
+
return {
|
|
59
|
+
expected: description,
|
|
60
|
+
observed: "Radio control was not selected after interaction",
|
|
61
|
+
result: "error",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (checkedPeers.length > 1) {
|
|
65
|
+
return {
|
|
66
|
+
expected: description,
|
|
67
|
+
observed: `Radio group has multiple selected controls (${checkedPeers.length})`,
|
|
68
|
+
result: "error",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
expected: description,
|
|
73
|
+
observed: "Radio control selected itself and unselected the rest of its group",
|
|
74
|
+
result: "pass",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function checkCheckboxSelection(description, initial, final, context) {
|
|
78
|
+
if (!final.checked) {
|
|
79
|
+
return {
|
|
80
|
+
expected: description,
|
|
81
|
+
observed: "Checkbox-like control is not checked after interaction",
|
|
82
|
+
result: "error",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const initialPeers = findControlPeers(context.initialControlStates, initial);
|
|
86
|
+
const finalPeers = findControlPeers(context.finalControlStates, final);
|
|
87
|
+
for (const peer of initialPeers) {
|
|
88
|
+
if (!peer.checked || peer.selector === final.selector)
|
|
89
|
+
continue;
|
|
90
|
+
const matchingFinal = finalPeers.find(candidate => candidate.selector === peer.selector);
|
|
91
|
+
if (matchingFinal && !matchingFinal.checked) {
|
|
92
|
+
return {
|
|
93
|
+
expected: description,
|
|
94
|
+
observed: `Checkbox interaction unexpectedly unchecked sibling control ${peer.selector}`,
|
|
95
|
+
result: "error",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
expected: description,
|
|
101
|
+
observed: "Checkbox-like control checked itself without clearing other checked siblings",
|
|
102
|
+
result: "pass",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function checkTabSelection(description, final, context) {
|
|
106
|
+
const peers = findControlPeers(context.finalControlStates, final);
|
|
107
|
+
const selectedPeers = peers.filter(peer => peer.selected);
|
|
108
|
+
if (!final.selected) {
|
|
109
|
+
return {
|
|
110
|
+
expected: description,
|
|
111
|
+
observed: "Tab did not become selected after interaction",
|
|
112
|
+
result: "error",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (selectedPeers.length !== 1) {
|
|
116
|
+
return {
|
|
117
|
+
expected: description,
|
|
118
|
+
observed: `Tablist has ${selectedPeers.length} selected tabs instead of exactly one`,
|
|
119
|
+
result: "error",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
expected: description,
|
|
124
|
+
observed: "Tab interaction resulted in a single selected tab",
|
|
125
|
+
result: "pass",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=selection-control-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection-control-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/selection-control-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExpertiseContext, Outcome } from "../types";
|
|
2
|
+
export declare function checkInputValue(expectation: {
|
|
3
|
+
description: string;
|
|
4
|
+
expectedValue?: string;
|
|
5
|
+
targetPath?: string;
|
|
6
|
+
expectNoChange?: boolean;
|
|
7
|
+
}, context: ExpertiseContext): Outcome;
|
|
8
|
+
//# sourceMappingURL=text-input-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-input-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/text-input-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAQ1D,wBAAgB,eAAe,CAC7B,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAuFT"}
|