@sudobility/testomniac_runner_service 0.1.24
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/CLAUDE.md +338 -0
- package/README.md +15 -0
- package/dist/adapter.d.ts +56 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +1 -0
- package/dist/adapter.js.map +1 -0
- package/dist/ai/analyzer.d.ts +16 -0
- package/dist/ai/analyzer.d.ts.map +1 -0
- package/dist/ai/analyzer.js +55 -0
- package/dist/ai/analyzer.js.map +1 -0
- package/dist/ai/input-generator.d.ts +9 -0
- package/dist/ai/input-generator.d.ts.map +1 -0
- package/dist/ai/input-generator.js +20 -0
- package/dist/ai/input-generator.js.map +1 -0
- package/dist/ai/persona-generator.d.ts +7 -0
- package/dist/ai/persona-generator.d.ts.map +1 -0
- package/dist/ai/persona-generator.js +23 -0
- package/dist/ai/persona-generator.js.map +1 -0
- package/dist/ai/use-case-generator.d.ts +7 -0
- package/dist/ai/use-case-generator.d.ts.map +1 -0
- package/dist/ai/use-case-generator.js +23 -0
- package/dist/ai/use-case-generator.js.map +1 -0
- package/dist/api/client.d.ts +69 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +327 -0
- package/dist/api/client.js.map +1 -0
- package/dist/browser/dom-snapshot.d.ts +4 -0
- package/dist/browser/dom-snapshot.d.ts.map +1 -0
- package/dist/browser/dom-snapshot.js +382 -0
- package/dist/browser/dom-snapshot.js.map +1 -0
- package/dist/browser/page-utils.d.ts +9 -0
- package/dist/browser/page-utils.d.ts.map +1 -0
- package/dist/browser/page-utils.js +63 -0
- package/dist/browser/page-utils.js.map +1 -0
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +99 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/detectors/action-description.d.ts +4 -0
- package/dist/detectors/action-description.d.ts.map +1 -0
- package/dist/detectors/action-description.js +25 -0
- package/dist/detectors/action-description.js.map +1 -0
- package/dist/detectors/bug-detector.d.ts +23 -0
- package/dist/detectors/bug-detector.d.ts.map +1 -0
- package/dist/detectors/bug-detector.js +214 -0
- package/dist/detectors/bug-detector.js.map +1 -0
- package/dist/detectors/content-checker.d.ts +10 -0
- package/dist/detectors/content-checker.d.ts.map +1 -0
- package/dist/detectors/content-checker.js +76 -0
- package/dist/detectors/content-checker.js.map +1 -0
- package/dist/detectors/detection-rule.d.ts +28 -0
- package/dist/detectors/detection-rule.d.ts.map +1 -0
- package/dist/detectors/detection-rule.js +1 -0
- package/dist/detectors/detection-rule.js.map +1 -0
- package/dist/detectors/functional-checker.d.ts +22 -0
- package/dist/detectors/functional-checker.d.ts.map +1 -0
- package/dist/detectors/functional-checker.js +88 -0
- package/dist/detectors/functional-checker.js.map +1 -0
- package/dist/detectors/index.d.ts +10 -0
- package/dist/detectors/index.d.ts.map +1 -0
- package/dist/detectors/index.js +9 -0
- package/dist/detectors/index.js.map +1 -0
- package/dist/detectors/link-checker.d.ts +24 -0
- package/dist/detectors/link-checker.d.ts.map +1 -0
- package/dist/detectors/link-checker.js +85 -0
- package/dist/detectors/link-checker.js.map +1 -0
- package/dist/detectors/modal-handler.d.ts +7 -0
- package/dist/detectors/modal-handler.d.ts.map +1 -0
- package/dist/detectors/modal-handler.js +60 -0
- package/dist/detectors/modal-handler.js.map +1 -0
- package/dist/detectors/rules/blank-page-rule.d.ts +3 -0
- package/dist/detectors/rules/blank-page-rule.d.ts.map +1 -0
- package/dist/detectors/rules/blank-page-rule.js +21 -0
- package/dist/detectors/rules/blank-page-rule.js.map +1 -0
- package/dist/detectors/rules/broken-image-rule.d.ts +3 -0
- package/dist/detectors/rules/broken-image-rule.d.ts.map +1 -0
- package/dist/detectors/rules/broken-image-rule.js +34 -0
- package/dist/detectors/rules/broken-image-rule.js.map +1 -0
- package/dist/detectors/rules/broken-link-rule.d.ts +3 -0
- package/dist/detectors/rules/broken-link-rule.d.ts.map +1 -0
- package/dist/detectors/rules/broken-link-rule.js +55 -0
- package/dist/detectors/rules/broken-link-rule.js.map +1 -0
- package/dist/detectors/rules/broken-media-rule.d.ts +3 -0
- package/dist/detectors/rules/broken-media-rule.d.ts.map +1 -0
- package/dist/detectors/rules/broken-media-rule.js +46 -0
- package/dist/detectors/rules/broken-media-rule.js.map +1 -0
- package/dist/detectors/rules/console-error-rule.d.ts +3 -0
- package/dist/detectors/rules/console-error-rule.d.ts.map +1 -0
- package/dist/detectors/rules/console-error-rule.js +9 -0
- package/dist/detectors/rules/console-error-rule.js.map +1 -0
- package/dist/detectors/rules/dead-click-rule.d.ts +3 -0
- package/dist/detectors/rules/dead-click-rule.d.ts.map +1 -0
- package/dist/detectors/rules/dead-click-rule.js +9 -0
- package/dist/detectors/rules/dead-click-rule.js.map +1 -0
- package/dist/detectors/rules/duplicate-heading-rule.d.ts +3 -0
- package/dist/detectors/rules/duplicate-heading-rule.d.ts.map +1 -0
- package/dist/detectors/rules/duplicate-heading-rule.js +35 -0
- package/dist/detectors/rules/duplicate-heading-rule.js.map +1 -0
- package/dist/detectors/rules/duplicate-id-rule.d.ts +3 -0
- package/dist/detectors/rules/duplicate-id-rule.d.ts.map +1 -0
- package/dist/detectors/rules/duplicate-id-rule.js +33 -0
- package/dist/detectors/rules/duplicate-id-rule.js.map +1 -0
- package/dist/detectors/rules/empty-link-rule.d.ts +3 -0
- package/dist/detectors/rules/empty-link-rule.d.ts.map +1 -0
- package/dist/detectors/rules/empty-link-rule.js +35 -0
- package/dist/detectors/rules/empty-link-rule.js.map +1 -0
- package/dist/detectors/rules/error-page-rule.d.ts +3 -0
- package/dist/detectors/rules/error-page-rule.d.ts.map +1 -0
- package/dist/detectors/rules/error-page-rule.js +40 -0
- package/dist/detectors/rules/error-page-rule.js.map +1 -0
- package/dist/detectors/rules/index.d.ts +16 -0
- package/dist/detectors/rules/index.d.ts.map +1 -0
- package/dist/detectors/rules/index.js +32 -0
- package/dist/detectors/rules/index.js.map +1 -0
- package/dist/detectors/rules/network-error-rule.d.ts +3 -0
- package/dist/detectors/rules/network-error-rule.d.ts.map +1 -0
- package/dist/detectors/rules/network-error-rule.js +9 -0
- package/dist/detectors/rules/network-error-rule.js.map +1 -0
- package/dist/detectors/rules/placeholder-text-rule.d.ts +3 -0
- package/dist/detectors/rules/placeholder-text-rule.d.ts.map +1 -0
- package/dist/detectors/rules/placeholder-text-rule.js +34 -0
- package/dist/detectors/rules/placeholder-text-rule.js.map +1 -0
- package/dist/detectors/visual-checker.d.ts +11 -0
- package/dist/detectors/visual-checker.d.ts.map +1 -0
- package/dist/detectors/visual-checker.js +78 -0
- package/dist/detectors/visual-checker.js.map +1 -0
- package/dist/domain/types.d.ts +3 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +3 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/url-ownership.d.ts +7 -0
- package/dist/domain/url-ownership.d.ts.map +1 -0
- package/dist/domain/url-ownership.js +49 -0
- package/dist/domain/url-ownership.js.map +1 -0
- package/dist/extractors/buttons.d.ts +3 -0
- package/dist/extractors/buttons.d.ts.map +1 -0
- package/dist/extractors/buttons.js +30 -0
- package/dist/extractors/buttons.js.map +1 -0
- package/dist/extractors/clickables.d.ts +3 -0
- package/dist/extractors/clickables.d.ts.map +1 -0
- package/dist/extractors/clickables.js +35 -0
- package/dist/extractors/clickables.js.map +1 -0
- package/dist/extractors/form-extractor.d.ts +4 -0
- package/dist/extractors/form-extractor.d.ts.map +1 -0
- package/dist/extractors/form-extractor.js +47 -0
- package/dist/extractors/form-extractor.js.map +1 -0
- package/dist/extractors/helpers.d.ts +7 -0
- package/dist/extractors/helpers.d.ts.map +1 -0
- package/dist/extractors/helpers.js +43 -0
- package/dist/extractors/helpers.js.map +1 -0
- package/dist/extractors/index.d.ts +5 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +25 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/product-actions.d.ts +3 -0
- package/dist/extractors/product-actions.d.ts.map +1 -0
- package/dist/extractors/product-actions.js +23 -0
- package/dist/extractors/product-actions.js.map +1 -0
- package/dist/extractors/selectors.d.ts +3 -0
- package/dist/extractors/selectors.d.ts.map +1 -0
- package/dist/extractors/selectors.js +42 -0
- package/dist/extractors/selectors.js.map +1 -0
- package/dist/extractors/selects.d.ts +3 -0
- package/dist/extractors/selects.d.ts.map +1 -0
- package/dist/extractors/selects.js +13 -0
- package/dist/extractors/selects.js.map +1 -0
- package/dist/extractors/text-inputs.d.ts +3 -0
- package/dist/extractors/text-inputs.d.ts.map +1 -0
- package/dist/extractors/text-inputs.js +35 -0
- package/dist/extractors/text-inputs.js.map +1 -0
- package/dist/extractors/toggles.d.ts +3 -0
- package/dist/extractors/toggles.d.ts.map +1 -0
- package/dist/extractors/toggles.js +14 -0
- package/dist/extractors/toggles.js.map +1 -0
- package/dist/extractors/types.d.ts +36 -0
- package/dist/extractors/types.d.ts.map +1 -0
- package/dist/extractors/types.js +1 -0
- package/dist/extractors/types.js.map +1 -0
- package/dist/generation/e2e.d.ts +15 -0
- package/dist/generation/e2e.d.ts.map +1 -0
- package/dist/generation/e2e.js +59 -0
- package/dist/generation/e2e.js.map +1 -0
- package/dist/generation/form-negative.d.ts +14 -0
- package/dist/generation/form-negative.d.ts.map +1 -0
- package/dist/generation/form-negative.js +36 -0
- package/dist/generation/form-negative.js.map +1 -0
- package/dist/generation/form.d.ts +23 -0
- package/dist/generation/form.d.ts.map +1 -0
- package/dist/generation/form.js +48 -0
- package/dist/generation/form.js.map +1 -0
- package/dist/generation/generator.d.ts +13 -0
- package/dist/generation/generator.d.ts.map +1 -0
- package/dist/generation/generator.js +38 -0
- package/dist/generation/generator.js.map +1 -0
- package/dist/generation/interaction.d.ts +14 -0
- package/dist/generation/interaction.d.ts.map +1 -0
- package/dist/generation/interaction.js +26 -0
- package/dist/generation/interaction.js.map +1 -0
- package/dist/generation/navigation.d.ts +14 -0
- package/dist/generation/navigation.d.ts.map +1 -0
- package/dist/generation/navigation.js +21 -0
- package/dist/generation/navigation.js.map +1 -0
- package/dist/generation/password.d.ts +20 -0
- package/dist/generation/password.d.ts.map +1 -0
- package/dist/generation/password.js +45 -0
- package/dist/generation/password.js.map +1 -0
- package/dist/generation/playwright-export.d.ts +3 -0
- package/dist/generation/playwright-export.d.ts.map +1 -0
- package/dist/generation/playwright-export.js +22 -0
- package/dist/generation/playwright-export.js.map +1 -0
- package/dist/generation/render.d.ts +29 -0
- package/dist/generation/render.d.ts.map +1 -0
- package/dist/generation/render.js +94 -0
- package/dist/generation/render.js.map +1 -0
- package/dist/generation/suite-tagger.d.ts +4 -0
- package/dist/generation/suite-tagger.d.ts.map +1 -0
- package/dist/generation/suite-tagger.js +20 -0
- package/dist/generation/suite-tagger.js.map +1 -0
- package/dist/identity/element-matcher.d.ts +23 -0
- package/dist/identity/element-matcher.d.ts.map +1 -0
- package/dist/identity/element-matcher.js +60 -0
- package/dist/identity/element-matcher.js.map +1 -0
- package/dist/identity/identity-cache.d.ts +12 -0
- package/dist/identity/identity-cache.d.ts.map +1 -0
- package/dist/identity/identity-cache.js +25 -0
- package/dist/identity/identity-cache.js.map +1 -0
- package/dist/identity/playwright-locator.d.ts +4 -0
- package/dist/identity/playwright-locator.d.ts.map +1 -0
- package/dist/identity/playwright-locator.js +67 -0
- package/dist/identity/playwright-locator.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/decomposition.d.ts +6 -0
- package/dist/orchestrator/decomposition.d.ts.map +1 -0
- package/dist/orchestrator/decomposition.js +55 -0
- package/dist/orchestrator/decomposition.js.map +1 -0
- package/dist/orchestrator/orchestrator.d.ts +5 -0
- package/dist/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator.js +122 -0
- package/dist/orchestrator/orchestrator.js.map +1 -0
- package/dist/orchestrator/test-execution.d.ts +5 -0
- package/dist/orchestrator/test-execution.d.ts.map +1 -0
- package/dist/orchestrator/test-execution.js +205 -0
- package/dist/orchestrator/test-execution.js.map +1 -0
- package/dist/orchestrator/types.d.ts +69 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/orchestrator/types.js +1 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/planners/fill-value-planner.d.ts +9 -0
- package/dist/planners/fill-value-planner.d.ts.map +1 -0
- package/dist/planners/fill-value-planner.js +166 -0
- package/dist/planners/fill-value-planner.js.map +1 -0
- package/dist/plugins/registry.d.ts +6 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +16 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +42 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +1 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/scanner/action-classifier.d.ts +7 -0
- package/dist/scanner/action-classifier.d.ts.map +1 -0
- package/dist/scanner/action-classifier.js +64 -0
- package/dist/scanner/action-classifier.js.map +1 -0
- package/dist/scanner/action-queue.d.ts +18 -0
- package/dist/scanner/action-queue.d.ts.map +1 -0
- package/dist/scanner/action-queue.js +20 -0
- package/dist/scanner/action-queue.js.map +1 -0
- package/dist/scanner/component-detector.d.ts +43 -0
- package/dist/scanner/component-detector.d.ts.map +1 -0
- package/dist/scanner/component-detector.js +231 -0
- package/dist/scanner/component-detector.js.map +1 -0
- package/dist/scanner/email-detector.d.ts +3 -0
- package/dist/scanner/email-detector.d.ts.map +1 -0
- package/dist/scanner/email-detector.js +12 -0
- package/dist/scanner/email-detector.js.map +1 -0
- package/dist/scanner/html-decomposer.d.ts +19 -0
- package/dist/scanner/html-decomposer.d.ts.map +1 -0
- package/dist/scanner/html-decomposer.js +41 -0
- package/dist/scanner/html-decomposer.js.map +1 -0
- package/dist/scanner/issue-detector.d.ts +8 -0
- package/dist/scanner/issue-detector.d.ts.map +1 -0
- package/dist/scanner/issue-detector.js +71 -0
- package/dist/scanner/issue-detector.js.map +1 -0
- package/dist/scanner/loop-guard.d.ts +18 -0
- package/dist/scanner/loop-guard.d.ts.map +1 -0
- package/dist/scanner/loop-guard.js +33 -0
- package/dist/scanner/loop-guard.js.map +1 -0
- package/dist/scanner/navigator.d.ts +25 -0
- package/dist/scanner/navigator.d.ts.map +1 -0
- package/dist/scanner/navigator.js +56 -0
- package/dist/scanner/navigator.js.map +1 -0
- package/dist/scanner/page-cache.d.ts +22 -0
- package/dist/scanner/page-cache.d.ts.map +1 -0
- package/dist/scanner/page-cache.js +42 -0
- package/dist/scanner/page-cache.js.map +1 -0
- package/dist/scanner/pairwise.d.ts +7 -0
- package/dist/scanner/pairwise.d.ts.map +1 -0
- package/dist/scanner/pairwise.js +64 -0
- package/dist/scanner/pairwise.js.map +1 -0
- package/dist/scanner/pattern-detector.d.ts +22 -0
- package/dist/scanner/pattern-detector.d.ts.map +1 -0
- package/dist/scanner/pattern-detector.js +108 -0
- package/dist/scanner/pattern-detector.js.map +1 -0
- package/dist/scanner/phase-timer.d.ts +9 -0
- package/dist/scanner/phase-timer.d.ts.map +1 -0
- package/dist/scanner/phase-timer.js +27 -0
- package/dist/scanner/phase-timer.js.map +1 -0
- package/dist/scanner/reusable-element-cache.d.ts +13 -0
- package/dist/scanner/reusable-element-cache.d.ts.map +1 -0
- package/dist/scanner/reusable-element-cache.js +37 -0
- package/dist/scanner/reusable-element-cache.js.map +1 -0
- package/dist/scanner/scroll-scanner.d.ts +3 -0
- package/dist/scanner/scroll-scanner.d.ts.map +1 -0
- package/dist/scanner/scroll-scanner.js +19 -0
- package/dist/scanner/scroll-scanner.js.map +1 -0
- package/dist/scanner/state-manager.d.ts +11 -0
- package/dist/scanner/state-manager.d.ts.map +1 -0
- package/dist/scanner/state-manager.js +24 -0
- package/dist/scanner/state-manager.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function describeAction(action, elementName) {
|
|
2
|
+
const name = elementName ?? "element";
|
|
3
|
+
switch (action.type) {
|
|
4
|
+
case "navigate":
|
|
5
|
+
return `Navigate to ${action.targetUrl ?? "page"}`;
|
|
6
|
+
case "hover":
|
|
7
|
+
return `Move mouse over ${name}`;
|
|
8
|
+
case "click":
|
|
9
|
+
return `Click ${name}`;
|
|
10
|
+
case "fill":
|
|
11
|
+
return `Enter '${action.inputValue ?? ""}' into ${name}`;
|
|
12
|
+
case "select":
|
|
13
|
+
return `Select option in ${name}`;
|
|
14
|
+
case "radio_select":
|
|
15
|
+
return `Select radio button ${name}`;
|
|
16
|
+
default:
|
|
17
|
+
return `${action.type} on ${name}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function buildTestCaseDescription(actions, elementNames) {
|
|
21
|
+
return actions
|
|
22
|
+
.map((a, i) => `${i + 1}. ${describeAction(a, elementNames?.get(a.actionableItemId ?? 0))}`)
|
|
23
|
+
.join("\n");
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=action-description.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-description.js","sourceRoot":"","sources":["../../src/detectors/action-description.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAC5B,MAAgC,EAChC,WAAoB;IAEpB,MAAM,IAAI,GAAG,WAAW,IAAI,SAAS,CAAC;IACtC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,UAAU;YACb,OAAO,eAAe,MAAM,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;QACrD,KAAK,OAAO;YACV,OAAO,mBAAmB,IAAI,EAAE,CAAC;QACnC,KAAK,OAAO;YACV,OAAO,SAAS,IAAI,EAAE,CAAC;QACzB,KAAK,MAAM;YACT,OAAO,UAAU,MAAM,CAAC,UAAU,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC;QAC3D,KAAK,QAAQ;YACX,OAAO,oBAAoB,IAAI,EAAE,CAAC;QACpC,KAAK,cAAc;YACjB,OAAO,uBAAuB,IAAI,EAAE,CAAC;QACvC;YACE,OAAO,GAAG,MAAM,CAAC,IAAI,OAAO,IAAI,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,OAAmC,EACnC,YAAkC;IAElC,OAAO,OAAO;SACX,GAAG,CACF,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,GAAG,CAAC,GAAG,CAAC,KAAK,cAAc,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,CAC/E;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BrowserAdapter } from "../adapter";
|
|
2
|
+
export interface BrokenLinkResult {
|
|
3
|
+
href: string;
|
|
4
|
+
text: string;
|
|
5
|
+
error: string;
|
|
6
|
+
}
|
|
7
|
+
export interface VisualIssue {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ContentIssue {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MediaIssue {
|
|
16
|
+
type: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function detectBrokenLinks(adapter: BrowserAdapter, pageUrl: string): Promise<BrokenLinkResult[]>;
|
|
20
|
+
export declare function detectVisualIssues(html: string): VisualIssue[];
|
|
21
|
+
export declare function detectContentIssues(text: string): ContentIssue[];
|
|
22
|
+
export declare function detectMediaIssues(adapter: BrowserAdapter): Promise<MediaIssue[]>;
|
|
23
|
+
//# sourceMappingURL=bug-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-detector.d.ts","sourceRoot":"","sources":["../../src/detectors/bug-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2C7B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAuF9D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CA2DhE;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,EAAE,CAAC,CAqCvB"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
export async function detectBrokenLinks(adapter, pageUrl) {
|
|
2
|
+
const origin = new URL(pageUrl).origin;
|
|
3
|
+
const links = (await adapter.evaluate((...args) => {
|
|
4
|
+
const orig = args[0];
|
|
5
|
+
const anchors = document.querySelectorAll("a[href]");
|
|
6
|
+
const results = [];
|
|
7
|
+
anchors.forEach(a => {
|
|
8
|
+
const href = a.href;
|
|
9
|
+
const text = a.textContent?.trim().slice(0, 80) || "";
|
|
10
|
+
try {
|
|
11
|
+
if (new URL(href).origin === orig) {
|
|
12
|
+
results.push({ href, text });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Invalid URL, skip
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return results;
|
|
20
|
+
}, origin));
|
|
21
|
+
if (!links || links.length === 0)
|
|
22
|
+
return [];
|
|
23
|
+
const uniqueLinks = new Map();
|
|
24
|
+
for (const link of links) {
|
|
25
|
+
if (!uniqueLinks.has(link.href)) {
|
|
26
|
+
uniqueLinks.set(link.href, link.text);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const broken = [];
|
|
30
|
+
for (const [href, text] of uniqueLinks) {
|
|
31
|
+
try {
|
|
32
|
+
const resp = await fetch(href, { method: "HEAD", redirect: "manual" });
|
|
33
|
+
if (resp.status === 404 || resp.status === 410 || resp.status >= 500) {
|
|
34
|
+
broken.push({ href, text, error: `HTTP ${resp.status}` });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Unreachable/CSP-blocked, skip
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return broken;
|
|
42
|
+
}
|
|
43
|
+
export function detectVisualIssues(html) {
|
|
44
|
+
const issues = [];
|
|
45
|
+
const headingRegex = /<(h[1-6])[^>]*>([\s\S]*?)<\/\1>/gi;
|
|
46
|
+
const headingTexts = new Map();
|
|
47
|
+
let headingMatch;
|
|
48
|
+
while ((headingMatch = headingRegex.exec(html)) !== null) {
|
|
49
|
+
const text = headingMatch[2]
|
|
50
|
+
.replace(/<[^>]+>/g, "")
|
|
51
|
+
.replace(/\s+/g, " ")
|
|
52
|
+
.trim()
|
|
53
|
+
.toLowerCase();
|
|
54
|
+
if (text) {
|
|
55
|
+
headingTexts.set(text, (headingTexts.get(text) || 0) + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const [text, count] of headingTexts) {
|
|
59
|
+
if (count > 1) {
|
|
60
|
+
issues.push({
|
|
61
|
+
type: "duplicate_heading",
|
|
62
|
+
description: `Heading "${text.slice(0, 60)}" appears ${count} times`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const linkRegex = /<a\s[^>]*>([\s\S]*?)<\/a>/gi;
|
|
67
|
+
let linkMatch;
|
|
68
|
+
let emptyLinkCount = 0;
|
|
69
|
+
while ((linkMatch = linkRegex.exec(html)) !== null) {
|
|
70
|
+
const innerText = linkMatch[1]
|
|
71
|
+
.replace(/<[^>]+>/g, "")
|
|
72
|
+
.replace(/\s+/g, "")
|
|
73
|
+
.trim();
|
|
74
|
+
const hasImg = /<img\s[^>]*alt\s*=\s*"[^"]+"/i.test(linkMatch[1]);
|
|
75
|
+
const hasAriaLabel = /aria-label\s*=\s*"[^"]+"/i.test(linkMatch[0]);
|
|
76
|
+
if (!innerText && !hasImg && !hasAriaLabel) {
|
|
77
|
+
emptyLinkCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (emptyLinkCount > 0) {
|
|
81
|
+
issues.push({
|
|
82
|
+
type: "empty_link",
|
|
83
|
+
description: `${emptyLinkCount} link(s) with no accessible text content`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const imgRegex = /<img\s([^>]*)>/gi;
|
|
87
|
+
let imgMatch;
|
|
88
|
+
let brokenImgCount = 0;
|
|
89
|
+
while ((imgMatch = imgRegex.exec(html)) !== null) {
|
|
90
|
+
const attrs = imgMatch[1];
|
|
91
|
+
const srcMatch = /src\s*=\s*"([^"]*)"/i.exec(attrs);
|
|
92
|
+
if (!srcMatch ||
|
|
93
|
+
!srcMatch[1] ||
|
|
94
|
+
srcMatch[1].trim() === "" ||
|
|
95
|
+
srcMatch[1] === "#") {
|
|
96
|
+
brokenImgCount++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (brokenImgCount > 0) {
|
|
100
|
+
issues.push({
|
|
101
|
+
type: "broken_image",
|
|
102
|
+
description: `${brokenImgCount} image(s) with empty or invalid src`,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const idRegex = /\sid\s*=\s*"([^"]+)"/gi;
|
|
106
|
+
const idCounts = new Map();
|
|
107
|
+
let idMatch;
|
|
108
|
+
while ((idMatch = idRegex.exec(html)) !== null) {
|
|
109
|
+
const id = idMatch[1];
|
|
110
|
+
idCounts.set(id, (idCounts.get(id) || 0) + 1);
|
|
111
|
+
}
|
|
112
|
+
const duplicateIds = [];
|
|
113
|
+
for (const [id, count] of idCounts) {
|
|
114
|
+
if (count > 1)
|
|
115
|
+
duplicateIds.push(id);
|
|
116
|
+
}
|
|
117
|
+
if (duplicateIds.length > 0) {
|
|
118
|
+
issues.push({
|
|
119
|
+
type: "duplicate_id",
|
|
120
|
+
description: `${duplicateIds.length} duplicate element ID(s): ${duplicateIds.slice(0, 5).join(", ")}${duplicateIds.length > 5 ? "..." : ""}`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return issues;
|
|
124
|
+
}
|
|
125
|
+
export function detectContentIssues(text) {
|
|
126
|
+
const issues = [];
|
|
127
|
+
const placeholderPatterns = [
|
|
128
|
+
/lorem ipsum/i,
|
|
129
|
+
/dolor sit amet/i,
|
|
130
|
+
/placeholder text/i,
|
|
131
|
+
/todo[:\s]/i,
|
|
132
|
+
/fixme[:\s]/i,
|
|
133
|
+
/your (?:name|email|text) here/i,
|
|
134
|
+
/example\.com/i,
|
|
135
|
+
/test@test/i,
|
|
136
|
+
/foo\s*bar/i,
|
|
137
|
+
];
|
|
138
|
+
for (const pattern of placeholderPatterns) {
|
|
139
|
+
if (pattern.test(text)) {
|
|
140
|
+
issues.push({
|
|
141
|
+
type: "placeholder_text",
|
|
142
|
+
description: `Placeholder text detected: matches "${pattern.source}"`,
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const errorPatterns = [
|
|
148
|
+
{ pattern: /404\s*(not found|error|page)/i, label: "404 Not Found" },
|
|
149
|
+
{ pattern: /500\s*(internal|server|error)/i, label: "500 Server Error" },
|
|
150
|
+
{
|
|
151
|
+
pattern: /503\s*(service|unavailable)/i,
|
|
152
|
+
label: "503 Service Unavailable",
|
|
153
|
+
},
|
|
154
|
+
{ pattern: /502\s*(bad gateway)/i, label: "502 Bad Gateway" },
|
|
155
|
+
{ pattern: /page\s*not\s*found/i, label: "Page Not Found" },
|
|
156
|
+
{ pattern: /server\s*error/i, label: "Server Error" },
|
|
157
|
+
{ pattern: /internal\s*server\s*error/i, label: "Internal Server Error" },
|
|
158
|
+
{ pattern: /access\s*denied/i, label: "Access Denied" },
|
|
159
|
+
{ pattern: /403\s*forbidden/i, label: "403 Forbidden" },
|
|
160
|
+
{ pattern: /something\s*went\s*wrong/i, label: "Something Went Wrong" },
|
|
161
|
+
{ pattern: /an?\s*error\s*(has\s*)?occurred/i, label: "Error Occurred" },
|
|
162
|
+
{ pattern: /application\s*error/i, label: "Application Error" },
|
|
163
|
+
];
|
|
164
|
+
for (const { pattern, label } of errorPatterns) {
|
|
165
|
+
if (pattern.test(text)) {
|
|
166
|
+
issues.push({
|
|
167
|
+
type: "error_page",
|
|
168
|
+
description: `Error page detected: ${label}`,
|
|
169
|
+
});
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (text.trim().length < 50) {
|
|
174
|
+
issues.push({
|
|
175
|
+
type: "blank_page",
|
|
176
|
+
description: `Page appears blank or nearly empty (${text.trim().length} characters)`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return issues;
|
|
180
|
+
}
|
|
181
|
+
export async function detectMediaIssues(adapter) {
|
|
182
|
+
const issues = (await adapter.evaluate(() => {
|
|
183
|
+
const results = [];
|
|
184
|
+
const media = document.querySelectorAll("video, audio");
|
|
185
|
+
media.forEach((element, index) => {
|
|
186
|
+
const mediaEl = element;
|
|
187
|
+
const tag = element.tagName.toLowerCase();
|
|
188
|
+
const hasSource = Boolean(mediaEl.getAttribute("src")) ||
|
|
189
|
+
element.querySelector("source[src]") !== null;
|
|
190
|
+
if (!hasSource) {
|
|
191
|
+
results.push({
|
|
192
|
+
type: "missing_media_source",
|
|
193
|
+
description: `${tag} #${index + 1} has no source`,
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (mediaEl.error) {
|
|
198
|
+
results.push({
|
|
199
|
+
type: "broken_media",
|
|
200
|
+
description: `${tag} #${index + 1} has media error code ${mediaEl.error.code}`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
else if (mediaEl.networkState === HTMLMediaElement.NETWORK_NO_SOURCE) {
|
|
204
|
+
results.push({
|
|
205
|
+
type: "broken_media",
|
|
206
|
+
description: `${tag} #${index + 1} has no playable source`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
return results;
|
|
211
|
+
}));
|
|
212
|
+
return issues;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=bug-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-detector.js","sourceRoot":"","sources":["../../src/detectors/bug-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ContentIssue {
|
|
2
|
+
type: string;
|
|
3
|
+
description: string;
|
|
4
|
+
severity: "error" | "warning" | "info";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Check visible text for content issues.
|
|
8
|
+
*/
|
|
9
|
+
export declare function checkContentIssues(visibleText: string, _html: string): ContentIssue[];
|
|
10
|
+
//# sourceMappingURL=content-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-checker.d.ts","sourceRoot":"","sources":["../../src/detectors/content-checker.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAkBD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,YAAY,EAAE,CA6DhB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const PLACEHOLDER_PATTERNS = [
|
|
2
|
+
/lorem ipsum/i,
|
|
3
|
+
/dolor sit amet/i,
|
|
4
|
+
/consectetur adipiscing/i,
|
|
5
|
+
/TODO/g,
|
|
6
|
+
/FIXME/g,
|
|
7
|
+
/xxx+/gi,
|
|
8
|
+
/placeholder/i,
|
|
9
|
+
/sample text/i,
|
|
10
|
+
/test test/i,
|
|
11
|
+
/foo bar/i,
|
|
12
|
+
/example\.com/gi,
|
|
13
|
+
];
|
|
14
|
+
const PRICE_PATTERN = /\$[\d,]+\.\d{2}/g;
|
|
15
|
+
/**
|
|
16
|
+
* Check visible text for content issues.
|
|
17
|
+
*/
|
|
18
|
+
export function checkContentIssues(visibleText, _html) {
|
|
19
|
+
const issues = [];
|
|
20
|
+
// Placeholder text
|
|
21
|
+
for (const pattern of PLACEHOLDER_PATTERNS) {
|
|
22
|
+
if (pattern.test(visibleText)) {
|
|
23
|
+
issues.push({
|
|
24
|
+
type: "placeholder_text",
|
|
25
|
+
description: `Page contains placeholder text matching: ${pattern.source}`,
|
|
26
|
+
severity: "error",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if ("lastIndex" in pattern)
|
|
30
|
+
pattern.lastIndex = 0;
|
|
31
|
+
}
|
|
32
|
+
// Negative or zero prices
|
|
33
|
+
const prices = visibleText.match(PRICE_PATTERN) || [];
|
|
34
|
+
for (const price of prices) {
|
|
35
|
+
const value = parseFloat(price.replace("$", "").replace(",", ""));
|
|
36
|
+
if (value <= 0) {
|
|
37
|
+
issues.push({
|
|
38
|
+
type: "invalid_price",
|
|
39
|
+
description: `Invalid price found: ${price}`,
|
|
40
|
+
severity: "error",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Very short page content (might be error/blank page)
|
|
45
|
+
if (visibleText.trim().length < 50) {
|
|
46
|
+
issues.push({
|
|
47
|
+
type: "empty_page",
|
|
48
|
+
description: "Page has very little visible content",
|
|
49
|
+
severity: "error",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Check for error page indicators
|
|
53
|
+
const errorPatterns = [
|
|
54
|
+
/404\s*(not found|error|page)/i,
|
|
55
|
+
/500\s*(internal|server|error)/i,
|
|
56
|
+
/403\s*(forbidden|error)/i,
|
|
57
|
+
/page not found/i,
|
|
58
|
+
/something went wrong/i,
|
|
59
|
+
/an error occurred/i,
|
|
60
|
+
/error loading/i,
|
|
61
|
+
/cannot be found/i,
|
|
62
|
+
/no longer available/i,
|
|
63
|
+
/oops/i,
|
|
64
|
+
];
|
|
65
|
+
for (const pattern of errorPatterns) {
|
|
66
|
+
if (pattern.test(visibleText)) {
|
|
67
|
+
issues.push({
|
|
68
|
+
type: "error_page",
|
|
69
|
+
description: `Page appears to be an error page: "${visibleText.match(pattern)?.[0]}"`,
|
|
70
|
+
severity: "error",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return issues;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=content-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-checker.js","sourceRoot":"","sources":["../../src/detectors/content-checker.ts"],"names":[],"mappings":"AAMA,MAAM,oBAAoB,GAAG;IAC3B,cAAc;IACd,iBAAiB;IACjB,yBAAyB;IACzB,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,cAAc;IACd,cAAc;IACd,YAAY;IACZ,UAAU;IACV,gBAAgB;CACjB,CAAC;AAEF,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEzC;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,KAAa;IAEb,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,mBAAmB;IACnB,KAAK,MAAM,OAAO,IAAI,oBAAoB,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE,4CAA4C,OAAO,CAAC,MAAM,EAAE;gBACzE,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,WAAW,IAAI,OAAO;YAAE,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IACpD,CAAC;IAED,0BAA0B;IAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IACtD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe;gBACrB,WAAW,EAAE,wBAAwB,KAAK,EAAE;gBAC5C,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,sCAAsC;YACnD,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,MAAM,aAAa,GAAG;QACpB,+BAA+B;QAC/B,gCAAgC;QAChC,0BAA0B;QAC1B,iBAAiB;QACjB,uBAAuB;QACvB,oBAAoB;QACpB,gBAAgB;QAChB,kBAAkB;QAClB,sBAAsB;QACtB,OAAO;KACR,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;QACpC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,YAAY;gBAClB,WAAW,EAAE,sCAAsC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG;gBACrF,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BrowserAdapter } from "../adapter";
|
|
2
|
+
import type { ActionableItem, PageResponse, PageStateResponse, ActionDefinitionResponse } from "@sudobility/testomniac_types";
|
|
3
|
+
export interface DetectionContext {
|
|
4
|
+
adapter: BrowserAdapter;
|
|
5
|
+
html: string;
|
|
6
|
+
visibleText: string;
|
|
7
|
+
pageUrl: string;
|
|
8
|
+
pageRecord: PageResponse;
|
|
9
|
+
pageState: PageStateResponse;
|
|
10
|
+
items: ActionableItem[];
|
|
11
|
+
appId: number;
|
|
12
|
+
scanId: number;
|
|
13
|
+
currentActionChain: ActionDefinitionResponse[];
|
|
14
|
+
}
|
|
15
|
+
export interface DetectedIssue {
|
|
16
|
+
severity: "bug" | "warning";
|
|
17
|
+
ruleName: string;
|
|
18
|
+
title: string;
|
|
19
|
+
expectedOutcome: string;
|
|
20
|
+
observedOutcome: string;
|
|
21
|
+
actionChain: number[];
|
|
22
|
+
}
|
|
23
|
+
export interface DetectionRule {
|
|
24
|
+
name: string;
|
|
25
|
+
severity: "bug" | "warning";
|
|
26
|
+
detect(context: DetectionContext): Promise<DetectedIssue[]>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=detection-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection-rule.d.ts","sourceRoot":"","sources":["../../src/detectors/detection-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,YAAY,CAAC;IACzB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,wBAAwB,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;CAC7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=detection-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection-rule.js","sourceRoot":"","sources":["../../src/detectors/detection-rule.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface FunctionalIssue {
|
|
2
|
+
type: string;
|
|
3
|
+
description: string;
|
|
4
|
+
severity: "error" | "warning" | "info";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Analyze console errors for real issues (filtering noise).
|
|
8
|
+
*/
|
|
9
|
+
export declare function analyzeConsoleErrors(errors: string[]): FunctionalIssue[];
|
|
10
|
+
/**
|
|
11
|
+
* Analyze network responses for errors.
|
|
12
|
+
*/
|
|
13
|
+
export declare function analyzeNetworkErrors(responses: Array<{
|
|
14
|
+
url: string;
|
|
15
|
+
status: number;
|
|
16
|
+
contentType?: string;
|
|
17
|
+
}>, baseOrigin: string): FunctionalIssue[];
|
|
18
|
+
/**
|
|
19
|
+
* Check if a click resulted in an error page or unexpected state.
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkPostClickState(beforeUrl: string, afterUrl: string, afterText: string): FunctionalIssue[];
|
|
22
|
+
//# sourceMappingURL=functional-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functional-checker.d.ts","sourceRoot":"","sources":["../../src/detectors/functional-checker.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CAuBxE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,KAAK,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC,EACF,UAAU,EAAE,MAAM,GACjB,eAAe,EAAE,CA4BnB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,CAyBnB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyze console errors for real issues (filtering noise).
|
|
3
|
+
*/
|
|
4
|
+
export function analyzeConsoleErrors(errors) {
|
|
5
|
+
const issues = [];
|
|
6
|
+
const noise = [
|
|
7
|
+
/favicon/i,
|
|
8
|
+
/third.party/i,
|
|
9
|
+
/polyfill/i,
|
|
10
|
+
/analytics/i,
|
|
11
|
+
/tracking/i,
|
|
12
|
+
/deprecated/i,
|
|
13
|
+
/JQMIGRATE/i,
|
|
14
|
+
];
|
|
15
|
+
for (const error of errors) {
|
|
16
|
+
const isNoise = noise.some(p => p.test(error));
|
|
17
|
+
if (!isNoise) {
|
|
18
|
+
issues.push({
|
|
19
|
+
type: "console_error",
|
|
20
|
+
description: error.slice(0, 200),
|
|
21
|
+
severity: "error",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return issues;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Analyze network responses for errors.
|
|
29
|
+
*/
|
|
30
|
+
export function analyzeNetworkErrors(responses, baseOrigin) {
|
|
31
|
+
const issues = [];
|
|
32
|
+
for (const resp of responses) {
|
|
33
|
+
if (resp.status < 400)
|
|
34
|
+
continue;
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(resp.url);
|
|
37
|
+
const isSameOrigin = url.origin === baseOrigin;
|
|
38
|
+
// Same origin errors are always important
|
|
39
|
+
if (isSameOrigin) {
|
|
40
|
+
issues.push({
|
|
41
|
+
type: resp.status >= 500 ? "server_error" : "not_found",
|
|
42
|
+
description: `${resp.status} for ${resp.url}`,
|
|
43
|
+
severity: resp.status >= 500 ? "error" : "warning",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// External 5xx are also important
|
|
47
|
+
else if (resp.status >= 500) {
|
|
48
|
+
issues.push({
|
|
49
|
+
type: "external_server_error",
|
|
50
|
+
description: `External resource returned ${resp.status}: ${resp.url}`,
|
|
51
|
+
severity: "warning",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* ignore invalid URLs */
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return issues;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if a click resulted in an error page or unexpected state.
|
|
63
|
+
*/
|
|
64
|
+
export function checkPostClickState(beforeUrl, afterUrl, afterText) {
|
|
65
|
+
const issues = [];
|
|
66
|
+
// Click led to error page
|
|
67
|
+
const errorIndicators = [
|
|
68
|
+
/404/i,
|
|
69
|
+
/not found/i,
|
|
70
|
+
/error/i,
|
|
71
|
+
/500/i,
|
|
72
|
+
/something went wrong/i,
|
|
73
|
+
/oops/i,
|
|
74
|
+
/forbidden/i,
|
|
75
|
+
];
|
|
76
|
+
for (const pattern of errorIndicators) {
|
|
77
|
+
if (pattern.test(afterText) && !pattern.test(beforeUrl)) {
|
|
78
|
+
issues.push({
|
|
79
|
+
type: "click_leads_to_error",
|
|
80
|
+
description: `Click navigated to error page: ${afterUrl}`,
|
|
81
|
+
severity: "error",
|
|
82
|
+
});
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return issues;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=functional-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"functional-checker.js","sourceRoot":"","sources":["../../src/detectors/functional-checker.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAgB;IACnD,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,cAAc;QACd,WAAW;QACX,YAAY;QACZ,WAAW;QACX,aAAa;QACb,YAAY;KACb,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe;gBACrB,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;gBAChC,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAIE,EACF,UAAkB;IAElB,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;YAAE,SAAS;QAChC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC;YAC/C,0CAA0C;YAC1C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW;oBACvD,WAAW,EAAE,GAAG,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,GAAG,EAAE;oBAC7C,QAAQ,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;iBACnD,CAAC,CAAC;YACL,CAAC;YACD,kCAAkC;iBAC7B,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,uBAAuB;oBAC7B,WAAW,EAAE,8BAA8B,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,GAAG,EAAE;oBACrE,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,QAAgB,EAChB,SAAiB;IAEjB,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,0BAA0B;IAC1B,MAAM,eAAe,GAAG;QACtB,MAAM;QACN,YAAY;QACZ,QAAQ;QACR,MAAM;QACN,uBAAuB;QACvB,OAAO;QACP,YAAY;KACb,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,sBAAsB;gBAC5B,WAAW,EAAE,kCAAkC,QAAQ,EAAE;gBACzD,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;YACH,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { extractLinks, checkLinks, type LinkCheckResult } from "./link-checker";
|
|
2
|
+
export { checkVisualIssues, type VisualIssue } from "./visual-checker";
|
|
3
|
+
export { checkContentIssues, type ContentIssue } from "./content-checker";
|
|
4
|
+
export { analyzeConsoleErrors, analyzeNetworkErrors, checkPostClickState, type FunctionalIssue, } from "./functional-checker";
|
|
5
|
+
export { detectBrokenLinks, detectVisualIssues, detectContentIssues, detectMediaIssues, type BrokenLinkResult, type MediaIssue, } from "./bug-detector";
|
|
6
|
+
export { detectAndHandleModal, dismissModal } from "./modal-handler";
|
|
7
|
+
export type { DetectionContext, DetectedIssue, DetectionRule, } from "./detection-rule";
|
|
8
|
+
export { describeAction, buildTestCaseDescription } from "./action-description";
|
|
9
|
+
export { getAllDetectionRules } from "./rules";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGrE,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { extractLinks, checkLinks } from "./link-checker";
|
|
2
|
+
export { checkVisualIssues } from "./visual-checker";
|
|
3
|
+
export { checkContentIssues } from "./content-checker";
|
|
4
|
+
export { analyzeConsoleErrors, analyzeNetworkErrors, checkPostClickState, } from "./functional-checker";
|
|
5
|
+
export { detectBrokenLinks, detectVisualIssues, detectContentIssues, detectMediaIssues, } from "./bug-detector";
|
|
6
|
+
export { detectAndHandleModal, dismissModal } from "./modal-handler";
|
|
7
|
+
export { describeAction, buildTestCaseDescription } from "./action-description";
|
|
8
|
+
export { getAllDetectionRules } from "./rules";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAwB,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAoB,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAqB,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,GAGlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAQrE,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface LinkCheckResult {
|
|
2
|
+
url: string;
|
|
3
|
+
text: string;
|
|
4
|
+
status: number | null;
|
|
5
|
+
error: string | null;
|
|
6
|
+
isBroken: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Extract all links from HTML and check which are suspicious.
|
|
10
|
+
* Detects: 404 links, typos in URLs, links to non-existent pages.
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractLinks(html: string, baseUrl: string): Array<{
|
|
13
|
+
href: string;
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Check a batch of URLs for broken links.
|
|
18
|
+
* Returns only broken/suspicious ones.
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkLinks(links: Array<{
|
|
21
|
+
href: string;
|
|
22
|
+
text: string;
|
|
23
|
+
}>, baseOrigin: string): Promise<LinkCheckResult[]>;
|
|
24
|
+
//# sourceMappingURL=link-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-checker.d.ts","sourceRoot":"","sources":["../../src/detectors/link-checker.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BvC;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,EAAE,CAAC,CAgD5B"}
|