@sudobility/testomniac_runner_service 0.1.31 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/orchestrator/decomposition.d.ts +5 -1
- package/dist/orchestrator/decomposition.d.ts.map +1 -1
- package/dist/orchestrator/decomposition.js +94 -15
- package/dist/orchestrator/decomposition.js.map +1 -1
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +29 -6
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/test-execution.d.ts +1 -1
- package/dist/orchestrator/test-execution.d.ts.map +1 -1
- package/dist/orchestrator/test-execution.js +59 -42
- package/dist/orchestrator/test-execution.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,5 +2,9 @@ import type { BrowserAdapter } from "../adapter";
|
|
|
2
2
|
import type { ApiClient } from "../api/client";
|
|
3
3
|
import type { DecompositionJobResponse } from "@sudobility/testomniac_types";
|
|
4
4
|
import type { ScanConfig, ScanEventHandler } from "./types";
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Process a decomposition job: extract actionable items from the live page
|
|
7
|
+
* and generate click/hover test cases. Returns created test case IDs.
|
|
8
|
+
*/
|
|
9
|
+
export declare function processDecompositionJob(job: DecompositionJobResponse, adapter: BrowserAdapter, config: ScanConfig, api: ApiClient, events: ScanEventHandler): Promise<number[]>;
|
|
6
10
|
//# sourceMappingURL=decomposition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decomposition.d.ts","sourceRoot":"","sources":["../../src/orchestrator/decomposition.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,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"decomposition.d.ts","sourceRoot":"","sources":["../../src/orchestrator/decomposition.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,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAW5D;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,wBAAwB,EAC7B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAkJnB"}
|
|
@@ -1,26 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { extractActionableItems } from "../extractors";
|
|
2
|
+
import { PlaywrightAction, ExpectationType, ExpectationSeverity, } from "../domain/types";
|
|
3
|
+
const LOG = (...args) => console.log("[decomposition]", ...args);
|
|
4
|
+
/**
|
|
5
|
+
* Process a decomposition job: extract actionable items from the live page
|
|
6
|
+
* and generate click/hover test cases. Returns created test case IDs.
|
|
7
|
+
*/
|
|
8
|
+
export async function processDecompositionJob(job, adapter, config, api, events) {
|
|
9
|
+
LOG(`Processing job ${job.id} for pageState ${job.pageStateId}`);
|
|
3
10
|
const pageState = await api.getPageState(job.pageStateId);
|
|
4
11
|
if (!pageState) {
|
|
5
12
|
throw new Error(`Page state ${job.pageStateId} not found`);
|
|
6
13
|
}
|
|
14
|
+
LOG(`Page state found: pageId=${pageState.pageId}`);
|
|
7
15
|
const page = await api.getPage(pageState.pageId);
|
|
8
16
|
if (!page) {
|
|
9
17
|
throw new Error(`Page ${pageState.pageId} not found`);
|
|
10
18
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
LOG(`Page found: relativePath=${page.relativePath}`);
|
|
20
|
+
// Extract actionable items from the live page
|
|
21
|
+
const items = await extractActionableItems(adapter);
|
|
22
|
+
LOG(`Extracted ${items.length} actionable items:`, items.map(i => ({
|
|
23
|
+
selector: i.selector?.slice(0, 60),
|
|
24
|
+
actionKind: i.actionKind,
|
|
25
|
+
tagName: i.tagName,
|
|
26
|
+
role: i.role,
|
|
27
|
+
accessibleName: i.accessibleName?.slice(0, 40),
|
|
28
|
+
visible: i.visible,
|
|
29
|
+
disabled: i.disabled,
|
|
30
|
+
})));
|
|
31
|
+
// Filter to visible, enabled, interactive items
|
|
32
|
+
const interactiveItems = items.filter(i => i.visible && !i.disabled && i.selector);
|
|
33
|
+
LOG(`${interactiveItems.length} items after filtering (visible, enabled, has selector)`);
|
|
34
|
+
if (interactiveItems.length === 0) {
|
|
35
|
+
LOG("No interactive items found — skipping decomposition");
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
20
38
|
// Create a test suite for this decomposition job
|
|
21
39
|
const suite = await api.insertTestSuite(config.runnerId, {
|
|
22
40
|
title: `Page State #${job.pageStateId}`,
|
|
23
|
-
description: `Auto-generated test suite for page state ${job.pageStateId}`,
|
|
41
|
+
description: `Auto-generated test suite for page state ${job.pageStateId} on ${page.relativePath}`,
|
|
24
42
|
startingPageStateId: job.pageStateId,
|
|
25
43
|
startingPath: page.relativePath,
|
|
26
44
|
sizeClass: config.sizeClass,
|
|
@@ -28,11 +46,70 @@ export async function processDecompositionJob(job, _adapter, config, api, events
|
|
|
28
46
|
suite_tags: ["auto-generated"],
|
|
29
47
|
decompositionJobId: job.id,
|
|
30
48
|
});
|
|
49
|
+
LOG(`Created test suite: id=${suite.id}, title=${suite.title}`);
|
|
31
50
|
events.onTestSuiteCreated({ suiteId: suite.id, title: suite.title });
|
|
32
|
-
//
|
|
33
|
-
|
|
51
|
+
// Generate one test case per actionable item (cap at 20 to avoid explosion)
|
|
52
|
+
const maxItems = Math.min(interactiveItems.length, 20);
|
|
53
|
+
const createdIds = [];
|
|
54
|
+
for (let i = 0; i < maxItems; i++) {
|
|
55
|
+
const item = interactiveItems[i];
|
|
56
|
+
const actionKind = item.actionKind || "click";
|
|
57
|
+
const label = item.accessibleName ||
|
|
58
|
+
item.tagName ||
|
|
59
|
+
item.selector?.slice(0, 30) ||
|
|
60
|
+
"element";
|
|
61
|
+
// Determine test action type
|
|
62
|
+
let actionType;
|
|
63
|
+
if (actionKind === "navigate" || actionKind === "click") {
|
|
64
|
+
actionType = "click";
|
|
65
|
+
}
|
|
66
|
+
else if (actionKind === "fill") {
|
|
67
|
+
actionType = "fill";
|
|
68
|
+
}
|
|
69
|
+
else if (actionKind === "select") {
|
|
70
|
+
actionType = "select";
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
actionType = "click";
|
|
74
|
+
}
|
|
75
|
+
const steps = [
|
|
76
|
+
{
|
|
77
|
+
action: {
|
|
78
|
+
actionType: PlaywrightAction.Click,
|
|
79
|
+
pageStateId: pageState.id,
|
|
80
|
+
path: item.selector,
|
|
81
|
+
playwrightCode: `await page.click('${item.selector.replace(/'/g, "\\'")}');`,
|
|
82
|
+
description: `${actionType} on ${label}`,
|
|
83
|
+
},
|
|
84
|
+
expectations: [
|
|
85
|
+
{
|
|
86
|
+
expectationType: ExpectationType.NoConsoleErrors,
|
|
87
|
+
severity: ExpectationSeverity.ShouldPass,
|
|
88
|
+
description: "No console errors after interaction",
|
|
89
|
+
playwrightCode: "expect(consoleErrors).toHaveLength(0);",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
description: `${actionType} on ${label}`,
|
|
93
|
+
continueOnFailure: false,
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
const testCase = {
|
|
97
|
+
title: `${actionType}: ${label}`,
|
|
98
|
+
type: "interaction",
|
|
99
|
+
sizeClass: config.sizeClass,
|
|
100
|
+
suite_tags: ["auto-generated", "mouse-scanning"],
|
|
101
|
+
page_id: page.id,
|
|
102
|
+
priority: 3,
|
|
103
|
+
startingPageStateId: pageState.id,
|
|
104
|
+
startingPath: page.relativePath,
|
|
105
|
+
steps,
|
|
106
|
+
globalExpectations: [],
|
|
107
|
+
};
|
|
108
|
+
LOG(`Creating test case ${i + 1}/${maxItems}: "${testCase.title}" selector=${item.selector?.slice(0, 60)}`);
|
|
34
109
|
const tc = await api.insertTestCase(config.runnerId, testCase);
|
|
35
|
-
|
|
110
|
+
createdIds.push(tc.id);
|
|
111
|
+
// Create test actions for each step
|
|
112
|
+
for (const [index, step] of steps.entries()) {
|
|
36
113
|
await api.createTestAction({
|
|
37
114
|
testCaseId: tc.id,
|
|
38
115
|
stepOrder: index,
|
|
@@ -50,5 +127,7 @@ export async function processDecompositionJob(job, _adapter, config, api, events
|
|
|
50
127
|
});
|
|
51
128
|
}
|
|
52
129
|
}
|
|
130
|
+
LOG(`Decomposition complete: created ${createdIds.length} test cases`);
|
|
131
|
+
return createdIds;
|
|
53
132
|
}
|
|
54
133
|
//# sourceMappingURL=decomposition.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decomposition.js","sourceRoot":"","sources":["../../src/orchestrator/decomposition.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"decomposition.js","sourceRoot":"","sources":["../../src/orchestrator/decomposition.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;
|
|
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"}
|
|
@@ -2,6 +2,7 @@ import { processDecompositionJob } from "./decomposition";
|
|
|
2
2
|
import { executeTestCases } from "./test-execution";
|
|
3
3
|
import { computeHashes } from "../browser/page-utils";
|
|
4
4
|
import { extractActionableItems } from "../extractors";
|
|
5
|
+
const LOG = (...args) => console.log("[orchestrator]", ...args);
|
|
5
6
|
export async function runScan(adapter, config, api, eventHandler) {
|
|
6
7
|
const startTime = Date.now();
|
|
7
8
|
let pagesFound = 0;
|
|
@@ -41,16 +42,21 @@ export async function runScan(adapter, config, api, eventHandler) {
|
|
|
41
42
|
}
|
|
42
43
|
try {
|
|
43
44
|
// 1. Navigate to scan URL, capture initial page state
|
|
45
|
+
LOG(`Step 1: Navigating to ${config.scanUrl}`);
|
|
44
46
|
await adapter.goto(config.scanUrl, { waitUntil: "networkidle0" });
|
|
45
47
|
const initialHtml = await adapter.content();
|
|
48
|
+
LOG(`Page HTML length: ${initialHtml.length}`);
|
|
46
49
|
// Compute relative path from scanUrl and baseUrl
|
|
47
50
|
const scanUrlObj = new URL(config.scanUrl);
|
|
48
51
|
const relativePath = scanUrlObj.pathname;
|
|
49
52
|
const page = await api.findOrCreatePage(config.runnerId, relativePath);
|
|
53
|
+
LOG(`Page created/found: id=${page.id}, path=${relativePath}`);
|
|
50
54
|
wrappedHandler.onPageFound({ relativePath, pageId: page.id });
|
|
51
55
|
// Extract actionable items and compute hashes
|
|
52
56
|
const items = await extractActionableItems(adapter);
|
|
57
|
+
LOG(`Extracted ${items.length} actionable items from page`);
|
|
53
58
|
const hashes = await computeHashes(initialHtml, items);
|
|
59
|
+
LOG(`Computed hashes:`, hashes);
|
|
54
60
|
const initialPageState = await api.createPageState({
|
|
55
61
|
pageId: page.id,
|
|
56
62
|
sizeClass: config.sizeClass,
|
|
@@ -58,12 +64,14 @@ export async function runScan(adapter, config, api, eventHandler) {
|
|
|
58
64
|
screenshotPath: undefined,
|
|
59
65
|
contentText: initialHtml.slice(0, 5000),
|
|
60
66
|
});
|
|
67
|
+
LOG(`Created page state: id=${initialPageState.id}`);
|
|
61
68
|
wrappedHandler.onPageStateCreated({
|
|
62
69
|
pageStateId: initialPageState.id,
|
|
63
70
|
pageId: page.id,
|
|
64
71
|
});
|
|
65
72
|
// 2. Create initial AI Decomposition Job
|
|
66
73
|
const initialJob = await api.createDecompositionJob(config.scanId, initialPageState.id);
|
|
74
|
+
LOG(`Created decomposition job: id=${initialJob.id}`);
|
|
67
75
|
wrappedHandler.onDecompositionJobCreated({
|
|
68
76
|
jobId: initialJob.id,
|
|
69
77
|
pageStateId: initialPageState.id,
|
|
@@ -72,23 +80,38 @@ export async function runScan(adapter, config, api, eventHandler) {
|
|
|
72
80
|
let iteration = 0;
|
|
73
81
|
const MAX_ITERATIONS = 50;
|
|
74
82
|
while (iteration < MAX_ITERATIONS) {
|
|
75
|
-
if (config.signal?.aborted)
|
|
83
|
+
if (config.signal?.aborted) {
|
|
84
|
+
LOG("Aborted by signal");
|
|
76
85
|
break;
|
|
86
|
+
}
|
|
77
87
|
iteration++;
|
|
88
|
+
LOG(`=== Iteration ${iteration} ===`);
|
|
78
89
|
// Phase 1: GENERATE — process all pending decomposition jobs
|
|
79
90
|
const pendingJobs = await api.getPendingDecompositionJobs(config.scanId);
|
|
91
|
+
LOG(`Pending decomposition jobs: ${pendingJobs.length}`);
|
|
92
|
+
const testCaseIds = [];
|
|
80
93
|
for (const job of pendingJobs) {
|
|
81
94
|
if (config.signal?.aborted)
|
|
82
95
|
break;
|
|
83
|
-
await processDecompositionJob(job, adapter, config, api, wrappedHandler);
|
|
96
|
+
const ids = await processDecompositionJob(job, adapter, config, api, wrappedHandler);
|
|
97
|
+
LOG(`Job ${job.id} produced ${ids.length} test case IDs: [${ids.join(", ")}]`);
|
|
98
|
+
testCaseIds.push(...ids);
|
|
84
99
|
await api.completeDecompositionJob(job.id);
|
|
85
100
|
wrappedHandler.onDecompositionJobCompleted({ jobId: job.id });
|
|
86
101
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
if (testCaseIds.length === 0) {
|
|
103
|
+
LOG("No test cases generated — done");
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
// Phase 2: RUN — execute only the test cases just created
|
|
107
|
+
LOG(`Executing ${testCaseIds.length} test cases: [${testCaseIds.join(", ")}]`);
|
|
108
|
+
const newJobsCreated = await executeTestCases(config, adapter, api, wrappedHandler, testCaseIds);
|
|
109
|
+
// If no new pages were discovered, we're done
|
|
110
|
+
if (!newJobsCreated) {
|
|
111
|
+
LOG("No new pages discovered — done");
|
|
91
112
|
break;
|
|
113
|
+
}
|
|
114
|
+
LOG("New pages discovered — continuing to next iteration");
|
|
92
115
|
}
|
|
93
116
|
// 4. Complete test run
|
|
94
117
|
const durationMs = Date.now() - startTime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAuB,EACvB,MAAkB,EAClB,GAAc,EACd,YAA8B;IAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,MAAM,cAAc,GAAqB;QACvC,GAAG,YAAY;QACf,WAAW,CAAC,IAAI;YACd,UAAU,EAAE,CAAC;YACb,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAC/B,SAAS,EAAE,CAAC;QACd,CAAC;QACD,kBAAkB,CAAC,KAAK;YACtB,eAAe,EAAE,CAAC;YAClB,YAAY,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACvC,SAAS,EAAE,CAAC;QACd,CAAC;QACD,kBAAkB,CAAC,GAAG;YACpB,iBAAiB,EAAE,CAAC;YACpB,YAAY,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;YACrC,SAAS,EAAE,CAAC;QACd,CAAC;QACD,gBAAgB,CAAC,OAAO;YACtB,aAAa,EAAE,CAAC;YAChB,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACvC,SAAS,EAAE,CAAC;QACd,CAAC;KACF,CAAC;IAEF,SAAS,SAAS;QAChB,YAAY,CAAC,cAAc,CAAC;YAC1B,UAAU;YACV,eAAe;YACf,iBAAiB;YACjB,aAAa;SACd,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACH,sDAAsD;QACtD,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BrowserAdapter } from "../adapter";
|
|
2
2
|
import type { ApiClient } from "../api/client";
|
|
3
3
|
import type { ScanConfig, ScanEventHandler } from "./types";
|
|
4
|
-
export declare function executeTestCases(config: ScanConfig, adapter: BrowserAdapter, api: ApiClient, events: ScanEventHandler): Promise<boolean>;
|
|
4
|
+
export declare function executeTestCases(config: ScanConfig, adapter: BrowserAdapter, api: ApiClient, events: ScanEventHandler, testCaseIds: number[]): Promise<boolean>;
|
|
5
5
|
//# sourceMappingURL=test-execution.d.ts.map
|
|
@@ -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;
|
|
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,CA0MlB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { extractActionableItems } from "../extractors";
|
|
2
2
|
import { computeHashes } from "../browser/page-utils";
|
|
3
|
+
const LOG = (...args) => console.log("[test-execution]", ...args);
|
|
3
4
|
/** Delay after each browser action to let the page settle. */
|
|
4
5
|
const POST_ACTION_DELAY_MS = 2000;
|
|
5
6
|
function sleep(ms) {
|
|
@@ -9,31 +10,33 @@ function checkAbort(signal) {
|
|
|
9
10
|
if (signal?.aborted)
|
|
10
11
|
throw new Error("Scan aborted");
|
|
11
12
|
}
|
|
13
|
+
/** Pages already discovered — only create decomposition jobs for NEW pages. */
|
|
14
|
+
const discoveredPagePaths = new Set();
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
+
* After each action, check if we navigated to a new page (different path).
|
|
17
|
+
* Only new pages trigger decomposition jobs. Same-page DOM changes from
|
|
18
|
+
* clicks/hovers are ignored — they don't generate new test work.
|
|
16
19
|
*/
|
|
17
|
-
|
|
18
|
-
async function captureCurrentPageState(config, adapter, api, testRunId) {
|
|
20
|
+
async function captureCurrentPageState(config, adapter, api, testRunId, events) {
|
|
19
21
|
const currentUrl = await adapter.getUrl();
|
|
20
22
|
const current = new URL(currentUrl);
|
|
21
23
|
const base = new URL(config.baseUrl);
|
|
24
|
+
// Off-site navigation — skip
|
|
22
25
|
if (current.origin !== base.origin) {
|
|
23
|
-
return
|
|
26
|
+
return false;
|
|
24
27
|
}
|
|
25
|
-
const relativePath =
|
|
28
|
+
const relativePath = current.pathname;
|
|
29
|
+
// Already seen this page path — no new work
|
|
30
|
+
if (discoveredPagePaths.has(relativePath)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
discoveredPagePaths.add(relativePath);
|
|
34
|
+
// New page discovered — create page, state, and decomposition job
|
|
26
35
|
const page = await api.findOrCreatePage(config.runnerId, relativePath);
|
|
36
|
+
events.onPageFound({ relativePath, pageId: page.id });
|
|
27
37
|
const html = await adapter.content();
|
|
28
38
|
const items = await extractActionableItems(adapter);
|
|
29
39
|
const hashes = await computeHashes(html, items);
|
|
30
|
-
// Use actionableHash for deduplication — it only changes when interactive
|
|
31
|
-
// elements change, not from dynamic text/timestamps/counters.
|
|
32
|
-
const stateKey = `${page.id}:${hashes.actionableHash}`;
|
|
33
|
-
if (seenActionableStates.has(stateKey)) {
|
|
34
|
-
return { isNew: false, pageStateId: 0, pageId: page.id };
|
|
35
|
-
}
|
|
36
|
-
seenActionableStates.add(stateKey);
|
|
37
40
|
const newState = await api.createPageState({
|
|
38
41
|
pageId: page.id,
|
|
39
42
|
sizeClass: config.sizeClass,
|
|
@@ -41,13 +44,16 @@ async function captureCurrentPageState(config, adapter, api, testRunId) {
|
|
|
41
44
|
contentText: html.slice(0, 5000),
|
|
42
45
|
createdByTestRunId: testRunId,
|
|
43
46
|
});
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
isNew: true,
|
|
47
|
+
events.onPageStateCreated({
|
|
47
48
|
pageStateId: newState.id,
|
|
48
49
|
pageId: page.id,
|
|
50
|
+
});
|
|
51
|
+
const job = await api.createDecompositionJob(config.scanId, newState.id);
|
|
52
|
+
events.onDecompositionJobCreated({
|
|
49
53
|
jobId: job.id,
|
|
50
|
-
|
|
54
|
+
pageStateId: newState.id,
|
|
55
|
+
});
|
|
56
|
+
return true;
|
|
51
57
|
}
|
|
52
58
|
async function executeStoredAction(adapter, config, playwrightCode, fallbackPath) {
|
|
53
59
|
const trimmedCode = playwrightCode.trim();
|
|
@@ -99,15 +105,26 @@ async function executeStoredAction(adapter, config, playwrightCode, fallbackPath
|
|
|
99
105
|
return;
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
|
-
export async function executeTestCases(config, adapter, api, events) {
|
|
103
|
-
|
|
108
|
+
export async function executeTestCases(config, adapter, api, events, testCaseIds) {
|
|
109
|
+
// 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);
|
|
112
|
+
// Only fetch and execute the specific test cases from this scan's decomposition
|
|
113
|
+
LOG(`Fetching test cases for runner ${config.runnerId}`);
|
|
114
|
+
const allTestCases = await api.getTestCasesByRunner(config.runnerId);
|
|
115
|
+
LOG(`Total test cases for runner: ${allTestCases.length}, target IDs: [${testCaseIds.join(", ")}]`);
|
|
116
|
+
const targetIds = new Set(testCaseIds);
|
|
117
|
+
const testCases = allTestCases.filter(tc => targetIds.has(tc.id));
|
|
118
|
+
LOG(`Matched ${testCases.length} test cases to execute`);
|
|
104
119
|
let newJobsCreated = false;
|
|
105
120
|
const completedCaseIds = new Set();
|
|
106
121
|
for (const tc of testCases) {
|
|
107
122
|
checkAbort(config.signal);
|
|
123
|
+
LOG(`--- Executing test case ${tc.id}: "${tc.title}" startingPath=${tc.startingPath}`);
|
|
108
124
|
// Check dependency
|
|
109
125
|
if (tc.dependencyTestCaseId) {
|
|
110
126
|
if (!completedCaseIds.has(tc.dependencyTestCaseId)) {
|
|
127
|
+
LOG(`Skipping — dependency ${tc.dependencyTestCaseId} not completed yet`);
|
|
111
128
|
continue;
|
|
112
129
|
}
|
|
113
130
|
}
|
|
@@ -123,24 +140,35 @@ export async function executeTestCases(config, adapter, api, events) {
|
|
|
123
140
|
const startTime = Date.now();
|
|
124
141
|
try {
|
|
125
142
|
if (tc.startingPath) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
const targetUrl = new URL(tc.startingPath, config.baseUrl).toString();
|
|
144
|
+
const currentUrl = await adapter.getUrl();
|
|
145
|
+
if (new URL(currentUrl).pathname !== new URL(targetUrl).pathname) {
|
|
146
|
+
LOG(`Navigating from ${currentUrl} to ${targetUrl}`);
|
|
147
|
+
await adapter.goto(targetUrl, { waitUntil: "networkidle0" });
|
|
148
|
+
await sleep(POST_ACTION_DELAY_MS);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
LOG(`Already on ${new URL(currentUrl).pathname} — skipping navigation`);
|
|
152
|
+
}
|
|
130
153
|
}
|
|
131
154
|
const actions = await api.getTestActionsByCase(tc.id);
|
|
155
|
+
LOG(`Test case has ${actions.length} actions`);
|
|
132
156
|
for (const action of actions) {
|
|
133
157
|
checkAbort(config.signal);
|
|
158
|
+
LOG(`Action: ${action.actionType} path=${action.path?.slice(0, 60)} value=${action.value?.slice(0, 30)}`);
|
|
134
159
|
switch (action.actionType) {
|
|
135
|
-
case "goto":
|
|
160
|
+
case "goto": {
|
|
136
161
|
if (!action.path) {
|
|
137
162
|
throw new Error("Goto test action missing path");
|
|
138
163
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
164
|
+
const gotoUrl = new URL(action.path, config.baseUrl).toString();
|
|
165
|
+
const nowUrl = await adapter.getUrl();
|
|
166
|
+
if (new URL(nowUrl).pathname !== new URL(gotoUrl).pathname) {
|
|
167
|
+
await adapter.goto(gotoUrl, { waitUntil: "networkidle0" });
|
|
168
|
+
await sleep(POST_ACTION_DELAY_MS);
|
|
169
|
+
}
|
|
143
170
|
break;
|
|
171
|
+
}
|
|
144
172
|
case "waitForLoadState":
|
|
145
173
|
await executeStoredAction(adapter, config, action.playwrightCode, action.path ?? undefined);
|
|
146
174
|
break;
|
|
@@ -185,20 +213,9 @@ export async function executeTestCases(config, adapter, api, events) {
|
|
|
185
213
|
default:
|
|
186
214
|
break;
|
|
187
215
|
}
|
|
188
|
-
const
|
|
189
|
-
if (
|
|
190
|
-
if (capturedState.jobId == null) {
|
|
191
|
-
throw new Error("New page state was captured without a decomposition job");
|
|
192
|
-
}
|
|
216
|
+
const isNewPage = await captureCurrentPageState(config, adapter, api, testRun.id, events);
|
|
217
|
+
if (isNewPage) {
|
|
193
218
|
newJobsCreated = true;
|
|
194
|
-
events.onPageStateCreated({
|
|
195
|
-
pageStateId: capturedState.pageStateId,
|
|
196
|
-
pageId: capturedState.pageId,
|
|
197
|
-
});
|
|
198
|
-
events.onDecompositionJobCreated({
|
|
199
|
-
jobId: capturedState.jobId,
|
|
200
|
-
pageStateId: capturedState.pageStateId,
|
|
201
|
-
});
|
|
202
219
|
}
|
|
203
220
|
}
|
|
204
221
|
const durationMs = Date.now() - startTime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-execution.js","sourceRoot":"","sources":["../../src/orchestrator/test-execution.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,UAAU,CAAC,MAAoB;IACtC,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AACvD,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"test-execution.js","sourceRoot":"","sources":["../../src/orchestrator/test-execution.ts"],"names":[],"mappings":"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"}
|