@sudobility/testomniac_runner_service 0.1.35 → 0.1.37

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 (56) hide show
  1. package/dist/api/client.d.ts +61 -2
  2. package/dist/api/client.d.ts.map +1 -1
  3. package/dist/api/client.js +37 -18
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/crawler/link-extractor.d.ts +8 -0
  6. package/dist/crawler/link-extractor.d.ts.map +1 -0
  7. package/dist/crawler/link-extractor.js +37 -0
  8. package/dist/crawler/link-extractor.js.map +1 -0
  9. package/dist/crawler/url-normalizer.d.ts +4 -0
  10. package/dist/crawler/url-normalizer.d.ts.map +1 -0
  11. package/dist/crawler/url-normalizer.js +27 -0
  12. package/dist/crawler/url-normalizer.js.map +1 -0
  13. package/dist/expertise/accessibility-expertise.d.ts +11 -0
  14. package/dist/expertise/accessibility-expertise.d.ts.map +1 -0
  15. package/dist/expertise/accessibility-expertise.js +131 -0
  16. package/dist/expertise/accessibility-expertise.js.map +1 -0
  17. package/dist/expertise/content-expertise.d.ts +10 -0
  18. package/dist/expertise/content-expertise.d.ts.map +1 -0
  19. package/dist/expertise/content-expertise.js +102 -0
  20. package/dist/expertise/content-expertise.js.map +1 -0
  21. package/dist/expertise/index.d.ts +3 -0
  22. package/dist/expertise/index.d.ts.map +1 -1
  23. package/dist/expertise/index.js +9 -4
  24. package/dist/expertise/index.js.map +1 -1
  25. package/dist/expertise/ui-expertise.d.ts +10 -0
  26. package/dist/expertise/ui-expertise.d.ts.map +1 -0
  27. package/dist/expertise/ui-expertise.js +76 -0
  28. package/dist/expertise/ui-expertise.js.map +1 -0
  29. package/dist/orchestrator/decomposition.d.ts.map +1 -1
  30. package/dist/orchestrator/decomposition.js +300 -65
  31. package/dist/orchestrator/decomposition.js.map +1 -1
  32. package/dist/orchestrator/direct-navigation.d.ts +4 -0
  33. package/dist/orchestrator/direct-navigation.d.ts.map +1 -0
  34. package/dist/orchestrator/direct-navigation.js +47 -0
  35. package/dist/orchestrator/direct-navigation.js.map +1 -0
  36. package/dist/orchestrator/discovery.d.ts +10 -0
  37. package/dist/orchestrator/discovery.d.ts.map +1 -0
  38. package/dist/orchestrator/discovery.js +77 -0
  39. package/dist/orchestrator/discovery.js.map +1 -0
  40. package/dist/orchestrator/expertise.d.ts +5 -0
  41. package/dist/orchestrator/expertise.d.ts.map +1 -0
  42. package/dist/orchestrator/expertise.js +157 -0
  43. package/dist/orchestrator/expertise.js.map +1 -0
  44. package/dist/orchestrator/orchestrator.d.ts.map +1 -1
  45. package/dist/orchestrator/orchestrator.js +63 -37
  46. package/dist/orchestrator/orchestrator.js.map +1 -1
  47. package/dist/orchestrator/page-capture.d.ts +22 -0
  48. package/dist/orchestrator/page-capture.d.ts.map +1 -0
  49. package/dist/orchestrator/page-capture.js +102 -0
  50. package/dist/orchestrator/page-capture.js.map +1 -0
  51. package/dist/orchestrator/test-execution.d.ts.map +1 -1
  52. package/dist/orchestrator/test-execution.js +17 -32
  53. package/dist/orchestrator/test-execution.js.map +1 -1
  54. package/dist/orchestrator/types.d.ts +10 -0
  55. package/dist/orchestrator/types.d.ts.map +1 -1
  56. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expertise.d.ts","sourceRoot":"","sources":["../../src/orchestrator/expertise.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAmG5D,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CA4Gf"}
