@sudobility/testomniac_runner_service 0.1.45 → 0.1.47

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.
Files changed (89) hide show
  1. package/dist/analyzer/page-analyzer.d.ts +78 -1
  2. package/dist/analyzer/page-analyzer.d.ts.map +1 -1
  3. package/dist/analyzer/page-analyzer.js +1600 -6
  4. package/dist/analyzer/page-analyzer.js.map +1 -1
  5. package/dist/browser/control-snapshot.d.ts +4 -0
  6. package/dist/browser/control-snapshot.d.ts.map +1 -0
  7. package/dist/browser/control-snapshot.js +181 -0
  8. package/dist/browser/control-snapshot.js.map +1 -0
  9. package/dist/browser/dom-snapshot.d.ts.map +1 -1
  10. package/dist/browser/dom-snapshot.js +8 -0
  11. package/dist/browser/dom-snapshot.js.map +1 -1
  12. package/dist/browser/ui-snapshot.d.ts +9 -0
  13. package/dist/browser/ui-snapshot.d.ts.map +1 -0
  14. package/dist/browser/ui-snapshot.js +53 -0
  15. package/dist/browser/ui-snapshot.js.map +1 -0
  16. package/dist/expertise/content-expertise.d.ts +1 -0
  17. package/dist/expertise/content-expertise.d.ts.map +1 -1
  18. package/dist/expertise/content-expertise.js +38 -0
  19. package/dist/expertise/content-expertise.js.map +1 -1
  20. package/dist/expertise/tester/commerce-checks.d.ts +14 -0
  21. package/dist/expertise/tester/commerce-checks.d.ts.map +1 -0
  22. package/dist/expertise/tester/commerce-checks.js +132 -0
  23. package/dist/expertise/tester/commerce-checks.js.map +1 -0
  24. package/dist/expertise/tester/control-state.d.ts +31 -0
  25. package/dist/expertise/tester/control-state.d.ts.map +1 -0
  26. package/dist/expertise/tester/control-state.js +46 -0
  27. package/dist/expertise/tester/control-state.js.map +1 -0
  28. package/dist/expertise/tester/core-checks.d.ts +5 -0
  29. package/dist/expertise/tester/core-checks.d.ts.map +1 -0
  30. package/dist/expertise/tester/core-checks.js +46 -0
  31. package/dist/expertise/tester/core-checks.js.map +1 -0
  32. package/dist/expertise/tester/dialog-feedback-checks.d.ts +13 -0
  33. package/dist/expertise/tester/dialog-feedback-checks.d.ts.map +1 -0
  34. package/dist/expertise/tester/dialog-feedback-checks.js +82 -0
  35. package/dist/expertise/tester/dialog-feedback-checks.js.map +1 -0
  36. package/dist/expertise/tester/form-checks.d.ts +8 -0
  37. package/dist/expertise/tester/form-checks.d.ts.map +1 -0
  38. package/dist/expertise/tester/form-checks.js +50 -0
  39. package/dist/expertise/tester/form-checks.js.map +1 -0
  40. package/dist/expertise/tester/keyboard-disclosure-checks.d.ts +7 -0
  41. package/dist/expertise/tester/keyboard-disclosure-checks.d.ts.map +1 -0
  42. package/dist/expertise/tester/keyboard-disclosure-checks.js +46 -0
  43. package/dist/expertise/tester/keyboard-disclosure-checks.js.map +1 -0
  44. package/dist/expertise/tester/navigation-checks.d.ts +8 -0
  45. package/dist/expertise/tester/navigation-checks.d.ts.map +1 -0
  46. package/dist/expertise/tester/navigation-checks.js +64 -0
  47. package/dist/expertise/tester/navigation-checks.js.map +1 -0
  48. package/dist/expertise/tester/network-intent-checks.d.ts +7 -0
  49. package/dist/expertise/tester/network-intent-checks.d.ts.map +1 -0
  50. package/dist/expertise/tester/network-intent-checks.js +56 -0
  51. package/dist/expertise/tester/network-intent-checks.js.map +1 -0
  52. package/dist/expertise/tester/page-behavior-checks.d.ts +17 -0
  53. package/dist/expertise/tester/page-behavior-checks.d.ts.map +1 -0
  54. package/dist/expertise/tester/page-behavior-checks.js +144 -0
  55. package/dist/expertise/tester/page-behavior-checks.js.map +1 -0
  56. package/dist/expertise/tester/persistence-checks.d.ts +12 -0
  57. package/dist/expertise/tester/persistence-checks.d.ts.map +1 -0
  58. package/dist/expertise/tester/persistence-checks.js +109 -0
  59. package/dist/expertise/tester/persistence-checks.js.map +1 -0
  60. package/dist/expertise/tester/search-checks.d.ts +10 -0
  61. package/dist/expertise/tester/search-checks.d.ts.map +1 -0
  62. package/dist/expertise/tester/search-checks.js +111 -0
  63. package/dist/expertise/tester/search-checks.js.map +1 -0
  64. package/dist/expertise/tester/selection-control-checks.d.ts +7 -0
  65. package/dist/expertise/tester/selection-control-checks.d.ts.map +1 -0
  66. package/dist/expertise/tester/selection-control-checks.js +128 -0
  67. package/dist/expertise/tester/selection-control-checks.js.map +1 -0
  68. package/dist/expertise/tester/text-input-checks.d.ts +8 -0
  69. package/dist/expertise/tester/text-input-checks.d.ts.map +1 -0
  70. package/dist/expertise/tester/text-input-checks.js +194 -0
  71. package/dist/expertise/tester/text-input-checks.js.map +1 -0
  72. package/dist/expertise/tester/validation-checks.d.ts +10 -0
  73. package/dist/expertise/tester/validation-checks.d.ts.map +1 -0
  74. package/dist/expertise/tester/validation-checks.js +59 -0
  75. package/dist/expertise/tester/validation-checks.js.map +1 -0
  76. package/dist/expertise/tester-expertise.d.ts +0 -3
  77. package/dist/expertise/tester-expertise.d.ts.map +1 -1
  78. package/dist/expertise/tester-expertise.js +75 -49
  79. package/dist/expertise/tester-expertise.js.map +1 -1
  80. package/dist/expertise/types.d.ts +12 -1
  81. package/dist/expertise/types.d.ts.map +1 -1
  82. package/dist/extractors/form-extractor.d.ts +19 -0
  83. package/dist/extractors/form-extractor.d.ts.map +1 -1
  84. package/dist/extractors/form-extractor.js +271 -42
  85. package/dist/extractors/form-extractor.js.map +1 -1
  86. package/dist/orchestrator/test-element-executor.d.ts.map +1 -1
  87. package/dist/orchestrator/test-element-executor.js +74 -9
  88. package/dist/orchestrator/test-element-executor.js.map +1 -1
  89. 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,7 @@
