@mechris3/glassbox 0.1.0
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/README.md +213 -0
- package/dist/bin/glassbox.d.ts +14 -0
- package/dist/bin/glassbox.d.ts.map +1 -0
- package/dist/bin/glassbox.js +140 -0
- package/dist/bin/glassbox.js.map +1 -0
- package/dist/src/adapters/base-adapter.d.ts +70 -0
- package/dist/src/adapters/base-adapter.d.ts.map +1 -0
- package/dist/src/adapters/base-adapter.js +155 -0
- package/dist/src/adapters/base-adapter.js.map +1 -0
- package/dist/src/adapters/browser-adapter.interface.d.ts +41 -0
- package/dist/src/adapters/browser-adapter.interface.d.ts.map +1 -0
- package/dist/src/adapters/browser-adapter.interface.js +7 -0
- package/dist/src/adapters/browser-adapter.interface.js.map +1 -0
- package/dist/src/adapters/cdp-adapter.d.ts +63 -0
- package/dist/src/adapters/cdp-adapter.d.ts.map +1 -0
- package/dist/src/adapters/cdp-adapter.js +231 -0
- package/dist/src/adapters/cdp-adapter.js.map +1 -0
- package/dist/src/ai/collectors.d.ts +35 -0
- package/dist/src/ai/collectors.d.ts.map +1 -0
- package/dist/src/ai/collectors.js +170 -0
- package/dist/src/ai/collectors.js.map +1 -0
- package/dist/src/ai/queries.d.ts +21 -0
- package/dist/src/ai/queries.d.ts.map +1 -0
- package/dist/src/ai/queries.js +59 -0
- package/dist/src/ai/queries.js.map +1 -0
- package/dist/src/ai/types.d.ts +55 -0
- package/dist/src/ai/types.d.ts.map +1 -0
- package/dist/src/ai/types.js +6 -0
- package/dist/src/ai/types.js.map +1 -0
- package/dist/src/cdp/connection.d.ts +37 -0
- package/dist/src/cdp/connection.d.ts.map +1 -0
- package/dist/src/cdp/connection.js +86 -0
- package/dist/src/cdp/connection.js.map +1 -0
- package/dist/src/cdp/connection.test.d.ts +6 -0
- package/dist/src/cdp/connection.test.d.ts.map +1 -0
- package/dist/src/cdp/connection.test.js +93 -0
- package/dist/src/cdp/connection.test.js.map +1 -0
- package/dist/src/cdp/domains.d.ts +116 -0
- package/dist/src/cdp/domains.d.ts.map +1 -0
- package/dist/src/cdp/domains.js +153 -0
- package/dist/src/cdp/domains.js.map +1 -0
- package/dist/src/cdp/launcher.d.ts +26 -0
- package/dist/src/cdp/launcher.d.ts.map +1 -0
- package/dist/src/cdp/launcher.js +175 -0
- package/dist/src/cdp/launcher.js.map +1 -0
- package/dist/src/config.d.ts +28 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +72 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/config.test.d.ts +5 -0
- package/dist/src/config.test.d.ts.map +1 -0
- package/dist/src/config.test.js +46 -0
- package/dist/src/config.test.js.map +1 -0
- package/dist/src/errors.d.ts +26 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +27 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +28 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/journey.d.ts +35 -0
- package/dist/src/journey.d.ts.map +1 -0
- package/dist/src/journey.js +39 -0
- package/dist/src/journey.js.map +1 -0
- package/dist/src/mcp/server.d.ts +22 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +229 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/page-objects/base.page.d.ts +28 -0
- package/dist/src/page-objects/base.page.d.ts.map +1 -0
- package/dist/src/page-objects/base.page.js +51 -0
- package/dist/src/page-objects/base.page.js.map +1 -0
- package/dist/src/page-objects/browser-context.page.d.ts +14 -0
- package/dist/src/page-objects/browser-context.page.d.ts.map +1 -0
- package/dist/src/page-objects/browser-context.page.js +28 -0
- package/dist/src/page-objects/browser-context.page.js.map +1 -0
- package/dist/src/runner/lifecycle-hooks.d.ts +43 -0
- package/dist/src/runner/lifecycle-hooks.d.ts.map +1 -0
- package/dist/src/runner/lifecycle-hooks.js +70 -0
- package/dist/src/runner/lifecycle-hooks.js.map +1 -0
- package/dist/src/runner/run-all-journeys.d.ts +35 -0
- package/dist/src/runner/run-all-journeys.d.ts.map +1 -0
- package/dist/src/runner/run-all-journeys.js +167 -0
- package/dist/src/runner/run-all-journeys.js.map +1 -0
- package/dist/src/runner/run-journey.d.ts +17 -0
- package/dist/src/runner/run-journey.d.ts.map +1 -0
- package/dist/src/runner/run-journey.js +179 -0
- package/dist/src/runner/run-journey.js.map +1 -0
- package/dist/src/runner/spawn-journey.d.ts +36 -0
- package/dist/src/runner/spawn-journey.d.ts.map +1 -0
- package/dist/src/runner/spawn-journey.js +40 -0
- package/dist/src/runner/spawn-journey.js.map +1 -0
- package/dist/src/server/diagnostic-service.d.ts +69 -0
- package/dist/src/server/diagnostic-service.d.ts.map +1 -0
- package/dist/src/server/diagnostic-service.js +165 -0
- package/dist/src/server/diagnostic-service.js.map +1 -0
- package/dist/src/server/diagnostic-service.test.d.ts +5 -0
- package/dist/src/server/diagnostic-service.test.d.ts.map +1 -0
- package/dist/src/server/diagnostic-service.test.js +82 -0
- package/dist/src/server/diagnostic-service.test.js.map +1 -0
- package/dist/src/server/index.d.ts +11 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +167 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/journey-discovery.d.ts +16 -0
- package/dist/src/server/journey-discovery.d.ts.map +1 -0
- package/dist/src/server/journey-discovery.js +38 -0
- package/dist/src/server/journey-discovery.js.map +1 -0
- package/dist/src/server/settings-storage.d.ts +27 -0
- package/dist/src/server/settings-storage.d.ts.map +1 -0
- package/dist/src/server/settings-storage.js +27 -0
- package/dist/src/server/settings-storage.js.map +1 -0
- package/dist/src/server/test-executor.d.ts +64 -0
- package/dist/src/server/test-executor.d.ts.map +1 -0
- package/dist/src/server/test-executor.js +279 -0
- package/dist/src/server/test-executor.js.map +1 -0
- package/dist/src/server/websocket.d.ts +51 -0
- package/dist/src/server/websocket.d.ts.map +1 -0
- package/dist/src/server/websocket.js +28 -0
- package/dist/src/server/websocket.js.map +1 -0
- package/dist/src/utils/browser-discovery.d.ts +11 -0
- package/dist/src/utils/browser-discovery.d.ts.map +1 -0
- package/dist/src/utils/browser-discovery.js +102 -0
- package/dist/src/utils/browser-discovery.js.map +1 -0
- package/dist/src/utils/error-formatter.d.ts +13 -0
- package/dist/src/utils/error-formatter.d.ts.map +1 -0
- package/dist/src/utils/error-formatter.js +29 -0
- package/dist/src/utils/error-formatter.js.map +1 -0
- package/dist/src/utils/escape.d.ts +10 -0
- package/dist/src/utils/escape.d.ts.map +1 -0
- package/dist/src/utils/escape.js +22 -0
- package/dist/src/utils/escape.js.map +1 -0
- package/dist/src/utils/escape.test.d.ts +5 -0
- package/dist/src/utils/escape.test.d.ts.map +1 -0
- package/dist/src/utils/escape.test.js +49 -0
- package/dist/src/utils/escape.test.js.map +1 -0
- package/dist/src/utils/page-object-error.d.ts +5 -0
- package/dist/src/utils/page-object-error.d.ts.map +1 -0
- package/dist/src/utils/page-object-error.js +22 -0
- package/dist/src/utils/page-object-error.js.map +1 -0
- package/dist/src/utils/profile-discovery.d.ts +20 -0
- package/dist/src/utils/profile-discovery.d.ts.map +1 -0
- package/dist/src/utils/profile-discovery.js +68 -0
- package/dist/src/utils/profile-discovery.js.map +1 -0
- package/dist/src/utils/wait-utils.d.ts +10 -0
- package/dist/src/utils/wait-utils.d.ts.map +1 -0
- package/dist/src/utils/wait-utils.js +20 -0
- package/dist/src/utils/wait-utils.js.map +1 -0
- package/dist/src/utils/wait-utils.test.d.ts +5 -0
- package/dist/src/utils/wait-utils.test.d.ts.map +1 -0
- package/dist/src/utils/wait-utils.test.js +30 -0
- package/dist/src/utils/wait-utils.test.js.map +1 -0
- package/package.json +60 -0
- package/src/server/static/index.html +541 -0
- package/ui/dist/3rdpartylicenses.txt +419 -0
- package/ui/dist/browser/assets/logo.svg +29 -0
- package/ui/dist/browser/index.html +13 -0
- package/ui/dist/browser/main-7OJWN7GZ.js +16 -0
- package/ui/dist/browser/polyfills-5CFQRCPP.js +2 -0
- package/ui/dist/browser/styles-HMZYQRBV.css +1 -0
- package/ui/dist/prerendered-routes.json +3 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestExecutor — orchestrates journey execution.
|
|
3
|
+
*
|
|
4
|
+
* Manages the browser lifecycle (launch, reuse, kill), spawns one child process
|
|
5
|
+
* per journey, streams output to connected dashboard clients via WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
import type { GlassboxConfig } from '../config.js';
|
|
8
|
+
import type { WebSocketManager } from './websocket.js';
|
|
9
|
+
import type { DiagnosticService } from './diagnostic-service.js';
|
|
10
|
+
export declare class TestExecutor {
|
|
11
|
+
private config;
|
|
12
|
+
private wsManager;
|
|
13
|
+
private diagnostics;
|
|
14
|
+
private currentProcess;
|
|
15
|
+
private browserInstance;
|
|
16
|
+
private browserLaunchConfig;
|
|
17
|
+
private breakpoints;
|
|
18
|
+
private running;
|
|
19
|
+
private aborted;
|
|
20
|
+
/** Whether a test run is currently in progress. */
|
|
21
|
+
get isRunning(): boolean;
|
|
22
|
+
constructor(config: GlassboxConfig, wsManager: WebSocketManager, diagnostics: DiagnosticService);
|
|
23
|
+
/**
|
|
24
|
+
* Run a set of journeys sequentially.
|
|
25
|
+
* Launches a browser if not already running, then spawns a child process per journey.
|
|
26
|
+
*/
|
|
27
|
+
run(journeys: string[], runConfig?: Record<string, unknown>): Promise<void>;
|
|
28
|
+
/** Stop the current run. Kills the running child process and aborts remaining journeys. */
|
|
29
|
+
stop(): void;
|
|
30
|
+
/** Pause execution via signal + stdin command to the child process. */
|
|
31
|
+
pause(): void;
|
|
32
|
+
/** Resume execution via signal + stdin command to the child process. */
|
|
33
|
+
resume(): void;
|
|
34
|
+
/** Step forward N actions, then re-pause. */
|
|
35
|
+
step(count?: number): void;
|
|
36
|
+
setBreakpoints(journey: string, breakpoints: number[]): void;
|
|
37
|
+
getBreakpoints(journey: string): number[];
|
|
38
|
+
clearBreakpoints(journey: string): void;
|
|
39
|
+
updateConfig(config: Record<string, unknown>): void;
|
|
40
|
+
/** Kill the browser process and clean up. */
|
|
41
|
+
shutdown(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Ensure a browser is launched and reachable.
|
|
44
|
+
* Reuses an existing instance if still running. If runtime settings differ
|
|
45
|
+
* from the current browser (e.g. headed vs headless), kills and relaunches.
|
|
46
|
+
*/
|
|
47
|
+
private ensureBrowser;
|
|
48
|
+
/** Extract the parent user data dir (without the profile subdirectory). */
|
|
49
|
+
private resolveUserDataDir;
|
|
50
|
+
/** Extract the profile directory name from a full profile path. */
|
|
51
|
+
private resolveProfileDirectory;
|
|
52
|
+
/** Auto-detect the first available Chromium browser. */
|
|
53
|
+
private autoDetectBrowser;
|
|
54
|
+
/** Check if the current browser instance is still reachable via its WebSocket endpoint. */
|
|
55
|
+
private isBrowserAlive;
|
|
56
|
+
/**
|
|
57
|
+
* Run a single journey in a child process.
|
|
58
|
+
* The runner connects to the shared browser via the WS endpoint.
|
|
59
|
+
*/
|
|
60
|
+
private runSingleJourney;
|
|
61
|
+
/** Send an IPC command to the running child process via stdin JSON. */
|
|
62
|
+
private sendCommand;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=test-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-executor.d.ts","sourceRoot":"","sources":["../../../src/server/test-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,qBAAa,YAAY;IAcrB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;IAfrB,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IAExB,mDAAmD;IACnD,IAAI,SAAS,IAAI,OAAO,CAEvB;gBAGS,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,gBAAgB,EAC3B,WAAW,EAAE,iBAAiB;IAGxC;;;OAGG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCjF,2FAA2F;IAC3F,IAAI,IAAI,IAAI;IAQZ,uEAAuE;IACvE,KAAK,IAAI,IAAI;IAOb,wEAAwE;IACxE,MAAM,IAAI,IAAI;IAOd,6CAA6C;IAC7C,IAAI,CAAC,KAAK,SAAI,GAAG,IAAI;IAIrB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI;IAK5D,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAIzC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKvC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAInD,6CAA6C;IACvC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B;;;;OAIG;YACW,aAAa;IAsD3B,2EAA2E;IAC3E,OAAO,CAAC,kBAAkB;IAY1B,mEAAmE;IACnE,OAAO,CAAC,uBAAuB;IAW/B,wDAAwD;IACxD,OAAO,CAAC,iBAAiB;IAKzB,2FAA2F;YAC7E,cAAc;IAW5B;;;OAGG;YACW,gBAAgB;IAuD9B,uEAAuE;IACvE,OAAO,CAAC,WAAW;CAKpB"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TestExecutor — orchestrates journey execution.
|
|
4
|
+
*
|
|
5
|
+
* Manages the browser lifecycle (launch, reuse, kill), spawns one child process
|
|
6
|
+
* per journey, streams output to connected dashboard clients via WebSocket.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.TestExecutor = void 0;
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const launcher_js_1 = require("../cdp/launcher.js");
|
|
12
|
+
const browser_discovery_js_1 = require("../utils/browser-discovery.js");
|
|
13
|
+
const spawn_journey_js_1 = require("../runner/spawn-journey.js");
|
|
14
|
+
class TestExecutor {
|
|
15
|
+
config;
|
|
16
|
+
wsManager;
|
|
17
|
+
diagnostics;
|
|
18
|
+
currentProcess = null;
|
|
19
|
+
browserInstance = null;
|
|
20
|
+
browserLaunchConfig = null;
|
|
21
|
+
breakpoints = new Map();
|
|
22
|
+
running = false;
|
|
23
|
+
aborted = false;
|
|
24
|
+
/** Whether a test run is currently in progress. */
|
|
25
|
+
get isRunning() {
|
|
26
|
+
return this.running;
|
|
27
|
+
}
|
|
28
|
+
constructor(config, wsManager, diagnostics) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.wsManager = wsManager;
|
|
31
|
+
this.diagnostics = diagnostics;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run a set of journeys sequentially.
|
|
35
|
+
* Launches a browser if not already running, then spawns a child process per journey.
|
|
36
|
+
*/
|
|
37
|
+
async run(journeys, runConfig) {
|
|
38
|
+
if (this.running)
|
|
39
|
+
return;
|
|
40
|
+
this.running = true;
|
|
41
|
+
this.aborted = false;
|
|
42
|
+
const results = [];
|
|
43
|
+
try {
|
|
44
|
+
// Ensure browser is available
|
|
45
|
+
await this.ensureBrowser(runConfig);
|
|
46
|
+
this.wsManager.broadcast({ type: 'run-start', journeys });
|
|
47
|
+
this.diagnostics.reset();
|
|
48
|
+
for (const journey of journeys) {
|
|
49
|
+
if (this.aborted) {
|
|
50
|
+
results.push({ journey, status: 'skipped' });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const status = await this.runSingleJourney(journey, runConfig);
|
|
54
|
+
results.push({ journey, status });
|
|
55
|
+
}
|
|
56
|
+
this.wsManager.broadcast({ type: 'run-end', results });
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
this.running = false;
|
|
60
|
+
const keepOpen = runConfig?.keepBrowserOpen ?? false;
|
|
61
|
+
const hasFailed = results.some((r) => r.status === 'failed');
|
|
62
|
+
if (hasFailed && this.browserInstance) {
|
|
63
|
+
// Keep browser alive on failure for post-mortem inspection via MCP
|
|
64
|
+
await this.diagnostics.setLiveSession(this.browserInstance.wsEndpoint);
|
|
65
|
+
}
|
|
66
|
+
else if (!keepOpen && this.browserInstance) {
|
|
67
|
+
this.diagnostics.closeLiveSession();
|
|
68
|
+
this.browserInstance.process.kill();
|
|
69
|
+
this.browserInstance = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Stop the current run. Kills the running child process and aborts remaining journeys. */
|
|
74
|
+
stop() {
|
|
75
|
+
this.aborted = true;
|
|
76
|
+
if (this.currentProcess) {
|
|
77
|
+
this.currentProcess.kill('SIGTERM');
|
|
78
|
+
this.currentProcess = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Pause execution via signal + stdin command to the child process. */
|
|
82
|
+
pause() {
|
|
83
|
+
if (this.currentProcess?.pid) {
|
|
84
|
+
this.currentProcess.kill('SIGUSR1');
|
|
85
|
+
}
|
|
86
|
+
this.sendCommand({ command: 'pause' });
|
|
87
|
+
}
|
|
88
|
+
/** Resume execution via signal + stdin command to the child process. */
|
|
89
|
+
resume() {
|
|
90
|
+
if (this.currentProcess?.pid) {
|
|
91
|
+
this.currentProcess.kill('SIGUSR2');
|
|
92
|
+
}
|
|
93
|
+
this.sendCommand({ command: 'resume' });
|
|
94
|
+
}
|
|
95
|
+
/** Step forward N actions, then re-pause. */
|
|
96
|
+
step(count = 1) {
|
|
97
|
+
this.sendCommand({ command: 'step', stepsRemaining: count });
|
|
98
|
+
}
|
|
99
|
+
setBreakpoints(journey, breakpoints) {
|
|
100
|
+
this.breakpoints.set(journey, breakpoints);
|
|
101
|
+
this.sendCommand({ command: 'config', breakpoints });
|
|
102
|
+
}
|
|
103
|
+
getBreakpoints(journey) {
|
|
104
|
+
return this.breakpoints.get(journey) ?? [];
|
|
105
|
+
}
|
|
106
|
+
clearBreakpoints(journey) {
|
|
107
|
+
this.breakpoints.delete(journey);
|
|
108
|
+
this.sendCommand({ command: 'config', breakpoints: [] });
|
|
109
|
+
}
|
|
110
|
+
updateConfig(config) {
|
|
111
|
+
this.sendCommand({ command: 'config', ...config });
|
|
112
|
+
}
|
|
113
|
+
/** Kill the browser process and clean up. */
|
|
114
|
+
async shutdown() {
|
|
115
|
+
this.stop();
|
|
116
|
+
if (this.browserInstance) {
|
|
117
|
+
this.browserInstance.process.kill();
|
|
118
|
+
this.browserInstance = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Ensure a browser is launched and reachable.
|
|
123
|
+
* Reuses an existing instance if still running. If runtime settings differ
|
|
124
|
+
* from the current browser (e.g. headed vs headless), kills and relaunches.
|
|
125
|
+
*/
|
|
126
|
+
async ensureBrowser(runConfig) {
|
|
127
|
+
const headless = runConfig?.headless ?? this.config.browser.headless;
|
|
128
|
+
const devtools = runConfig?.devtools ?? false;
|
|
129
|
+
const browserPath = runConfig?.browserPath
|
|
130
|
+
?? this.config.browser.executablePath
|
|
131
|
+
?? this.autoDetectBrowser();
|
|
132
|
+
const userDataDir = this.resolveUserDataDir(runConfig);
|
|
133
|
+
const profileDirectory = this.resolveProfileDirectory(runConfig);
|
|
134
|
+
// Create a fingerprint of the launch config to detect when we need to relaunch
|
|
135
|
+
const launchFingerprint = JSON.stringify({ browserPath, headless, devtools, userDataDir, profileDirectory });
|
|
136
|
+
// If browser is alive and config hasn't changed, reuse it
|
|
137
|
+
if (this.browserInstance && this.browserLaunchConfig === launchFingerprint) {
|
|
138
|
+
// Verify the endpoint is still reachable
|
|
139
|
+
const isAlive = await this.isBrowserAlive();
|
|
140
|
+
if (isAlive)
|
|
141
|
+
return;
|
|
142
|
+
// Browser died — clear and relaunch
|
|
143
|
+
this.browserInstance = null;
|
|
144
|
+
}
|
|
145
|
+
// Config changed or no browser — kill existing and relaunch
|
|
146
|
+
if (this.browserInstance && !this.browserInstance.process.killed) {
|
|
147
|
+
const proc = this.browserInstance.process;
|
|
148
|
+
this.browserInstance = null;
|
|
149
|
+
// If this is a real process we spawned, wait for it to exit
|
|
150
|
+
if (proc.pid) {
|
|
151
|
+
proc.kill();
|
|
152
|
+
await new Promise((resolve) => {
|
|
153
|
+
proc.on('exit', () => resolve());
|
|
154
|
+
proc.on('error', () => resolve());
|
|
155
|
+
// Safety: if exit never fires (fake process), resolve after a flush
|
|
156
|
+
setTimeout(() => resolve(), 0);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!browserPath) {
|
|
161
|
+
throw new Error('No browser found. Set browserPath in config or install Chrome/Brave/Edge.');
|
|
162
|
+
}
|
|
163
|
+
this.browserInstance = await (0, launcher_js_1.launchBrowser)({
|
|
164
|
+
browserPath,
|
|
165
|
+
headless,
|
|
166
|
+
devtools,
|
|
167
|
+
viewport: this.config.browser.defaultViewport,
|
|
168
|
+
userDataDir,
|
|
169
|
+
profileDirectory,
|
|
170
|
+
});
|
|
171
|
+
this.browserLaunchConfig = launchFingerprint;
|
|
172
|
+
}
|
|
173
|
+
/** Extract the parent user data dir (without the profile subdirectory). */
|
|
174
|
+
resolveUserDataDir(runConfig) {
|
|
175
|
+
const raw = runConfig?.userDataDir ?? this.config.browser.userDataDir;
|
|
176
|
+
if (!raw)
|
|
177
|
+
return undefined;
|
|
178
|
+
// If the path ends with a profile directory name (Default, Profile N), return the parent
|
|
179
|
+
const dirName = (0, path_1.basename)(raw);
|
|
180
|
+
if (dirName === 'Default' || dirName.startsWith('Profile ')) {
|
|
181
|
+
return (0, path_1.dirname)(raw);
|
|
182
|
+
}
|
|
183
|
+
return raw;
|
|
184
|
+
}
|
|
185
|
+
/** Extract the profile directory name from a full profile path. */
|
|
186
|
+
resolveProfileDirectory(runConfig) {
|
|
187
|
+
const raw = runConfig?.userDataDir ?? this.config.browser.userDataDir;
|
|
188
|
+
if (!raw)
|
|
189
|
+
return undefined;
|
|
190
|
+
const dirName = (0, path_1.basename)(raw);
|
|
191
|
+
if (dirName === 'Default' || dirName.startsWith('Profile ')) {
|
|
192
|
+
return dirName;
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
/** Auto-detect the first available Chromium browser. */
|
|
197
|
+
autoDetectBrowser() {
|
|
198
|
+
const browsers = (0, browser_discovery_js_1.discoverBrowsers)();
|
|
199
|
+
return browsers[0]?.executablePath;
|
|
200
|
+
}
|
|
201
|
+
/** Check if the current browser instance is still reachable via its WebSocket endpoint. */
|
|
202
|
+
async isBrowserAlive() {
|
|
203
|
+
if (!this.browserInstance)
|
|
204
|
+
return false;
|
|
205
|
+
try {
|
|
206
|
+
const port = new URL(this.browserInstance.wsEndpoint).port;
|
|
207
|
+
const response = await fetch(`http://127.0.0.1:${port}/json/version`, { signal: AbortSignal.timeout(1000) });
|
|
208
|
+
return response.ok;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Run a single journey in a child process.
|
|
216
|
+
* The runner connects to the shared browser via the WS endpoint.
|
|
217
|
+
*/
|
|
218
|
+
async runSingleJourney(journeyPath, runConfig) {
|
|
219
|
+
this.wsManager.broadcast({ type: 'test-start', journey: journeyPath });
|
|
220
|
+
const start = Date.now();
|
|
221
|
+
const spawned = (0, spawn_journey_js_1.spawnJourney)({
|
|
222
|
+
journeyPath: (0, path_1.resolve)(process.cwd(), journeyPath),
|
|
223
|
+
wsEndpoint: this.browserInstance.wsEndpoint,
|
|
224
|
+
targetUrl: runConfig?.targetUrl ?? '',
|
|
225
|
+
viewportWidth: runConfig?.viewportWidth ?? this.config.browser.defaultViewport.width,
|
|
226
|
+
viewportHeight: runConfig?.viewportHeight ?? this.config.browser.defaultViewport.height,
|
|
227
|
+
actionDelay: runConfig?.actionDelay ?? 0,
|
|
228
|
+
breakpoints: this.breakpoints.get(journeyPath) ?? [],
|
|
229
|
+
});
|
|
230
|
+
this.currentProcess = spawned.process;
|
|
231
|
+
spawned.process.stdout?.on('data', (chunk) => {
|
|
232
|
+
const lines = chunk.toString().split('\n');
|
|
233
|
+
for (const line of lines) {
|
|
234
|
+
if (!line.trim())
|
|
235
|
+
continue;
|
|
236
|
+
try {
|
|
237
|
+
const parsed = JSON.parse(line);
|
|
238
|
+
if (parsed.type === 'diagnostics' && parsed.data) {
|
|
239
|
+
this.diagnostics.ingestRunnerData(parsed.data);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch { /* not JSON, treat as log */ }
|
|
244
|
+
this.wsManager.broadcast({ type: 'log', message: line, journey: journeyPath });
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
spawned.process.stderr?.on('data', (chunk) => {
|
|
248
|
+
const lines = chunk.toString().split('\n');
|
|
249
|
+
for (const line of lines) {
|
|
250
|
+
if (line.startsWith('[JSON]')) {
|
|
251
|
+
try {
|
|
252
|
+
const json = JSON.parse(line.slice(6));
|
|
253
|
+
this.wsManager.broadcast(json);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
this.wsManager.broadcast({ type: 'error', message: line, journey: journeyPath });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else if (line.trim()) {
|
|
260
|
+
this.wsManager.broadcast({ type: 'error', message: line, journey: journeyPath });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
const code = await spawned.exitCode;
|
|
265
|
+
const duration = `${((Date.now() - start) / 1000).toFixed(2)}s`;
|
|
266
|
+
const status = code === 0 ? 'passed' : 'failed';
|
|
267
|
+
this.wsManager.broadcast({ type: 'test-end', journey: journeyPath, status, duration });
|
|
268
|
+
this.currentProcess = null;
|
|
269
|
+
return status;
|
|
270
|
+
}
|
|
271
|
+
/** Send an IPC command to the running child process via stdin JSON. */
|
|
272
|
+
sendCommand(cmd) {
|
|
273
|
+
if (this.currentProcess?.stdin?.writable) {
|
|
274
|
+
this.currentProcess.stdin.write(JSON.stringify(cmd) + '\n');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.TestExecutor = TestExecutor;
|
|
279
|
+
//# sourceMappingURL=test-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-executor.js","sourceRoot":"","sources":["../../../src/server/test-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket manager — broadcasts typed messages to all connected dashboard clients.
|
|
3
|
+
*/
|
|
4
|
+
import type { Server } from 'http';
|
|
5
|
+
export type WSMessage = {
|
|
6
|
+
type: 'run-start';
|
|
7
|
+
journeys: string[];
|
|
8
|
+
} | {
|
|
9
|
+
type: 'run-end';
|
|
10
|
+
results: Array<{
|
|
11
|
+
journey: string;
|
|
12
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
13
|
+
}>;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'test-start';
|
|
16
|
+
journey: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'test-end';
|
|
19
|
+
journey: string;
|
|
20
|
+
status: 'passed' | 'failed';
|
|
21
|
+
duration: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: 'log';
|
|
24
|
+
message: string;
|
|
25
|
+
journey?: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'error';
|
|
28
|
+
message: string;
|
|
29
|
+
journey?: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'journeys';
|
|
32
|
+
journeys: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
}>;
|
|
36
|
+
} | {
|
|
37
|
+
type: 'action';
|
|
38
|
+
index: number;
|
|
39
|
+
status: 'start' | 'complete' | 'breakpoint';
|
|
40
|
+
description?: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'ui-control';
|
|
43
|
+
action: 'pause' | 'resume';
|
|
44
|
+
};
|
|
45
|
+
export declare class WebSocketManager {
|
|
46
|
+
private wss;
|
|
47
|
+
private clients;
|
|
48
|
+
constructor(server: Server);
|
|
49
|
+
broadcast(message: WSMessage): void;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;KAAE,CAAC,CAAA;CAAE,GACjG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,YAAY,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACpG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAA;CAAE,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,OAAO,CAAwB;gBAE3B,MAAM,EAAE,MAAM;IAS1B,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;CAQpC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WebSocket manager — broadcasts typed messages to all connected dashboard clients.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WebSocketManager = void 0;
|
|
7
|
+
const ws_1 = require("ws");
|
|
8
|
+
class WebSocketManager {
|
|
9
|
+
wss;
|
|
10
|
+
clients = new Set();
|
|
11
|
+
constructor(server) {
|
|
12
|
+
this.wss = new ws_1.WebSocketServer({ server });
|
|
13
|
+
this.wss.on('connection', (ws) => {
|
|
14
|
+
this.clients.add(ws);
|
|
15
|
+
ws.on('close', () => this.clients.delete(ws));
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
broadcast(message) {
|
|
19
|
+
const data = JSON.stringify(message);
|
|
20
|
+
for (const client of this.clients) {
|
|
21
|
+
if (client.readyState === 1) {
|
|
22
|
+
client.send(data);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.WebSocketManager = WebSocketManager;
|
|
28
|
+
//# sourceMappingURL=websocket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,2BAAqD;AAcrD,MAAa,gBAAgB;IACnB,GAAG,CAAkB;IACrB,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;IAEvC,YAAY,MAAc;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,oBAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAE3C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE;YAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrB,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,CAAC,OAAkB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AArBD,4CAqBC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform browser auto-discovery.
|
|
3
|
+
* Detects Chromium-based browsers on macOS, Windows, and Linux.
|
|
4
|
+
*/
|
|
5
|
+
export interface DiscoveredBrowser {
|
|
6
|
+
name: string;
|
|
7
|
+
executablePath: string;
|
|
8
|
+
userDataDir: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function discoverBrowsers(): DiscoveredBrowser[];
|
|
11
|
+
//# sourceMappingURL=browser-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-discovery.d.ts","sourceRoot":"","sources":["../../../src/utils/browser-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,IAAI,iBAAiB,EAAE,CAatD"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-platform browser auto-discovery.
|
|
4
|
+
* Detects Chromium-based browsers on macOS, Windows, and Linux.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.discoverBrowsers = discoverBrowsers;
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
function discoverBrowsers() {
|
|
12
|
+
const os = (0, os_1.platform)();
|
|
13
|
+
const browsers = [];
|
|
14
|
+
if (os === 'darwin') {
|
|
15
|
+
browsers.push(...discoverMacOS());
|
|
16
|
+
}
|
|
17
|
+
else if (os === 'win32') {
|
|
18
|
+
browsers.push(...discoverWindows());
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
browsers.push(...discoverLinux());
|
|
22
|
+
}
|
|
23
|
+
return browsers.filter((b) => (0, fs_1.existsSync)(b.executablePath));
|
|
24
|
+
}
|
|
25
|
+
function discoverMacOS() {
|
|
26
|
+
const home = process.env.HOME ?? '';
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
name: 'Google Chrome',
|
|
30
|
+
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
31
|
+
userDataDir: (0, path_1.join)(home, 'Library/Application Support/Google/Chrome'),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'Brave Browser',
|
|
35
|
+
executablePath: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser',
|
|
36
|
+
userDataDir: (0, path_1.join)(home, 'Library/Application Support/BraveSoftware/Brave-Browser'),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Microsoft Edge',
|
|
40
|
+
executablePath: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
41
|
+
userDataDir: (0, path_1.join)(home, 'Library/Application Support/Microsoft Edge'),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Chromium',
|
|
45
|
+
executablePath: '/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
46
|
+
userDataDir: (0, path_1.join)(home, 'Library/Application Support/Chromium'),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
function discoverWindows() {
|
|
51
|
+
const programFiles = process.env['ProgramFiles'] ?? 'C:\\Program Files';
|
|
52
|
+
const programFilesX86 = process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)';
|
|
53
|
+
const localAppData = process.env.LOCALAPPDATA ?? '';
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
name: 'Google Chrome',
|
|
57
|
+
executablePath: (0, path_1.join)(programFiles, 'Google/Chrome/Application/chrome.exe'),
|
|
58
|
+
userDataDir: (0, path_1.join)(localAppData, 'Google/Chrome/User Data'),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'Google Chrome (x86)',
|
|
62
|
+
executablePath: (0, path_1.join)(programFilesX86, 'Google/Chrome/Application/chrome.exe'),
|
|
63
|
+
userDataDir: (0, path_1.join)(localAppData, 'Google/Chrome/User Data'),
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Brave Browser',
|
|
67
|
+
executablePath: (0, path_1.join)(programFiles, 'BraveSoftware/Brave-Browser/Application/brave.exe'),
|
|
68
|
+
userDataDir: (0, path_1.join)(localAppData, 'BraveSoftware/Brave-Browser/User Data'),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Microsoft Edge',
|
|
72
|
+
executablePath: (0, path_1.join)(programFiles, 'Microsoft/Edge/Application/msedge.exe'),
|
|
73
|
+
userDataDir: (0, path_1.join)(localAppData, 'Microsoft/Edge/User Data'),
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
function discoverLinux() {
|
|
78
|
+
const home = process.env.HOME ?? '';
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
name: 'Google Chrome',
|
|
82
|
+
executablePath: '/usr/bin/google-chrome',
|
|
83
|
+
userDataDir: (0, path_1.join)(home, '.config/google-chrome'),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Brave Browser',
|
|
87
|
+
executablePath: '/usr/bin/brave-browser',
|
|
88
|
+
userDataDir: (0, path_1.join)(home, '.config/BraveSoftware/Brave-Browser'),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Chromium',
|
|
92
|
+
executablePath: '/usr/bin/chromium-browser',
|
|
93
|
+
userDataDir: (0, path_1.join)(home, '.config/chromium'),
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'Microsoft Edge',
|
|
97
|
+
executablePath: '/usr/bin/microsoft-edge',
|
|
98
|
+
userDataDir: (0, path_1.join)(home, '.config/microsoft-edge'),
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=browser-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-discovery.js","sourceRoot":"","sources":["../../../src/utils/browser-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error formatting for test failures.
|
|
3
|
+
*/
|
|
4
|
+
export interface FormattedError {
|
|
5
|
+
header: string;
|
|
6
|
+
applicationStack: string[];
|
|
7
|
+
pageObject?: string;
|
|
8
|
+
journeyStep?: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function formatTestError(error: Error, journeyName: string, duration?: string): FormattedError;
|
|
12
|
+
export declare function getErrorSummary(error: Error, journeyName: string): string;
|
|
13
|
+
//# sourceMappingURL=error-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-formatter.d.ts","sourceRoot":"","sources":["../../../src/utils/error-formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAsBpG;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Structured error formatting for test failures.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatTestError = formatTestError;
|
|
7
|
+
exports.getErrorSummary = getErrorSummary;
|
|
8
|
+
function formatTestError(error, journeyName, duration) {
|
|
9
|
+
const timestamp = new Date().toISOString();
|
|
10
|
+
const stack = error.stack ?? '';
|
|
11
|
+
const applicationStack = stack
|
|
12
|
+
.split('\n')
|
|
13
|
+
.filter((line) => !line.includes('node_modules'))
|
|
14
|
+
.filter((line) => line.trim().startsWith('at '));
|
|
15
|
+
const pageObject = applicationStack.find((line) => line.includes('.page.'))?.trim();
|
|
16
|
+
const journeyStep = applicationStack.find((line) => line.includes('.journey.'))?.trim();
|
|
17
|
+
const header = [
|
|
18
|
+
`Journey: ${journeyName}`,
|
|
19
|
+
`Time: ${timestamp}`,
|
|
20
|
+
duration ? `Duration: ${duration}` : '',
|
|
21
|
+
`Error: ${error.message}`,
|
|
22
|
+
].filter(Boolean).join('\n');
|
|
23
|
+
const summary = getErrorSummary(error, journeyName);
|
|
24
|
+
return { header, applicationStack, pageObject, journeyStep, summary };
|
|
25
|
+
}
|
|
26
|
+
function getErrorSummary(error, journeyName) {
|
|
27
|
+
return `${journeyName}: ${error.message.split('\n')[0]}`;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=error-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-formatter.js","sourceRoot":"","sources":["../../../src/utils/error-formatter.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAUH,0CAsBC;AAED,0CAEC;AA1BD,SAAgB,eAAe,CAAC,KAAY,EAAE,WAAmB,EAAE,QAAiB;IAClF,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;IAEhC,MAAM,gBAAgB,GAAG,KAAK;SAC3B,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;SAChD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnD,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACpF,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAExF,MAAM,MAAM,GAAG;QACb,YAAY,WAAW,EAAE;QACzB,SAAS,SAAS,EAAE;QACpB,QAAQ,CAAC,CAAC,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;QACvC,UAAU,KAAK,CAAC,OAAO,EAAE;KAC1B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAEpD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AACxE,CAAC;AAED,SAAgB,eAAe,CAAC,KAAY,EAAE,WAAmB;IAC/D,OAAO,GAAG,WAAW,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape utilities for safely interpolating values into JavaScript strings
|
|
3
|
+
* evaluated via CDP's Runtime.evaluate.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Escape a string for safe interpolation into a single-quoted JS string.
|
|
7
|
+
* Handles quotes, backslashes, newlines, null bytes, and Unicode line/paragraph separators.
|
|
8
|
+
*/
|
|
9
|
+
export declare function escapeJS(str: string): string;
|
|
10
|
+
//# sourceMappingURL=escape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../../src/utils/escape.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS5C"}
|