@@ -0,0 +1,157 @@
1
+ import { ExpectationType } from "../domain/types";
2
+ import { createDefaultExpertises } from "../expertise";
3
+ import { detectScaffoldRegions } from "../scanner/component-detector";
4
+ import { detectPatternsWithInstances } from "../scanner/pattern-detector";
5
+ const EXPERTISE_PREFIX = "Expertise:";
6
+ function buildDefaultExpectations() {
7
+ return [
8
+ {
9
+ expectationType: ExpectationType.PageLoaded,
10
+ description: "Page should load successfully",
11
+ },
12
+ {
13
+ expectationType: ExpectationType.NoConsoleErrors,
14
+ description: "Page should not produce console errors",
15
+ },
16
+ {
17
+ expectationType: ExpectationType.NoNetworkErrors,
18
+ description: "Page should not produce network errors",
19
+ },
20
+ ];
21
+ }
22
+ function normalizeOutcomes(outcomes) {
23
+ const expectedOutcome = outcomes.length > 0
24
+ ? outcomes.map(item => item.expected).join("\n")
25
+ : undefined;
26
+ const observedOutcome = outcomes.length > 0
27
+ ? outcomes.map(item => `[${item.result}] ${item.observed}`).join("\n")
28
+ : undefined;
29
+ const hasErrors = outcomes.some(item => item.result === "error");
30
+ return {
31
+ expectedOutcome,
32
+ observedOutcome,
33
+ status: hasErrors ? "failed" : "completed",
34
+ };
35
+ }
36
+ async function ensureExpertiseSuite(api, config, events, expertiseName) {
37
+ const title = `${EXPERTISE_PREFIX} ${expertiseName}`;
38
+ const suites = await api.getTestSuitesByRunner(config.runnerId);
39
+ const existing = suites.find(suite => suite.title === title);
40
+ if (existing) {
41
+ return existing.id;
42
+ }
43
+ const created = await api.insertTestSuite(config.runnerId, {
44
+ title,
45
+ description: `Auto-generated expertise suite for ${expertiseName} findings`,
46
+ startingPath: "/",
47
+ sizeClass: config.sizeClass,
48
+ priority: 2,
49
+ suite_tags: ["expertise", expertiseName],
50
+ });
51
+ events.onTestSuiteCreated({ suiteId: created.id, title: created.title });
52
+ return created.id;
53
+ }
54
+ async function ensureExpertiseCase(api, config, suiteId, expertiseName, pageStateId, pageId, relativePath) {
55
+ const testCase = await api.insertTestCase(config.runnerId, {
56
+ title: `${expertiseName}: ${relativePath || "/"}`,
57
+ type: "render",
58
+ sizeClass: config.sizeClass,
59
+ suite_tags: ["expertise", expertiseName],
60
+ page_id: pageId,
61
+ priority: 2,
62
+ startingPageStateId: pageStateId,
63
+ startingPath: relativePath || "/",
64
+ steps: [],
65
+ globalExpectations: [],
66
+ }, suiteId);
67
+ return testCase.id;
68
+ }
69
+ export async function executePageExpertises(adapter, config, api, events, pageStateId, pageId, relativePath) {
70
+ const html = await adapter.content();
71
+ const scaffolds = await detectScaffoldRegions(adapter);
72
+ const patterns = await detectPatternsWithInstances(adapter);
73
+ const context = {
74
+ html,
75
+ scaffolds,
76
+ patterns,
77
+ consoleLogs: [],
78
+ networkLogs: [],
79
+ expectations: buildDefaultExpectations(),
80
+ };
81
+ const expertises = createDefaultExpertises();
82
+ for (const expertise of expertises) {
83
+ const suiteId = await ensureExpertiseSuite(api, config, events, expertise.name);
84
+ const testCaseId = await ensureExpertiseCase(api, config, suiteId, expertise.name, pageStateId, pageId, relativePath);
85
+ const testCaseRun = await api.createTestCaseRun({ testCaseId });
86
+ const testRun = await api.createTestRun({
87
+ runnerId: config.runnerId,
88
+ testCaseRunId: testCaseRun.id,
89
+ testEnvironmentId: config.testEnvironmentId,
90
+ parentTestRunId: config.scanId,
91
+ rootTestRunId: config.scanId,
92
+ sizeClass: config.sizeClass,
93
+ runnerInstanceId: config.runnerInstanceId,
94
+ runnerInstanceName: config.runnerInstanceName,
95
+ });
96
+ const startedAt = Date.now();
97
+ try {
98
+ const outcomes = expertise.evaluate(context);
99
+ const { expectedOutcome, observedOutcome, status } = normalizeOutcomes(outcomes);
100
+ for (const outcome of outcomes) {
101
+ if (outcome.result === "warning" || outcome.result === "error") {
102
+ await api.createTestRunFinding({
103
+ testCaseRunId: testCaseRun.id,
104
+ type: outcome.result === "error" ? "error" : "warning",
105
+ title: `[${expertise.name}] ${outcome.expected}`,
106
+ description: outcome.observed,
107
+ });
108
+ events.onFindingCreated({
109
+ type: outcome.result,
110
+ title: `[${expertise.name}] ${outcome.expected}`,
111
+ });
112
+ }
113
+ }
114
+ await api.completeTestCaseRun(testCaseRun.id, {
115
+ status,
116
+ durationMs: Date.now() - startedAt,
117
+ expectedOutcome,
118
+ observedOutcome,
119
+ });
120
+ await api.completeTestRun(testRun.id, {
121
+ status,
122
+ totalDurationMs: Date.now() - startedAt,
123
+ });
124
+ events.onTestRunCompleted({
125
+ testRunId: testRun.id,
126
+ passed: status !== "failed",
127
+ });
128
+ }
129
+ catch (error) {
130
+ const message = error instanceof Error ? error.message : "Expertise evaluation failed";
131
+ await api.completeTestCaseRun(testCaseRun.id, {
132
+ status: "failed",
133
+ durationMs: Date.now() - startedAt,
134
+ errorMessage: message,
135
+ });
136
+ await api.completeTestRun(testRun.id, {
137
+ status: "failed",
138
+ totalDurationMs: Date.now() - startedAt,
139
+ });
140
+ await api.createTestRunFinding({
141
+ testCaseRunId: testCaseRun.id,
142
+ type: "error",
143
+ title: `[${expertise.name}] expertise execution failed`,
144
+ description: message,
145
+ });
146
+ events.onFindingCreated({
147
+ type: "error",
148
+ title: `[${expertise.name}] expertise execution failed`,
149
+ });
150
+ events.onTestRunCompleted({
151
+ testRunId: testRun.id,
152
+ passed: false,
153
+ });
154
+ }
155
+ }
156
+ }
157
+ //# sourceMappingURL=expertise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expertise.js","sourceRoot":"","sources":["../../src/orchestrator/expertise.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAQxE,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,YAAY,EAAE,gBAAgB,GAC7B,OAAO,CAAC,UAAU,CAAC,CAgLrB"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA6CxE,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,YAAY,EAAE,gBAAgB,GAC7B,OAAO,CAAC,UAAU,CAAC,CA2LrB"}
@@ -1,14 +1,38 @@
1
+ import { discoverPublicPages } from "./discovery";
1
2
  import { processDecompositionJob } from "./decomposition";