1
+ import type { ExpertiseContext, Outcome } from "../types";
2
+ export declare function checkNetworkRequestMade(expectation: {
3
+ description: string;
4
+ expectedValue?: string;
5
+ expectedTextTokens?: string[];
6
+ }, context: ExpertiseContext): Outcome;
7
+ //# sourceMappingURL=network-intent-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-intent-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/network-intent-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,uBAAuB,CACrC,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA6CT"}
@@ -0,0 +1,56 @@
1
+ export function checkNetworkRequestMade(expectation, context) {
2
+ const methodExpectation = normalizeMethodExpectation(expectation.expectedValue);
3
+ const tokens = (expectation.expectedTextTokens ?? [])
4
+ .map(token => token.trim().toLowerCase())
5
+ .filter(Boolean);
6
+ const candidates = context.networkLogs.filter(log => {
7
+ const method = (log.method ?? "").toUpperCase();
8
+ const haystack = `${method} ${log.url}`.toLowerCase();
9
+ if (methodExpectation === "MUTATION" && !isMutationMethod(method)) {
10
+ return false;
11
+ }
12
+ if (methodExpectation !== "ANY" &&
13
+ methodExpectation !== "MUTATION" &&
14
+ method !== methodExpectation) {
15
+ return false;
16
+ }
17
+ if (tokens.length === 0) {
18
+ return true;
19
+ }
20
+ return tokens.some(token => haystack.includes(token));
21
+ });
22
+ if (candidates.length === 0) {
23
+ return {
24
+ expected: expectation.description,
25
+ observed: describeMissingRequest(methodExpectation, tokens),
26
+ result: "error",
27
+ };
28
+ }
29
+ const matched = candidates[0];
30
+ return {
31
+ expected: expectation.description,
32
+ observed: `Observed ${matched.method} ${matched.url} (${matched.status})`,
33
+ result: "pass",
34
+ };
35
+ }
36
+ function normalizeMethodExpectation(value) {
37
+ const normalized = (value ?? "ANY").trim().toUpperCase();
38
+ if (!normalized)
39
+ return "ANY";
40
+ if (normalized === "POST_OR_MUTATION")
41
+ return "MUTATION";
42
+ return normalized;
43
+ }
44
+ function isMutationMethod(method) {
45
+ return ["POST", "PUT", "PATCH", "DELETE"].includes(method);
46
+ }
47
+ function describeMissingRequest(methodExpectation, tokens) {
48
+ const methodDescription = methodExpectation === "ANY"
49
+ ? "network request"
50
+ : methodExpectation === "MUTATION"
51
+ ? "mutation request"
52
+ : `${methodExpectation} request`;
53
+ const tokenDescription = tokens.length > 0 ? ` matching [${tokens.join(", ")}]` : "";
54
+ return `No ${methodDescription}${tokenDescription} was observed`;
55
+ }
56
+ //# sourceMappingURL=network-intent-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-intent-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/network-intent-checks.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CACrC,WAIC,EACD,OAAyB;IAEzB,MAAM,iBAAiB,GAAG,0BAA0B,CAClD,WAAW,CAAC,aAAa,CAC1B,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,WAAW,CAAC,kBAAkB,IAAI,EAAE,CAAC;SAClD,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SACxC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;QAClD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QAEtD,IAAI,iBAAiB,KAAK,UAAU,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;YAClE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IACE,iBAAiB,KAAK,KAAK;YAC3B,iBAAiB,KAAK,UAAU;YAChC,MAAM,KAAK,iBAAiB,EAC5B,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,QAAQ,EAAE,WAAW,CAAC,WAAW;YACjC,QAAQ,EAAE,sBAAsB,CAAC,iBAAiB,EAAE,MAAM,CAAC;YAC3D,MAAM,EAAE,OAAO;SAChB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9B,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,WAAW;QACjC,QAAQ,EAAE,YAAY,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,MAAM,GAAG;QACzE,MAAM,EAAE,MAAM;KACf,CAAC;AACJ,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAc;IAChD,MAAM,UAAU,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACzD,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,UAAU,KAAK,kBAAkB;QAAE,OAAO,UAAU,CAAC;IACzD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAc;IACtC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,sBAAsB,CAC7B,iBAAyB,EACzB,MAAgB;IAEhB,MAAM,iBAAiB,GACrB,iBAAiB,KAAK,KAAK;QACzB,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,iBAAiB,KAAK,UAAU;YAChC,CAAC,CAAC,kBAAkB;YACpB,CAAC,CAAC,GAAG,iBAAiB,UAAU,CAAC;IACvC,MAAM,gBAAgB,GACpB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9D,OAAO,MAAM,iBAAiB,GAAG,gBAAgB,eAAe,CAAC;AACnE,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,10 @@
1
+ import type { ExpertiseContext, Outcome } from "../types";
2
+ export declare function checkResultsChanged(expectation: {
3
+ description: string;
4
+ expectedTextTokens?: string[];
5
+ }, context: ExpertiseContext): Outcome;
6
+ export declare function checkEmptyStateVisible(expectation: {
7
+ description: string;
8
+ expectedTextTokens?: string[];
9
+ }, context: ExpertiseContext): Outcome;
10
+ //# sourceMappingURL=search-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-checks.d.ts","sourceRoot":"","sources":["../../../src/expertise/tester/search-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAuDT;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,EACD,OAAO,EAAE,gBAAgB,GACxB,OAAO,CA8BT"}
@@ -0,0 +1,111 @@
1
+ export function checkResultsChanged(expectation, context) {
2
+ const tokens = expectation.expectedTextTokens?.length
3
+ ? expectation.expectedTextTokens
4
+ : ["results", "products", "items", "matches", "showing", "search"];
5
+ const initialSummary = extractRelevantSummary(context.initialHtml, tokens);
6
+ const finalSummary = extractRelevantSummary(context.html, tokens);
7
+ if (initialSummary && finalSummary) {
8
+ if (normalizeText(initialSummary) === normalizeText(finalSummary)) {
9
+ return {
10
+ expected: expectation.description,
11
+ observed: "Results-like summary text did not change after the action",
12
+ result: "error",
13
+ };
14
+ }
15
+ return {
16
+ expected: expectation.description,
17
+ observed: "Results-like summary text changed after the action",
18
+ result: "pass",
19
+ };
20
+ }
21
+ const initialSignature = extractCollectionSignature(context.initialHtml);
22
+ const finalSignature = extractCollectionSignature(context.html);
23
+ if (initialSignature &&
24
+ finalSignature &&
25
+ initialSignature !== finalSignature) {
26
+ return {
27
+ expected: expectation.description,
28
+ observed: "Visible result ordering or composition changed after the action",
29
+ result: "pass",
30
+ };
31
+ }
32
+ if (context.initialUrl &&
33
+ context.currentUrl &&
34
+ context.initialUrl !== context.currentUrl) {
35
+ return {
36
+ expected: expectation.description,
37
+ observed: `URL changed from ${context.initialUrl} to ${context.currentUrl}`,
38
+ result: "pass",
39
+ };
40
+ }
41
+ return {
42
+ expected: expectation.description,
43
+ observed: "Could not detect a meaningful result-state change",
44
+ result: "error",
45
+ };
46
+ }
47
+ export function checkEmptyStateVisible(expectation, context) {
48
+ const text = stripHtml(context.html).toLowerCase();
49
+ const tokens = expectation.expectedTextTokens?.length
50
+ ? expectation.expectedTextTokens.map(token => token.toLowerCase())
51
+ : [
52
+ "no results",
53
+ "0 results",
54
+ "no matches",
55
+ "nothing found",
56
+ "did not match",
57
+ "try a different search",
58
+ "search returned no",
59
+ "no products found",
60
+ "no items found",
61
+ ];
62
+ const matched = tokens.find(token => text.includes(token));
63
+ if (matched) {
64
+ return {
65
+ expected: expectation.description,
66
+ observed: `Visible empty-state text detected: ${matched}`,
67
+ result: "pass",
68
+ };
69
+ }
70
+ return {
71
+ expected: expectation.description,
72
+ observed: "No visible empty-state text was detected after the search",
73
+ result: "error",
74
+ };
75
+ }
76
+ function extractRelevantSummary(html, tokens) {
77
+ const text = stripHtml(html);
78
+ const lower = text.toLowerCase();
79
+ for (const token of tokens) {
80
+ const index = lower.indexOf(token.toLowerCase());
81
+ if (index < 0)
82
+ continue;
83
+ return text.slice(Math.max(0, index - 40), Math.min(text.length, index + 120));
84
+ }
85
+ return null;
86
+ }
87
+ function stripHtml(html) {
88
+ return html
89
+ .replace(/<script[\s\S]*?<\/script>/gi, " ")
90
+ .replace(/<style[\s\S]*?<\/style>/gi, " ")
91
+ .replace(/<[^>]+>/g, " ")
92
+ .replace(/\s+/g, " ")
93
+ .trim();
94
+ }
95
+ function normalizeText(value) {
96
+ return value.replace(/\s+/g, " ").trim().toLowerCase();
97
+ }
98
+ function extractCollectionSignature(html) {
99
+ const normalized = html.replace(/\s+/g, " ");
100
+ const matches = Array.from(normalized.matchAll(/<(?:h[1-6]|a|button|li|option)\b[^>]*>(.*?)<\/(?:h[1-6]|a|button|li|option)>/gi))
101
+ .map(match => match[1]
102
+ .replace(/<[^>]+>/g, " ")
103
+ .replace(/\s+/g, " ")
104
+ .trim())
105
+ .filter(text => text.length >= 3 && text.length <= 80);
106
+ const unique = Array.from(new Set(matches));
107
+ if (unique.length < 3)
108
+ return null;
109
+ return unique.slice(0, 8).join(" | ").toLowerCase();
110
+ }
111
+ //# sourceMappingURL=search-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-checks.js","sourceRoot":"","sources":["../../../src/expertise/tester/search-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"}