@sudobility/testomniac_runner_service 0.1.39 → 0.1.40
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 +85 -331
- package/README.md +4 -8
- package/dist/analyzer/page-analyzer.d.ts +11 -5
- package/dist/analyzer/page-analyzer.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer.js +122 -35
- package/dist/analyzer/page-analyzer.js.map +1 -1
- package/dist/api/client.d.ts +2 -4
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +3 -17
- package/dist/api/client.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/runner.d.ts +1 -2
- package/dist/orchestrator/runner.d.ts.map +1 -1
- package/dist/orchestrator/runner.js +7 -12
- package/dist/orchestrator/runner.js.map +1 -1
- package/dist/orchestrator/test-case-executor.d.ts.map +1 -1
- package/dist/orchestrator/test-case-executor.js +39 -9
- package/dist/orchestrator/test-case-executor.js.map +1 -1
- package/dist/orchestrator/types.d.ts +0 -15
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/orchestrator/decomposition.d.ts +0 -10
- package/dist/orchestrator/decomposition.d.ts.map +0 -1
- package/dist/orchestrator/decomposition.js +0 -658
- package/dist/orchestrator/decomposition.js.map +0 -1
- package/dist/orchestrator/direct-navigation.d.ts +0 -4
- package/dist/orchestrator/direct-navigation.d.ts.map +0 -1
- package/dist/orchestrator/direct-navigation.js +0 -47
- package/dist/orchestrator/direct-navigation.js.map +0 -1
- package/dist/orchestrator/discovery.d.ts +0 -10
- package/dist/orchestrator/discovery.d.ts.map +0 -1
- package/dist/orchestrator/discovery.js +0 -77
- package/dist/orchestrator/discovery.js.map +0 -1
- package/dist/orchestrator/expertise.d.ts +0 -5
- package/dist/orchestrator/expertise.d.ts.map +0 -1
- package/dist/orchestrator/expertise.js +0 -168
- package/dist/orchestrator/expertise.js.map +0 -1
- package/dist/orchestrator/orchestrator.d.ts +0 -5
- package/dist/orchestrator/orchestrator.d.ts.map +0 -1
- package/dist/orchestrator/orchestrator.js +0 -172
- package/dist/orchestrator/orchestrator.js.map +0 -1
- package/dist/orchestrator/page-capture.d.ts +0 -22
- package/dist/orchestrator/page-capture.d.ts.map +0 -1
- package/dist/orchestrator/page-capture.js +0 -112
- package/dist/orchestrator/page-capture.js.map +0 -1
- package/dist/orchestrator/test-execution.d.ts +0 -5
- package/dist/orchestrator/test-execution.d.ts.map +0 -1
- package/dist/orchestrator/test-execution.js +0 -254
- package/dist/orchestrator/test-execution.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
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;AAeD,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;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,CAuHnC"}
|
|
@@ -1,112 +0,0 @@
|
|
|
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 discoveredPagePaths = new Set();
|
|
6
|
-
const capturedStateKeys = new Set();
|
|
7
|
-
function toStateKey(relativePath, hashes) {
|
|
8
|
-
return `${relativePath}:${hashes.normalizedHtmlHash}:${hashes.actionableHash}`;
|
|
9
|
-
}
|
|
10
|
-
export function resetCapturedPagePaths() {
|
|
11
|
-
discoveredPagePaths.clear();
|
|
12
|
-
capturedStateKeys.clear();
|
|
13
|
-
}
|
|
14
|
-
export function seedCapturedPagePath(relativePath) {
|
|
15
|
-
discoveredPagePaths.add(relativePath);
|
|
16
|
-
}
|
|
17
|
-
export function hasCapturedPagePath(relativePath) {
|
|
18
|
-
return discoveredPagePaths.has(relativePath);
|
|
19
|
-
}
|
|
20
|
-
export async function captureCurrentPage(adapter, config, api, events, options = {}) {
|
|
21
|
-
const currentUrl = await adapter.getUrl();
|
|
22
|
-
const current = new URL(currentUrl);
|
|
23
|
-
const base = new URL(config.baseUrl);
|
|
24
|
-
if (current.origin !== base.origin) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
const relativePath = toRelativePath(currentUrl);
|
|
28
|
-
const page = await api.findOrCreatePage(config.runnerId, relativePath);
|
|
29
|
-
if (options.markDiscovered) {
|
|
30
|
-
const firstTimeDiscovered = !hasCapturedPagePath(relativePath);
|
|
31
|
-
if (firstTimeDiscovered) {
|
|
32
|
-
events.onPageFound({ relativePath, pageId: page.id });
|
|
33
|
-
if (config.testEnvironmentId) {
|
|
34
|
-
await api.createDiscoveredPages({
|
|
35
|
-
testEnvironmentId: config.testEnvironmentId,
|
|
36
|
-
pages: [{ relativePath, isPublic: true }],
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
seedCapturedPagePath(relativePath);
|
|
40
|
-
}
|
|
41
|
-
if (config.testEnvironmentId && options.testRunId) {
|
|
42
|
-
await api.createPageVisit({
|
|
43
|
-
testRunId: options.testRunId,
|
|
44
|
-
testEnvironmentId: config.testEnvironmentId,
|
|
45
|
-
relativePath,
|
|
46
|
-
status: "visited",
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (options.captureState === false) {
|
|
51
|
-
return {
|
|
52
|
-
pageId: page.id,
|
|
53
|
-
relativePath,
|
|
54
|
-
createdNewState: false,
|
|
55
|
-
matchedExistingState: false,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
const html = await adapter.content();
|
|
59
|
-
const items = await extractActionableItems(adapter);
|
|
60
|
-
const hashes = await computeHashes(html, items);
|
|
61
|
-
const stateKey = toStateKey(relativePath, hashes);
|
|
62
|
-
if (capturedStateKeys.has(stateKey)) {
|
|
63
|
-
return {
|
|
64
|
-
pageId: page.id,
|
|
65
|
-
relativePath,
|
|
66
|
-
createdNewState: false,
|
|
67
|
-
matchedExistingState: false,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const existingState = await api.findMatchingPageState(page.id, hashes, config.sizeClass);
|
|
71
|
-
if (existingState) {
|
|
72
|
-
capturedStateKeys.add(stateKey);
|
|
73
|
-
return {
|
|
74
|
-
pageId: page.id,
|
|
75
|
-
relativePath,
|
|
76
|
-
pageStateId: existingState.id,
|
|
77
|
-
createdNewState: false,
|
|
78
|
-
matchedExistingState: true,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
const pageState = await api.createPageState({
|
|
82
|
-
pageId: page.id,
|
|
83
|
-
sizeClass: config.sizeClass,
|
|
84
|
-
hashes,
|
|
85
|
-
contentText: html.slice(0, 5000),
|
|
86
|
-
createdByTestRunId: options.testRunId,
|
|
87
|
-
});
|
|
88
|
-
capturedStateKeys.add(stateKey);
|
|
89
|
-
events.onPageStateCreated({
|
|
90
|
-
pageStateId: pageState.id,
|
|
91
|
-
pageId: page.id,
|
|
92
|
-
});
|
|
93
|
-
await executePageExpertises(adapter, config, api, events, pageState.id, page.id, relativePath);
|
|
94
|
-
let decompositionJobId;
|
|
95
|
-
if (options.createDecompositionJob) {
|
|
96
|
-
const job = await api.createDecompositionJob(config.scanId, pageState.id);
|
|
97
|
-
decompositionJobId = job.id;
|
|
98
|
-
events.onDecompositionJobCreated({
|
|
99
|
-
jobId: job.id,
|
|
100
|
-
pageStateId: pageState.id,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
pageId: page.id,
|
|
105
|
-
relativePath,
|
|
106
|
-
pageStateId: pageState.id,
|
|
107
|
-
decompositionJobId,
|
|
108
|
-
createdNewState: true,
|
|
109
|
-
matchedExistingState: false,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
//# sourceMappingURL=page-capture.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page-capture.js","sourceRoot":"","sources":["../../src/orchestrator/page-capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { BrowserAdapter } from "../adapter";
|
|
2
|
-
import type { ApiClient } from "../api/client";
|
|
3
|
-
import type { ScanConfig, ScanEventHandler } from "./types";
|
|
4
|
-
export declare function executeTestCases(config: ScanConfig, adapter: BrowserAdapter, api: ApiClient, events: ScanEventHandler, testCaseIds: number[]): Promise<boolean>;
|
|
5
|
-
//# sourceMappingURL=test-execution.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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;AA4H5D,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,254 +0,0 @@
|
|
|
1
|
-
import { extractActionableItems } from "../extractors";
|
|
2
|
-
import { toRelativePath } from "../crawler/url-normalizer";
|
|
3
|
-
import { captureCurrentPage, hasCapturedPagePath, seedCapturedPagePath, } from "./page-capture";
|
|
4
|
-
const LOG = (...args) => console.warn("[test-execution]", ...args);
|
|
5
|
-
/** Delay after each browser action to let the page settle. */
|
|
6
|
-
const POST_ACTION_DELAY_MS = 2000;
|
|
7
|
-
function sleep(ms) {
|
|
8
|
-
return new Promise(r => setTimeout(r, ms));
|
|
9
|
-
}
|
|
10
|
-
function checkAbort(signal) {
|
|
11
|
-
if (signal?.aborted)
|
|
12
|
-
throw new Error("Scan aborted");
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* After each action, capture the current same-origin state. New paths are
|
|
16
|
-
* discovered once, but same-path DOM transitions can still generate new page
|
|
17
|
-
* states and decomposition work when their structural hashes change.
|
|
18
|
-
*/
|
|
19
|
-
async function captureCurrentPageState(config, adapter, api, testRunId, events) {
|
|
20
|
-
const currentUrl = await adapter.getUrl();
|
|
21
|
-
const current = new URL(currentUrl);
|
|
22
|
-
const base = new URL(config.baseUrl);
|
|
23
|
-
// Off-site navigation — skip
|
|
24
|
-
if (current.origin !== base.origin) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
const relativePath = toRelativePath(currentUrl);
|
|
28
|
-
const captureResult = await captureCurrentPage(adapter, config, api, events, {
|
|
29
|
-
testRunId,
|
|
30
|
-
markDiscovered: !hasCapturedPagePath(relativePath),
|
|
31
|
-
createDecompositionJob: true,
|
|
32
|
-
});
|
|
33
|
-
if (!captureResult?.createdNewState) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
async function executeStoredAction(adapter, config, playwrightCode, fallbackPath) {
|
|
39
|
-
const trimmedCode = playwrightCode.trim();
|
|
40
|
-
if (trimmedCode.startsWith("await page.goto(") ||
|
|
41
|
-
trimmedCode.startsWith("page.goto(")) {
|
|
42
|
-
const gotoPath = fallbackPath ?? config.scanUrl;
|
|
43
|
-
const absoluteUrl = gotoPath.startsWith("http")
|
|
44
|
-
? gotoPath
|
|
45
|
-
: new URL(gotoPath, config.baseUrl).toString();
|
|
46
|
-
await adapter.goto(absoluteUrl, { waitUntil: "networkidle0" });
|
|
47
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (trimmedCode.startsWith("await page.waitForLoadState(") ||
|
|
51
|
-
trimmedCode.startsWith("page.waitForLoadState(")) {
|
|
52
|
-
try {
|
|
53
|
-
await adapter.waitForNavigation({
|
|
54
|
-
waitUntil: "networkidle0",
|
|
55
|
-
timeout: 5000,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
// Treat "no navigation pending" as settled enough for scan orchestration.
|
|
60
|
-
}
|
|
61
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (trimmedCode.startsWith("await page.click(") ||
|
|
65
|
-
trimmedCode.startsWith("page.click(")) {
|
|
66
|
-
const selector = fallbackPath;
|
|
67
|
-
if (!selector)
|
|
68
|
-
throw new Error("Missing selector for click action");
|
|
69
|
-
await adapter.click(selector);
|
|
70
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (trimmedCode.startsWith("await page.hover(") ||
|
|
74
|
-
trimmedCode.startsWith("page.hover(")) {
|
|
75
|
-
const selector = fallbackPath;
|
|
76
|
-
if (!selector)
|
|
77
|
-
throw new Error("Missing selector for hover action");
|
|
78
|
-
await adapter.hover(selector);
|
|
79
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (trimmedCode.startsWith("await page.screenshot(") ||
|
|
83
|
-
trimmedCode.startsWith("page.screenshot(")) {
|
|
84
|
-
await adapter.screenshot({ type: "png" });
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export async function executeTestCases(config, adapter, api, events, testCaseIds) {
|
|
89
|
-
// Seed the initial scan URL path so we don't re-discover it
|
|
90
|
-
const scanPath = toRelativePath(config.scanUrl);
|
|
91
|
-
seedCapturedPagePath(scanPath);
|
|
92
|
-
// Only fetch and execute the specific test cases from this scan's decomposition
|
|
93
|
-
LOG(`Fetching test cases for runner ${config.runnerId}`);
|
|
94
|
-
const allTestCases = await api.getTestCasesByRunner(config.runnerId);
|
|
95
|
-
LOG(`Total test cases for runner: ${allTestCases.length}, target IDs: [${testCaseIds.join(", ")}]`);
|
|
96
|
-
const targetIds = new Set(testCaseIds);
|
|
97
|
-
const testCases = allTestCases.filter(tc => targetIds.has(tc.id));
|
|
98
|
-
LOG(`Matched ${testCases.length} test cases to execute`);
|
|
99
|
-
let newJobsCreated = false;
|
|
100
|
-
const completedCaseIds = new Set();
|
|
101
|
-
for (const tc of testCases) {
|
|
102
|
-
checkAbort(config.signal);
|
|
103
|
-
LOG(`--- Executing test case ${tc.id}: "${tc.title}" startingPath=${tc.startingPath}`);
|
|
104
|
-
// Check dependency
|
|
105
|
-
if (tc.dependencyTestCaseId) {
|
|
106
|
-
if (!completedCaseIds.has(tc.dependencyTestCaseId)) {
|
|
107
|
-
LOG(`Skipping — dependency ${tc.dependencyTestCaseId} not completed yet`);
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// Create test case run + child test run
|
|
112
|
-
const testCaseRun = await api.createTestCaseRun({ testCaseId: tc.id });
|
|
113
|
-
const testRun = await api.createTestRun({
|
|
114
|
-
runnerId: config.runnerId,
|
|
115
|
-
testCaseRunId: testCaseRun.id,
|
|
116
|
-
parentTestRunId: config.scanId,
|
|
117
|
-
rootTestRunId: config.scanId,
|
|
118
|
-
sizeClass: config.sizeClass,
|
|
119
|
-
});
|
|
120
|
-
const startTime = Date.now();
|
|
121
|
-
try {
|
|
122
|
-
if (tc.startingPath) {
|
|
123
|
-
const targetUrl = new URL(tc.startingPath, config.baseUrl).toString();
|
|
124
|
-
const currentUrl = await adapter.getUrl();
|
|
125
|
-
if (toRelativePath(currentUrl) !== toRelativePath(targetUrl)) {
|
|
126
|
-
LOG(`Navigating from ${currentUrl} to ${targetUrl}`);
|
|
127
|
-
await adapter.goto(targetUrl, { waitUntil: "networkidle0" });
|
|
128
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
LOG(`Already on ${toRelativePath(currentUrl)} — skipping navigation`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// Re-inject data-tmnc-id attributes into the DOM (they are transient
|
|
135
|
-
// and lost when the page re-renders, e.g. React SPA)
|
|
136
|
-
await extractActionableItems(adapter);
|
|
137
|
-
const actions = await api.getTestActionsByCase(tc.id);
|
|
138
|
-
LOG(`Test case has ${actions.length} actions`);
|
|
139
|
-
for (const action of actions) {
|
|
140
|
-
checkAbort(config.signal);
|
|
141
|
-
LOG(`Action: ${action.actionType} path=${action.path?.slice(0, 60)} value=${action.value?.slice(0, 30)}`);
|
|
142
|
-
switch (action.actionType) {
|
|
143
|
-
case "goto": {
|
|
144
|
-
if (!action.path) {
|
|
145
|
-
throw new Error("Goto test action missing path");
|
|
146
|
-
}
|
|
147
|
-
const gotoUrl = new URL(action.path, config.baseUrl).toString();
|
|
148
|
-
const nowUrl = await adapter.getUrl();
|
|
149
|
-
if (toRelativePath(nowUrl) !== toRelativePath(gotoUrl)) {
|
|
150
|
-
await adapter.goto(gotoUrl, { waitUntil: "networkidle0" });
|
|
151
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
152
|
-
}
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
case "waitForLoadState":
|
|
156
|
-
await executeStoredAction(adapter, config, action.playwrightCode, action.path ?? undefined);
|
|
157
|
-
break;
|
|
158
|
-
case "click":
|
|
159
|
-
if (!action.path &&
|
|
160
|
-
!action.playwrightCode.includes("page.click(")) {
|
|
161
|
-
throw new Error(`Unsupported click action without selector for test case ${tc.id}`);
|
|
162
|
-
}
|
|
163
|
-
await executeStoredAction(adapter, config, action.playwrightCode, action.path ?? undefined);
|
|
164
|
-
break;
|
|
165
|
-
case "fill":
|
|
166
|
-
if (!action.path || action.value == null) {
|
|
167
|
-
throw new Error("Fill test action requires selector path and value");
|
|
168
|
-
}
|
|
169
|
-
await adapter.type(action.path, action.value);
|
|
170
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
171
|
-
break;
|
|
172
|
-
case "select":
|
|
173
|
-
case "selectOption":
|
|
174
|
-
if (!action.path || action.value == null) {
|
|
175
|
-
throw new Error("Select test action requires selector path and value");
|
|
176
|
-
}
|
|
177
|
-
await adapter.select(action.path, action.value);
|
|
178
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
179
|
-
break;
|
|
180
|
-
case "radio_select":
|
|
181
|
-
if (!action.path) {
|
|
182
|
-
throw new Error("Radio select test action requires selector path");
|
|
183
|
-
}
|
|
184
|
-
await adapter.click(action.path);
|
|
185
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
186
|
-
break;
|
|
187
|
-
case "hover":
|
|
188
|
-
if (!action.path) {
|
|
189
|
-
throw new Error("Hover test action requires selector path");
|
|
190
|
-
}
|
|
191
|
-
await adapter.hover(action.path);
|
|
192
|
-
await sleep(POST_ACTION_DELAY_MS);
|
|
193
|
-
break;
|
|
194
|
-
case "screenshot":
|
|
195
|
-
await executeStoredAction(adapter, config, action.playwrightCode, action.path ?? undefined);
|
|
196
|
-
break;
|
|
197
|
-
default:
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
const isNewPage = await captureCurrentPageState(config, adapter, api, testRun.id, events);
|
|
201
|
-
if (isNewPage) {
|
|
202
|
-
newJobsCreated = true;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const durationMs = Date.now() - startTime;
|
|
206
|
-
await api.completeTestCaseRun(testCaseRun.id, {
|
|
207
|
-
status: "completed",
|
|
208
|
-
durationMs,
|
|
209
|
-
});
|
|
210
|
-
await api.completeTestRun(testRun.id, { status: "completed" });
|
|
211
|
-
completedCaseIds.add(tc.id);
|
|
212
|
-
events.onTestRunCompleted({ testRunId: testRun.id, passed: true });
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
const durationMs = Date.now() - startTime;
|
|
216
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
217
|
-
LOG(`ERROR in test case ${tc.id} "${tc.title}":`, errorMessage);
|
|
218
|
-
if (error instanceof Error && error.stack) {
|
|
219
|
-
LOG(`Stack:`, error.stack);
|
|
220
|
-
}
|
|
221
|
-
await api.completeTestCaseRun(testCaseRun.id, {
|
|
222
|
-
status: "failed",
|
|
223
|
-
durationMs,
|
|
224
|
-
errorMessage,
|
|
225
|
-
});
|
|
226
|
-
await api.completeTestRun(testRun.id, { status: "failed" });
|
|
227
|
-
// Create finding for the error
|
|
228
|
-
await api.createTestRunFinding({
|
|
229
|
-
testCaseRunId: testCaseRun.id,
|
|
230
|
-
type: "error",
|
|
231
|
-
title: `Test failure: ${tc.title}`,
|
|
232
|
-
description: errorMessage,
|
|
233
|
-
});
|
|
234
|
-
events.onFindingCreated({
|
|
235
|
-
type: "error",
|
|
236
|
-
title: `Test failure: ${tc.title}`,
|
|
237
|
-
});
|
|
238
|
-
events.onTestRunCompleted({ testRunId: testRun.id, passed: false });
|
|
239
|
-
}
|
|
240
|
-
finally {
|
|
241
|
-
// Close any tabs/windows opened during this test case
|
|
242
|
-
if (adapter.closeOtherTabs) {
|
|
243
|
-
try {
|
|
244
|
-
await adapter.closeOtherTabs();
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
// Ignore cleanup errors
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return newJobsCreated;
|
|
253
|
-
}
|
|
254
|
-
//# sourceMappingURL=test-execution.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-execution.js","sourceRoot":"","sources":["../../src/orchestrator/test-execution.ts"],"names":[],"mappings":"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"}
|