2
3
  import { executeTestCases } from "./test-execution";
3
- import { computeHashes } from "../browser/page-utils";
4
- import { extractActionableItems } from "../extractors";
4
+ import { captureCurrentPage, resetCapturedPagePaths } from "./page-capture";
5
5
  const LOG = (...args) => console.warn("[orchestrator]", ...args);
6
+ function buildAiSummary(pagesFound, pageStatesFound, testRunsCompleted, findingsFound, expertiseSummary) {
7
+ const expertiseLines = Object.entries(expertiseSummary)
8
+ .sort(([left], [right]) => left.localeCompare(right))
9
+ .map(([name, counts]) => {
10
+ const parts = [];
11
+ if (counts.errors > 0)
12
+ parts.push(`${counts.errors} error${counts.errors === 1 ? "" : "s"}`);
13
+ if (counts.warnings > 0) {
14
+ parts.push(`${counts.warnings} warning${counts.warnings === 1 ? "" : "s"}`);
15
+ }
16
+ return parts.length > 0
17
+ ? `${name}: ${parts.join(", ")}`
18
+ : `${name}: no findings`;
19
+ });
20
+ const headline = findingsFound === 0
21
+ ? `Scan completed with no findings across ${pagesFound} page${pagesFound === 1 ? "" : "s"}.`
22
+ : `Scan completed with ${findingsFound} finding${findingsFound === 1 ? "" : "s"} across ${pagesFound} page${pagesFound === 1 ? "" : "s"}.`;
23
+ const detail = `Captured ${pageStatesFound} page state${pageStatesFound === 1 ? "" : "s"} and completed ${testRunsCompleted} test run${testRunsCompleted === 1 ? "" : "s"}.`;
24
+ if (expertiseLines.length === 0) {
25
+ return `${headline} ${detail}`;
26
+ }
27
+ return `${headline} ${detail} Findings by expertise: ${expertiseLines.join("; ")}.`;
28
+ }
6
29
  export async function runScan(adapter, config, api, eventHandler) {
7
30
  const startTime = Date.now();
8
31
  let pagesFound = 0;
9
32
  let pageStatesFound = 0;
10
33
  let testRunsCompleted = 0;
11
34
  let findingsFound = 0;
35
+ const expertiseSummary = {};
12
36
  const wrappedHandler = {
13
37
  ...eventHandler,
14
38
  onPageFound(page) {
@@ -28,6 +52,21 @@ export async function runScan(adapter, config, api, eventHandler) {
28
52
  },
29
53
  onFindingCreated(finding) {
30
54
  findingsFound++;
55
+ const match = /^\[([^\]]+)\]/.exec(finding.title);
56
+ if (match?.[1]) {
57
+ const expertiseName = match[1];
58
+ const counts = expertiseSummary[expertiseName] ?? {
59
+ warnings: 0,
60
+ errors: 0,
61
+ };
62
+ if (finding.type === "error") {
63
+ counts.errors += 1;
64
+ }
65
+ else if (finding.type === "warning") {
66
+ counts.warnings += 1;
67
+ }
68
+ expertiseSummary[expertiseName] = counts;
69
+ }
31
70
  eventHandler.onFindingCreated(finding);
32
71
  emitStats();
33
72
  },
@@ -41,42 +80,23 @@ export async function runScan(adapter, config, api, eventHandler) {
41
80
  });
42
81
  }
43
82
  try {
44
- // 1. Navigate to scan URL, capture initial page state
45
- LOG(`Step 1: Navigating to ${config.scanUrl}`);
83
+ resetCapturedPagePaths();
84
+ // 1. Crawl the site from the scan URL to inventory public pages
85
+ LOG(`Step 1: Discovering pages from ${config.scanUrl}`);
86
+ await discoverPublicPages(adapter, config, api, wrappedHandler);
87
+ // 2. Navigate back to scan URL and capture initial page state
88
+ LOG(`Step 2: Navigating to ${config.scanUrl}`);
46
89
  await adapter.goto(config.scanUrl, { waitUntil: "networkidle0" });
47
- const initialHtml = await adapter.content();
48
- LOG(`Page HTML length: ${initialHtml.length}`);
49
- // Compute relative path from scanUrl and baseUrl
50
- const scanUrlObj = new URL(config.scanUrl);
51
- const relativePath = scanUrlObj.pathname;
52
- const page = await api.findOrCreatePage(config.runnerId, relativePath);
53
- LOG(`Page created/found: id=${page.id}, path=${relativePath}`);
54
- wrappedHandler.onPageFound({ relativePath, pageId: page.id });
55
- // Extract actionable items and compute hashes
56
- const items = await extractActionableItems(adapter);
57
- LOG(`Extracted ${items.length} actionable items from page`);
58
- const hashes = await computeHashes(initialHtml, items);
59
- LOG(`Computed hashes:`, hashes);
60
- const initialPageState = await api.createPageState({
61
- pageId: page.id,
62
- sizeClass: config.sizeClass,
63
- hashes,
64
- screenshotPath: undefined,
65
- contentText: initialHtml.slice(0, 5000),
66
- });
67
- LOG(`Created page state: id=${initialPageState.id}`);
68
- wrappedHandler.onPageStateCreated({
69
- pageStateId: initialPageState.id,
70
- pageId: page.id,
71
- });
72
- // 2. Create initial AI Decomposition Job
73
- const initialJob = await api.createDecompositionJob(config.scanId, initialPageState.id);
74
- LOG(`Created decomposition job: id=${initialJob.id}`);
75
- wrappedHandler.onDecompositionJobCreated({
76
- jobId: initialJob.id,
77
- pageStateId: initialPageState.id,
90
+ const initialCapture = await captureCurrentPage(adapter, config, api, wrappedHandler, {
91
+ testRunId: config.scanId,
92
+ markDiscovered: false,
93
+ createDecompositionJob: true,
78
94
  });
79
- // 3. Generate/Run loop
95
+ if (!initialCapture?.pageStateId) {
96
+ throw new Error("Failed to capture initial page state");
97
+ }
98
+ LOG(`Captured initial page state ${initialCapture.pageStateId} for ${initialCapture.relativePath}`);
99
+ // 4. Generate/Run loop
80
100
  let iteration = 0;
81
101
  const MAX_ITERATIONS = 50;
82
102
  while (iteration < MAX_ITERATIONS) {
@@ -113,10 +133,12 @@ export async function runScan(adapter, config, api, eventHandler) {
113
133
  }
114
134
  LOG("New pages discovered — continuing to next iteration");
115
135
  }
116
- // 4. Complete test run
136
+ // 5. Complete test run
117
137
  const durationMs = Date.now() - startTime;
138
+ const aiSummary = buildAiSummary(pagesFound, pageStatesFound, testRunsCompleted, findingsFound, expertiseSummary);
118
139
  await api.completeTestRun(config.scanId, {
119
140
  status: "completed",
141
+ aiSummary,
120
142
  totalDurationMs: durationMs,
121
143
  pagesFound,
122
144
  pageStatesFound,
@@ -129,11 +151,15 @@ export async function runScan(adapter, config, api, eventHandler) {
129
151
  testRunsCompleted,
130
152
  findingsFound,
131
153
  durationMs,
154
+ aiSummary,
155
+ expertiseSummary,
132
156
  };
133
157
  wrappedHandler.onScanComplete({
134
158
  totalPages: pagesFound,
135
159
  totalFindings: findingsFound,
136
160
  durationMs,
161
+ aiSummary,
162
+ expertiseSummary,
137
163
  });
138
164
  return result;
139
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { BrowserAdapter } from "../adapter";
2
+ import type { ApiClient } from "../api/client";
3
+ import type { ScanConfig, ScanEventHandler } from "./types";
4
+ export interface CapturePageOptions {
5
+ testRunId?: number;
6
+ markDiscovered?: boolean;
7
+ captureState?: boolean;
8
+ createDecompositionJob?: boolean;
9
+ }
10
+ export interface CapturePageResult {
11
+ pageId: number;
12
+ relativePath: string;
13
+ pageStateId?: number;
14
+ decompositionJobId?: number;
15
+ createdNewState: boolean;
16
+ matchedExistingState: boolean;
17
+ }
18
+ export declare function resetCapturedPagePaths(): void;
19
+ export declare function seedCapturedPagePath(relativePath: string): void;
20
+ export declare function hasCapturedPagePath(relativePath: string): boolean;
21
+ export declare function captureCurrentPage(adapter: BrowserAdapter, config: ScanConfig, api: ApiClient, events: ScanEventHandler, options?: CapturePageOptions): Promise<CapturePageResult | null>;
22
+ //# sourceMappingURL=page-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-capture.d.ts","sourceRoot":"","sources":["../../src/orchestrator/page-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAM5D,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAID,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAgHnC"}
@@ -0,0 +1,102 @@
1
+ import { computeHashes } from "../browser/page-utils";
2
+ import { toRelativePath } from "../crawler/url-normalizer";
3
+ import { extractActionableItems } from "../extractors";
4
+ import { executePageExpertises } from "./expertise";
5
+ const capturedPagePaths = new Set();
6
+ export function resetCapturedPagePaths() {
7
+ capturedPagePaths.clear();
8
+ }
9
+ export function seedCapturedPagePath(relativePath) {
10
+ capturedPagePaths.add(relativePath);
11
+ }
12
+ export function hasCapturedPagePath(relativePath) {
13
+ return capturedPagePaths.has(relativePath);
14
+ }
15
+ export async function captureCurrentPage(adapter, config, api, events, options = {}) {
16
+ const currentUrl = await adapter.getUrl();
17
+ const current = new URL(currentUrl);
18
+ const base = new URL(config.baseUrl);
19
+ if (current.origin !== base.origin) {
20
+ return null;
21
+ }
22
+ const relativePath = toRelativePath(currentUrl);
23
+ const page = await api.findOrCreatePage(config.runnerId, relativePath);
24
+ if (options.markDiscovered) {
25
+ events.onPageFound({ relativePath, pageId: page.id });
26
+ if (config.testEnvironmentId) {
27
+ await api.createDiscoveredPages({
28
+ testEnvironmentId: config.testEnvironmentId,
29
+ pages: [{ relativePath, isPublic: true }],
30
+ });
31
+ }
32
+ if (config.testEnvironmentId && options.testRunId) {
33
+ await api.createPageVisit({
34
+ testRunId: options.testRunId,
35
+ testEnvironmentId: config.testEnvironmentId,
36
+ relativePath,
37
+ status: "visited",
38
+ });
39
+ }
40
+ }
41
+ if (hasCapturedPagePath(relativePath)) {
42
+ return {
43
+ pageId: page.id,
44
+ relativePath,
45
+ createdNewState: false,
46
+ matchedExistingState: false,
47
+ };
48
+ }
49
+ if (options.captureState === false) {
50
+ return {
51
+ pageId: page.id,
52
+ relativePath,
53
+ createdNewState: false,
54
+ matchedExistingState: false,
55
+ };
56
+ }
57
+ const html = await adapter.content();
58
+ const items = await extractActionableItems(adapter);
59
+ const hashes = await computeHashes(html, items);
60
+ const existingState = await api.findMatchingPageState(page.id, hashes, config.sizeClass);
61
+ if (existingState) {
62
+ seedCapturedPagePath(relativePath);
63
+ return {
64
+ pageId: page.id,
65
+ relativePath,
66
+ pageStateId: existingState.id,
67
+ createdNewState: false,
68
+ matchedExistingState: true,
69
+ };
70
+ }
71
+ const pageState = await api.createPageState({
72
+ pageId: page.id,
73
+ sizeClass: config.sizeClass,
74
+ hashes,
75
+ contentText: html.slice(0, 5000),
76
+ createdByTestRunId: options.testRunId,
77
+ });
78
+ seedCapturedPagePath(relativePath);
79
+ events.onPageStateCreated({
80
+ pageStateId: pageState.id,
81
+ pageId: page.id,
82
+ });
83
+ await executePageExpertises(adapter, config, api, events, pageState.id, page.id, relativePath);
84
+ let decompositionJobId;
85
+ if (options.createDecompositionJob) {
86
+ const job = await api.createDecompositionJob(config.scanId, pageState.id);
87
+ decompositionJobId = job.id;
88
+ events.onDecompositionJobCreated({
89
+ jobId: job.id,
90
+ pageStateId: pageState.id,
91
+ });
92
+ }
93
+ return {
94
+ pageId: page.id,
95
+ relativePath,
96
+ pageStateId: pageState.id,
97
+ decompositionJobId,
98
+ createdNewState: true,
99
+ matchedExistingState: false,
100
+ };
101
+ }
102
+ //# sourceMappingURL=page-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-capture.js","sourceRoot":"","sources":["../../src/orchestrator/page-capture.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-execution.d.ts","sourceRoot":"","sources":["../../src/orchestrator/test-execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAkJ5D,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CA2NlB"}
1
+ {"version":3,"file":"test-execution.d.ts","sourceRoot":"","sources":["../../src/orchestrator/test-execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAiI5D,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CA0NlB"}
@@ -1,5 +1,6 @@
1
1
  import { extractActionableItems } from "../extractors";
2
- import { computeHashes } from "../browser/page-utils";
2
+ import { toRelativePath } from "../crawler/url-normalizer";
3
+ import { captureCurrentPage, hasCapturedPagePath, seedCapturedPagePath, } from "./page-capture";
3
4
  const LOG = (...args) => console.warn("[test-execution]", ...args);
4
5
  /** Delay after each browser action to let the page settle. */
5
6
  const POST_ACTION_DELAY_MS = 2000;
@@ -10,8 +11,6 @@ function checkAbort(signal) {
10
11
  if (signal?.aborted)
11
12
  throw new Error("Scan aborted");
12
13
  }
13
- /** Pages already discovered — only create decomposition jobs for NEW pages. */
14
- const discoveredPagePaths = new Set();
15
14
  /**
16
15
  * After each action, check if we navigated to a new page (different path).
17
16
  * Only new pages trigger decomposition jobs. Same-page DOM changes from
@@ -25,34 +24,19 @@ async function captureCurrentPageState(config, adapter, api, testRunId, events)
25
24
  if (current.origin !== base.origin) {
26
25
  return false;
27
26
  }
28
- const relativePath = current.pathname;
27
+ const relativePath = toRelativePath(currentUrl);
29
28
  // Already seen this page path — no new work
30
- if (discoveredPagePaths.has(relativePath)) {
29
+ if (hasCapturedPagePath(relativePath)) {
31
30
  return false;
32
31
  }
33
- discoveredPagePaths.add(relativePath);
34
- // New page discovered — create page, state, and decomposition job
35
- const page = await api.findOrCreatePage(config.runnerId, relativePath);
36
- events.onPageFound({ relativePath, pageId: page.id });
37
- const html = await adapter.content();
38
- const items = await extractActionableItems(adapter);
39
- const hashes = await computeHashes(html, items);
40
- const newState = await api.createPageState({
41
- pageId: page.id,
42
- sizeClass: config.sizeClass,
43
- hashes,
44
- contentText: html.slice(0, 5000),
45
- createdByTestRunId: testRunId,
46
- });
47
- events.onPageStateCreated({
48
- pageStateId: newState.id,
49
- pageId: page.id,
50
- });
51
- const job = await api.createDecompositionJob(config.scanId, newState.id);
52
- events.onDecompositionJobCreated({
53
- jobId: job.id,
54
- pageStateId: newState.id,
32
+ const captureResult = await captureCurrentPage(adapter, config, api, events, {
33
+ testRunId,
34
+ markDiscovered: true,
35
+ createDecompositionJob: true,
55
36
  });
37
+ if (!captureResult?.createdNewState) {
38
+ return false;
39
+ }
56
40
  return true;
57
41
  }
58
42
  async function executeStoredAction(adapter, config, playwrightCode, fallbackPath) {
@@ -107,8 +91,8 @@ async function executeStoredAction(adapter, config, playwrightCode, fallbackPath
107
91
  }
108
92
  export async function executeTestCases(config, adapter, api, events, testCaseIds) {
109
93
  // Seed the initial scan URL path so we don't re-discover it
110
- const scanPath = new URL(config.scanUrl).pathname;
111
- discoveredPagePaths.add(scanPath);
94
+ const scanPath = toRelativePath(config.scanUrl);
95
+ seedCapturedPagePath(scanPath);
112
96
  // Only fetch and execute the specific test cases from this scan's decomposition
113
97
  LOG(`Fetching test cases for runner ${config.runnerId}`);
114
98
  const allTestCases = await api.getTestCasesByRunner(config.runnerId);
@@ -142,13 +126,13 @@ export async function executeTestCases(config, adapter, api, events, testCaseIds
142
126
  if (tc.startingPath) {
143
127
  const targetUrl = new URL(tc.startingPath, config.baseUrl).toString();
144
128
  const currentUrl = await adapter.getUrl();
145
- if (new URL(currentUrl).pathname !== new URL(targetUrl).pathname) {
129
+ if (toRelativePath(currentUrl) !== toRelativePath(targetUrl)) {
146
130
  LOG(`Navigating from ${currentUrl} to ${targetUrl}`);
147
131
  await adapter.goto(targetUrl, { waitUntil: "networkidle0" });
148
132
  await sleep(POST_ACTION_DELAY_MS);
149
133
  }
150
134
  else {
151
- LOG(`Already on ${new URL(currentUrl).pathname} — skipping navigation`);
135
+ LOG(`Already on ${toRelativePath(currentUrl)} — skipping navigation`);
152
136
  }
153
137
  }
154
138
  // Re-inject data-tmnc-id attributes into the DOM (they are transient
@@ -166,7 +150,7 @@ export async function executeTestCases(config, adapter, api, events, testCaseIds
166
150
  }
167
151
  const gotoUrl = new URL(action.path, config.baseUrl).toString();
168
152
  const nowUrl = await adapter.getUrl();
169
- if (new URL(nowUrl).pathname !== new URL(gotoUrl).pathname) {
153
+ if (toRelativePath(nowUrl) !== toRelativePath(gotoUrl)) {
170
154
  await adapter.goto(gotoUrl, { waitUntil: "networkidle0" });
171
155
  await sleep(POST_ACTION_DELAY_MS);
172
156
  }
@@ -190,6 +174,7 @@ export async function executeTestCases(config, adapter, api, events, testCaseIds
190
174
  await sleep(POST_ACTION_DELAY_MS);
191
175
  break;
192
176
  case "select":
177
+ case "selectOption":
193
178
  if (!action.path || action.value == null) {
194
179
  throw new Error("Select test action requires selector path and value");
195
180
  }