@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.
Files changed (162) hide show
  1. package/README.md +213 -0
  2. package/dist/bin/glassbox.d.ts +14 -0
  3. package/dist/bin/glassbox.d.ts.map +1 -0
  4. package/dist/bin/glassbox.js +140 -0
  5. package/dist/bin/glassbox.js.map +1 -0
  6. package/dist/src/adapters/base-adapter.d.ts +70 -0
  7. package/dist/src/adapters/base-adapter.d.ts.map +1 -0
  8. package/dist/src/adapters/base-adapter.js +155 -0
  9. package/dist/src/adapters/base-adapter.js.map +1 -0
  10. package/dist/src/adapters/browser-adapter.interface.d.ts +41 -0
  11. package/dist/src/adapters/browser-adapter.interface.d.ts.map +1 -0
  12. package/dist/src/adapters/browser-adapter.interface.js +7 -0
  13. package/dist/src/adapters/browser-adapter.interface.js.map +1 -0
  14. package/dist/src/adapters/cdp-adapter.d.ts +63 -0
  15. package/dist/src/adapters/cdp-adapter.d.ts.map +1 -0
  16. package/dist/src/adapters/cdp-adapter.js +231 -0
  17. package/dist/src/adapters/cdp-adapter.js.map +1 -0
  18. package/dist/src/ai/collectors.d.ts +35 -0
  19. package/dist/src/ai/collectors.d.ts.map +1 -0
  20. package/dist/src/ai/collectors.js +170 -0
  21. package/dist/src/ai/collectors.js.map +1 -0
  22. package/dist/src/ai/queries.d.ts +21 -0
  23. package/dist/src/ai/queries.d.ts.map +1 -0
  24. package/dist/src/ai/queries.js +59 -0
  25. package/dist/src/ai/queries.js.map +1 -0
  26. package/dist/src/ai/types.d.ts +55 -0
  27. package/dist/src/ai/types.d.ts.map +1 -0
  28. package/dist/src/ai/types.js +6 -0
  29. package/dist/src/ai/types.js.map +1 -0
  30. package/dist/src/cdp/connection.d.ts +37 -0
  31. package/dist/src/cdp/connection.d.ts.map +1 -0
  32. package/dist/src/cdp/connection.js +86 -0
  33. package/dist/src/cdp/connection.js.map +1 -0
  34. package/dist/src/cdp/connection.test.d.ts +6 -0
  35. package/dist/src/cdp/connection.test.d.ts.map +1 -0
  36. package/dist/src/cdp/connection.test.js +93 -0
  37. package/dist/src/cdp/connection.test.js.map +1 -0
  38. package/dist/src/cdp/domains.d.ts +116 -0
  39. package/dist/src/cdp/domains.d.ts.map +1 -0
  40. package/dist/src/cdp/domains.js +153 -0
  41. package/dist/src/cdp/domains.js.map +1 -0
  42. package/dist/src/cdp/launcher.d.ts +26 -0
  43. package/dist/src/cdp/launcher.d.ts.map +1 -0
  44. package/dist/src/cdp/launcher.js +175 -0
  45. package/dist/src/cdp/launcher.js.map +1 -0
  46. package/dist/src/config.d.ts +28 -0
  47. package/dist/src/config.d.ts.map +1 -0
  48. package/dist/src/config.js +72 -0
  49. package/dist/src/config.js.map +1 -0
  50. package/dist/src/config.test.d.ts +5 -0
  51. package/dist/src/config.test.d.ts.map +1 -0
  52. package/dist/src/config.test.js +46 -0
  53. package/dist/src/config.test.js.map +1 -0
  54. package/dist/src/errors.d.ts +26 -0
  55. package/dist/src/errors.d.ts.map +1 -0
  56. package/dist/src/errors.js +27 -0
  57. package/dist/src/errors.js.map +1 -0
  58. package/dist/src/index.d.ts +18 -0
  59. package/dist/src/index.d.ts.map +1 -0
  60. package/dist/src/index.js +28 -0
  61. package/dist/src/index.js.map +1 -0
  62. package/dist/src/journey.d.ts +35 -0
  63. package/dist/src/journey.d.ts.map +1 -0
  64. package/dist/src/journey.js +39 -0
  65. package/dist/src/journey.js.map +1 -0
  66. package/dist/src/mcp/server.d.ts +22 -0
  67. package/dist/src/mcp/server.d.ts.map +1 -0
  68. package/dist/src/mcp/server.js +229 -0
  69. package/dist/src/mcp/server.js.map +1 -0
  70. package/dist/src/page-objects/base.page.d.ts +28 -0
  71. package/dist/src/page-objects/base.page.d.ts.map +1 -0
  72. package/dist/src/page-objects/base.page.js +51 -0
  73. package/dist/src/page-objects/base.page.js.map +1 -0
  74. package/dist/src/page-objects/browser-context.page.d.ts +14 -0
  75. package/dist/src/page-objects/browser-context.page.d.ts.map +1 -0
  76. package/dist/src/page-objects/browser-context.page.js +28 -0
  77. package/dist/src/page-objects/browser-context.page.js.map +1 -0
  78. package/dist/src/runner/lifecycle-hooks.d.ts +43 -0
  79. package/dist/src/runner/lifecycle-hooks.d.ts.map +1 -0
  80. package/dist/src/runner/lifecycle-hooks.js +70 -0
  81. package/dist/src/runner/lifecycle-hooks.js.map +1 -0
  82. package/dist/src/runner/run-all-journeys.d.ts +35 -0
  83. package/dist/src/runner/run-all-journeys.d.ts.map +1 -0
  84. package/dist/src/runner/run-all-journeys.js +167 -0
  85. package/dist/src/runner/run-all-journeys.js.map +1 -0
  86. package/dist/src/runner/run-journey.d.ts +17 -0
  87. package/dist/src/runner/run-journey.d.ts.map +1 -0
  88. package/dist/src/runner/run-journey.js +179 -0
  89. package/dist/src/runner/run-journey.js.map +1 -0
  90. package/dist/src/runner/spawn-journey.d.ts +36 -0
  91. package/dist/src/runner/spawn-journey.d.ts.map +1 -0
  92. package/dist/src/runner/spawn-journey.js +40 -0
  93. package/dist/src/runner/spawn-journey.js.map +1 -0
  94. package/dist/src/server/diagnostic-service.d.ts +69 -0
  95. package/dist/src/server/diagnostic-service.d.ts.map +1 -0
  96. package/dist/src/server/diagnostic-service.js +165 -0
  97. package/dist/src/server/diagnostic-service.js.map +1 -0
  98. package/dist/src/server/diagnostic-service.test.d.ts +5 -0
  99. package/dist/src/server/diagnostic-service.test.d.ts.map +1 -0
  100. package/dist/src/server/diagnostic-service.test.js +82 -0
  101. package/dist/src/server/diagnostic-service.test.js.map +1 -0
  102. package/dist/src/server/index.d.ts +11 -0
  103. package/dist/src/server/index.d.ts.map +1 -0
  104. package/dist/src/server/index.js +167 -0
  105. package/dist/src/server/index.js.map +1 -0
  106. package/dist/src/server/journey-discovery.d.ts +16 -0
  107. package/dist/src/server/journey-discovery.d.ts.map +1 -0
  108. package/dist/src/server/journey-discovery.js +38 -0
  109. package/dist/src/server/journey-discovery.js.map +1 -0
  110. package/dist/src/server/settings-storage.d.ts +27 -0
  111. package/dist/src/server/settings-storage.d.ts.map +1 -0
  112. package/dist/src/server/settings-storage.js +27 -0
  113. package/dist/src/server/settings-storage.js.map +1 -0
  114. package/dist/src/server/test-executor.d.ts +64 -0
  115. package/dist/src/server/test-executor.d.ts.map +1 -0
  116. package/dist/src/server/test-executor.js +279 -0
  117. package/dist/src/server/test-executor.js.map +1 -0
  118. package/dist/src/server/websocket.d.ts +51 -0
  119. package/dist/src/server/websocket.d.ts.map +1 -0
  120. package/dist/src/server/websocket.js +28 -0
  121. package/dist/src/server/websocket.js.map +1 -0
  122. package/dist/src/utils/browser-discovery.d.ts +11 -0
  123. package/dist/src/utils/browser-discovery.d.ts.map +1 -0
  124. package/dist/src/utils/browser-discovery.js +102 -0
  125. package/dist/src/utils/browser-discovery.js.map +1 -0
  126. package/dist/src/utils/error-formatter.d.ts +13 -0
  127. package/dist/src/utils/error-formatter.d.ts.map +1 -0
  128. package/dist/src/utils/error-formatter.js +29 -0
  129. package/dist/src/utils/error-formatter.js.map +1 -0
  130. package/dist/src/utils/escape.d.ts +10 -0
  131. package/dist/src/utils/escape.d.ts.map +1 -0
  132. package/dist/src/utils/escape.js +22 -0
  133. package/dist/src/utils/escape.js.map +1 -0
  134. package/dist/src/utils/escape.test.d.ts +5 -0
  135. package/dist/src/utils/escape.test.d.ts.map +1 -0
  136. package/dist/src/utils/escape.test.js +49 -0
  137. package/dist/src/utils/escape.test.js.map +1 -0
  138. package/dist/src/utils/page-object-error.d.ts +5 -0
  139. package/dist/src/utils/page-object-error.d.ts.map +1 -0
  140. package/dist/src/utils/page-object-error.js +22 -0
  141. package/dist/src/utils/page-object-error.js.map +1 -0
  142. package/dist/src/utils/profile-discovery.d.ts +20 -0
  143. package/dist/src/utils/profile-discovery.d.ts.map +1 -0
  144. package/dist/src/utils/profile-discovery.js +68 -0
  145. package/dist/src/utils/profile-discovery.js.map +1 -0
  146. package/dist/src/utils/wait-utils.d.ts +10 -0
  147. package/dist/src/utils/wait-utils.d.ts.map +1 -0
  148. package/dist/src/utils/wait-utils.js +20 -0
  149. package/dist/src/utils/wait-utils.js.map +1 -0
  150. package/dist/src/utils/wait-utils.test.d.ts +5 -0
  151. package/dist/src/utils/wait-utils.test.d.ts.map +1 -0
  152. package/dist/src/utils/wait-utils.test.js +30 -0
  153. package/dist/src/utils/wait-utils.test.js.map +1 -0
  154. package/package.json +60 -0
  155. package/src/server/static/index.html +541 -0
  156. package/ui/dist/3rdpartylicenses.txt +419 -0
  157. package/ui/dist/browser/assets/logo.svg +29 -0
  158. package/ui/dist/browser/index.html +13 -0
  159. package/ui/dist/browser/main-7OJWN7GZ.js +16 -0
  160. package/ui/dist/browser/polyfills-5CFQRCPP.js +2 -0
  161. package/ui/dist/browser/styles-HMZYQRBV.css +1 -0
  162. package/ui/dist/prerendered-routes.json +3 -0
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # @mechris3/glassbox
2
+
3
+ Debugger-style browser automation test runner using Chrome DevTools Protocol (CDP) directly. No Puppeteer, no Playwright — just raw WebSocket + JSON.
4
+
5
+ Features:
6
+ - Live execution control: breakpoints, pause/resume, step-through
7
+ - Visual dashboard with real-time action streaming
8
+ - Headless batch runner for CI
9
+ - Diagnostic data collection (console errors, network, performance)
10
+ - MCP server for AI agent integration
11
+ - Browser and profile auto-detection
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Install
17
+ npm install @mechris3/glassbox
18
+
19
+ # Scaffold a project (creates glassbox.config.ts + directories)
20
+ npx glassbox init
21
+
22
+ # Write journeys and page objects (see below), then:
23
+ npx glassbox serve # Dashboard UI at http://localhost:3001
24
+ npx glassbox run # Headless batch run (for CI)
25
+ ```
26
+
27
+ `glassbox init` creates this structure in your current directory:
28
+
29
+ ```
30
+ my-tests/
31
+ ├── glassbox.config.ts ← created by init
32
+ ├── journeys/ ← put your journey files here
33
+ └── page-objects/ ← put your page objects here
34
+ ```
35
+
36
+ You can set this up as a standalone project or as a subfolder within an existing frontend project:
37
+
38
+ ```
39
+ # Standalone
40
+ my-e2e-tests/
41
+ ├── package.json
42
+ ├── glassbox.config.ts
43
+ ├── journeys/
44
+ └── page-objects/
45
+
46
+ # Inside an existing project
47
+ my-app/
48
+ ├── src/
49
+ ├── package.json
50
+ └── e2e/
51
+ ├── glassbox.config.ts
52
+ ├── journeys/
53
+ └── page-objects/
54
+ ```
55
+
56
+ Either way, run `glassbox` commands from the directory containing your `glassbox.config.ts`.
57
+
58
+ ## Prerequisites
59
+
60
+ - Node.js 20+
61
+ - A Chromium-based browser (Chrome, Brave, Edge)
62
+
63
+ ## Consumer Usage
64
+
65
+ ### Page Objects
66
+
67
+ Extend `BasePage` — no constructor needed:
68
+
69
+ ```typescript
70
+ // page-objects/login.page.ts
71
+ import { BasePage } from '@mechris3/glassbox';
72
+
73
+ export class LoginPage extends BasePage {
74
+ private selectors = {
75
+ username: '[data-testid="username"]',
76
+ password: '[data-testid="password"]',
77
+ submit: '[data-testid="submit"]',
78
+ };
79
+
80
+ async login(user: string, pass: string) {
81
+ await this.fill(this.selectors.username, user);
82
+ await this.fill(this.selectors.password, pass);
83
+ await this.click(this.selectors.submit);
84
+ }
85
+
86
+ async verifyLoggedIn(expectedName: string) {
87
+ const name = await this.getText('[data-testid="display-name"]');
88
+ if (name !== expectedName) throw new Error(`Expected "${expectedName}", got "${name}"`);
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### Journeys
94
+
95
+ Extend `Journey` — use `this.page()` to create page objects:
96
+
97
+ ```typescript
98
+ // journeys/login.journey.ts
99
+ import { Journey } from '@mechris3/glassbox';
100
+ import { LoginPage } from '../page-objects/login.page';
101
+
102
+ export class LoginJourney extends Journey {
103
+ loginPage = this.page(LoginPage);
104
+
105
+ async execute() {
106
+ await this.loginPage.login('testuser', 'password123');
107
+ await this.loginPage.verifyLoggedIn('testuser');
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Config
113
+
114
+ All paths in the config are relative to the config file's directory:
115
+
116
+ ```
117
+ my-tests/
118
+ ├── glassbox.config.ts
119
+ ├── journeys/
120
+ │ └── login.journey.ts
121
+ ├── page-objects/
122
+ │ └── login.page.ts
123
+ └── helpers/
124
+ └── before-each.ts
125
+ ```
126
+
127
+ ```typescript
128
+ // glassbox.config.ts
129
+ import { defineConfig } from '@mechris3/glassbox';
130
+
131
+ export default defineConfig({
132
+ journeys: './journeys/**/*.journey.ts',
133
+ browser: {
134
+ defaultViewport: { width: 1280, height: 720 },
135
+ headless: false,
136
+ },
137
+ server: { port: 3001 },
138
+ testData: {
139
+ beforeEach: './helpers/before-each.ts',
140
+ },
141
+ });
142
+ ```
143
+
144
+ ## CLI Commands
145
+
146
+ Run all commands from the directory containing your `glassbox.config.ts`:
147
+
148
+ ```bash
149
+ cd my-tests/ # where your glassbox.config.ts lives
150
+ ```
151
+
152
+ **Dashboard (visual UI):**
153
+ ```bash
154
+ npx glassbox serve # Start dashboard at http://localhost:3001
155
+ ```
156
+ Open the URL in your browser to see journeys, run them, set breakpoints, pause/step, and inspect results visually.
157
+
158
+ **Headless runner (CI / terminal):**
159
+ ```bash
160
+ npx glassbox run # Run all journeys, exit 0/1
161
+ npx glassbox run login # Only journeys matching "login"
162
+ npx glassbox run --url http://localhost:3000 # Specify app URL
163
+ npx glassbox run --headed # Show the browser while running
164
+ npx glassbox run --no-fail-fast # Don't stop at first failure
165
+ ```
166
+
167
+ **Other:**
168
+ ```bash
169
+ npx glassbox init # Scaffold config + directories in current dir
170
+ npx glassbox mcp # Start MCP server for AI agent integration
171
+ ```
172
+
173
+ ## MCP Server (AI Integration)
174
+
175
+ The MCP server lets AI agents (Kiro, Claude) debug failed journeys by querying diagnostic data.
176
+
177
+ Add to your `.kiro/settings/mcp.json`:
178
+
179
+ ```json
180
+ {
181
+ "mcpServers": {
182
+ "glassbox": {
183
+ "command": "npx",
184
+ "args": ["glassbox", "mcp"],
185
+ "env": { "GLASSBOX_URL": "http://localhost:3001" }
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ Requires `glassbox serve` to be running. The AI gets these tools:
192
+
193
+ | Tool | Purpose |
194
+ |------|---------|
195
+ | `getJourneyStatus` | Summary of diagnostic counts (call first) |
196
+ | `getConsoleErrors` | console.error/warn with stack traces |
197
+ | `getExceptions` | Unhandled JS exceptions with source locations |
198
+ | `getNetworkFailures` | Failed HTTP requests (4xx/5xx/network errors) |
199
+ | `getNetworkLog` | All XHR/Fetch requests with status codes |
200
+ | `getTimeline` | Chronological event stream |
201
+ | `getPerformanceMetrics` | Heap size, DOM nodes, layout recalculations |
202
+ | `listJourneys` | Available journey files |
203
+ | `runJourney` | Run by name/ID (browser stays open on failure) |
204
+ | `getDomSnapshot` | Inspect page HTML or a specific element |
205
+ | `getScreenshot` | Capture page screenshot (base64 PNG) |
206
+ | `getAccessibilityTree` | Full ARIA tree for understanding page structure |
207
+ | `resetDiagnostics` | Clear data + close live session before re-run |
208
+
209
+ The AI can identify journeys by name (`"login"`), ID (`"login-and-add-todos"`), or full path. After a failure, the browser stays open so `getDomSnapshot` and `getScreenshot` can inspect the failed state.
210
+
211
+ ## License
212
+
213
+ Proprietary. All rights reserved.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Glassbox CLI entry point.
4
+ *
5
+ * Commands:
6
+ * serve (default) — Start the dashboard server with REST API + WebSocket
7
+ * run [journeys] — Run journeys headless from the command line
8
+ * init — Scaffold a glassbox.config.ts in the current directory
9
+ *
10
+ * The CLI resolves configuration from glassbox.config.ts in the working directory
11
+ * (or a custom path via --config). All commands respect the same config file.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=glassbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glassbox.d.ts","sourceRoot":"","sources":["../../bin/glassbox.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Glassbox CLI entry point.
5
+ *
6
+ * Commands:
7
+ * serve (default) — Start the dashboard server with REST API + WebSocket
8
+ * run [journeys] — Run journeys headless from the command line
9
+ * init — Scaffold a glassbox.config.ts in the current directory
10
+ *
11
+ * The CLI resolves configuration from glassbox.config.ts in the working directory
12
+ * (or a custom path via --config). All commands respect the same config file.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const commander_1 = require("commander");
16
+ const config_js_1 = require("../src/config.js");
17
+ const index_js_1 = require("../src/server/index.js");
18
+ const program = new commander_1.Command();
19
+ program
20
+ .name('glassbox')
21
+ .description('Debugger-style browser automation test runner with live execution control via CDP')
22
+ .version('0.1.0');
23
+ /**
24
+ * serve — the default command.
25
+ *
26
+ * Starts the Express server which provides:
27
+ * - REST API for controlling test execution (run, pause, resume, step, stop)
28
+ * - WebSocket for real-time action streaming to connected dashboard clients
29
+ * - Static file serving for the Angular dashboard UI
30
+ *
31
+ * The server discovers journeys from the glob pattern in config, launches
32
+ * Chrome on demand when a run is triggered, and manages the browser lifecycle.
33
+ */
34
+ program
35
+ .command('serve', { isDefault: true })
36
+ .description('Start the UI dashboard server')
37
+ .option('-p, --port <port>', 'Server port (overrides config)')
38
+ .option('-c, --config <path>', 'Path to glassbox.config.ts')
39
+ .action(async (options) => {
40
+ const config = await (0, config_js_1.loadConfig)(options.config);
41
+ const port = options.port ? parseInt(options.port, 10) : config.server.port;
42
+ const { server } = (0, index_js_1.createGlassboxServer)(config);
43
+ server.listen(port, () => {
44
+ console.log(`\n ✦ Glassbox running at http://localhost:${port}\n`);
45
+ });
46
+ });
47
+ /**
48
+ * run — headless batch execution.
49
+ *
50
+ * Runs journeys without the dashboard UI. Useful for CI pipelines or
51
+ * quick command-line verification. Exits with code 0 if all pass, 1 if any fail.
52
+ *
53
+ * If specific journey names are provided, only those are run.
54
+ * Otherwise all journeys matching the configured glob are executed.
55
+ */
56
+ program
57
+ .command('run [journeys...]')
58
+ .description('Run journeys headless (exit 0 = all pass, 1 = any fail)')
59
+ .option('-c, --config <path>', 'Path to glassbox.config.ts')
60
+ .option('--headed', 'Run in headed mode (visible browser)')
61
+ .option('-u, --url <url>', 'Target URL of the app under test')
62
+ .option('--no-fail-fast', 'Continue running after a journey fails')
63
+ .action(async (journeys, options) => {
64
+ const config = await (0, config_js_1.loadConfig)(options.config);
65
+ const { runAllJourneys } = await import('../src/runner/run-all-journeys.js');
66
+ const { exitCode } = await runAllJourneys(config, {
67
+ journeyFilter: journeys,
68
+ headed: options.headed ?? false,
69
+ targetUrl: options.url ?? '',
70
+ noFailFast: options.failFast === false,
71
+ });
72
+ process.exit(exitCode);
73
+ });
74
+ /**
75
+ * mcp — start the MCP server for AI agent integration.
76
+ *
77
+ * Runs a stdio-based MCP server that exposes Glassbox diagnostic tools.
78
+ * AI agents (Kiro, Claude, etc.) connect via the MCP protocol and can
79
+ * run journeys, inspect diagnostic data, and debug failures.
80
+ *
81
+ * Requires the Glassbox server to be running (glassbox serve).
82
+ */
83
+ program
84
+ .command('mcp')
85
+ .description('Start the MCP server for AI agent integration')
86
+ .option('--url <url>', 'Glassbox server URL (default: http://localhost:3001)')
87
+ .action(async (options) => {
88
+ if (options.url) {
89
+ process.env.GLASSBOX_URL = options.url;
90
+ }
91
+ const { startMCPServer } = await import('../src/mcp/server.js');
92
+ await startMCPServer();
93
+ });
94
+ /**
95
+ * init — project scaffolding.
96
+ *
97
+ * Creates a glassbox.config.ts with sensible defaults in the current directory,
98
+ * plus a journeys/ directory and a sample page-objects/ directory.
99
+ * Intended for consumers setting up Glassbox in a new project.
100
+ */
101
+ program
102
+ .command('init')
103
+ .description('Scaffold a glassbox.config.ts in the current directory')
104
+ .action(async () => {
105
+ const { writeFileSync, mkdirSync, existsSync } = await import('fs');
106
+ if (existsSync('glassbox.config.ts')) {
107
+ console.log(' glassbox.config.ts already exists — skipping.\n');
108
+ return;
109
+ }
110
+ const configContent = `import { defineConfig } from 'glassbox';
111
+
112
+ export default defineConfig({
113
+ journeys: './journeys/**/*.journey.ts',
114
+ browser: {
115
+ defaultViewport: { width: 1280, height: 720 },
116
+ headless: false,
117
+ },
118
+ server: { port: 3001 },
119
+ testData: {
120
+ // beforeEach: './helpers/before-each.ts',
121
+ },
122
+ });
123
+ `;
124
+ writeFileSync('glassbox.config.ts', configContent);
125
+ console.log(' ✦ Created glassbox.config.ts');
126
+ if (!existsSync('journeys')) {
127
+ mkdirSync('journeys', { recursive: true });
128
+ console.log(' ✦ Created journeys/ directory');
129
+ }
130
+ if (!existsSync('page-objects')) {
131
+ mkdirSync('page-objects', { recursive: true });
132
+ console.log(' ✦ Created page-objects/ directory');
133
+ }
134
+ console.log('\n Next steps:');
135
+ console.log(' 1. Write page objects in page-objects/');
136
+ console.log(' 2. Write journeys in journeys/');
137
+ console.log(' 3. Run: npx glassbox serve\n');
138
+ });
139
+ program.parse();
140
+ //# sourceMappingURL=glassbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glassbox.js","sourceRoot":"","sources":["../../bin/glassbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * BaseAdapter — abstract class providing debugger infrastructure.
3
+ * Breakpoints, pause/resume, step mode, slow mode, IPC via signals + stdin.
4
+ *
5
+ * All mutable debugger state is instance-scoped (not static), making
6
+ * the adapter testable and safe for potential multi-instance use.
7
+ */
8
+ import type { BrowserAdapter, DownloadResult } from './browser-adapter.interface.js';
9
+ interface IPCCommand {
10
+ command: 'pause' | 'resume' | 'step' | 'config';
11
+ stepsRemaining?: number;
12
+ actionDelay?: number;
13
+ breakpoints?: number[];
14
+ }
15
+ export declare abstract class BaseAdapter implements BrowserAdapter {
16
+ protected static downloadDir: string;
17
+ private isPaused;
18
+ private stepMode;
19
+ private stepsRemaining;
20
+ private actionIndex;
21
+ private breakpoints;
22
+ private actionDelay;
23
+ private baseUrl;
24
+ constructor();
25
+ abstract click(selector: string): Promise<void>;
26
+ abstract fill(selector: string, value: string): Promise<void>;
27
+ abstract type(selector: string, value: string, options?: {
28
+ delay?: number;
29
+ }): Promise<void>;
30
+ abstract getText(selector: string): Promise<string>;
31
+ abstract getInputValue(selector: string): Promise<string>;
32
+ abstract getAttribute(selector: string, attribute: string): Promise<string | null>;
33
+ abstract countElements(selector: string): Promise<number>;
34
+ abstract isVisible(selector: string): Promise<boolean>;
35
+ abstract isDisabled(selector: string): Promise<boolean>;
36
+ abstract waitForSelector(selector: string, options?: {
37
+ timeout?: number;
38
+ }): Promise<void>;
39
+ abstract waitForHidden(selector: string, options?: {
40
+ timeout?: number;
41
+ }): Promise<void>;
42
+ abstract waitForTimeout(ms: number): Promise<void>;
43
+ abstract goto(url: string): Promise<void>;
44
+ abstract clickAndWaitForNavigation(selector: string): Promise<void>;
45
+ abstract getCurrentUrl(): Promise<string>;
46
+ abstract evaluate<T = unknown>(script: string | (() => T)): Promise<T>;
47
+ abstract clearSession(origin?: string): Promise<void>;
48
+ abstract readClipboard(): Promise<string>;
49
+ abstract uploadFile(selector: string, filePath: string): Promise<void>;
50
+ abstract selectByIndex(selector: string, index: number): Promise<void>;
51
+ abstract selectByValue(selector: string, value: string): Promise<void>;
52
+ abstract selectByText(selector: string, text: string, exact?: boolean): Promise<void>;
53
+ abstract clickAndDownload(selector: string): Promise<DownloadResult>;
54
+ abstract clearDownloads(): Promise<void>;
55
+ /** Called BEFORE each adapter action — handles breakpoints, pause state, step mode. */
56
+ protected logAndCheckAction(description: string): Promise<void>;
57
+ /** Called AFTER each adapter action. */
58
+ protected logActionComplete(): void;
59
+ /** Applies slow-mode delay between actions. */
60
+ protected addSlowModeDelay(): Promise<void>;
61
+ /** Resolve relative URLs against the base URL (TEST_DOMAIN). */
62
+ protected resolveUrl(url: string): string;
63
+ /** Block execution while paused, polling for resume/step/config commands. */
64
+ private checkPauseState;
65
+ private emitJSON;
66
+ /** Handle an IPC command from the server (via stdin or signal). */
67
+ handleCommand(cmd: IPCCommand): void;
68
+ }
69
+ export {};
70
+ //# sourceMappingURL=base-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/base-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ /**
3
+ * BaseAdapter — abstract class providing debugger infrastructure.
4
+ * Breakpoints, pause/resume, step mode, slow mode, IPC via signals + stdin.
5
+ *
6
+ * All mutable debugger state is instance-scoped (not static), making
7
+ * the adapter testable and safe for potential multi-instance use.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.BaseAdapter = void 0;
11
+ /** Whether IPC (signals + stdin) has been initialized for this process. */
12
+ let ipcInitialized = false;
13
+ /** The single adapter instance in this process that receives IPC commands. */
14
+ let activeAdapter = null;
15
+ class BaseAdapter {
16
+ static downloadDir = '/tmp/glassbox-downloads';
17
+ isPaused = false;
18
+ stepMode = false;
19
+ stepsRemaining = 0;
20
+ actionIndex = 0;
21
+ breakpoints;
22
+ actionDelay;
23
+ baseUrl;
24
+ constructor() {
25
+ this.baseUrl = process.env.TEST_DOMAIN ?? '';
26
+ this.actionDelay = parseInt(process.env.ACTION_DELAY ?? '0', 10);
27
+ const breakpointsEnv = process.env.TEST_BREAKPOINTS;
28
+ this.breakpoints = breakpointsEnv
29
+ ? new Set(JSON.parse(breakpointsEnv))
30
+ : new Set();
31
+ // Register this as the active adapter for IPC routing
32
+ if (activeAdapter && activeAdapter !== this) {
33
+ process.stderr.write('[WARN] Multiple BaseAdapter instances in same process — IPC will route to the latest only\n');
34
+ }
35
+ activeAdapter = this;
36
+ if (!ipcInitialized) {
37
+ initializeIPC();
38
+ ipcInitialized = true;
39
+ }
40
+ }
41
+ /** Called BEFORE each adapter action — handles breakpoints, pause state, step mode. */
42
+ async logAndCheckAction(description) {
43
+ this.actionIndex++;
44
+ const index = this.actionIndex;
45
+ this.emitJSON({ type: 'action', index, status: 'start', description });
46
+ if (this.breakpoints.has(index)) {
47
+ this.emitJSON({ type: 'action', index, status: 'breakpoint', description });
48
+ this.isPaused = true;
49
+ }
50
+ await this.checkPauseState();
51
+ if (this.stepMode) {
52
+ this.stepsRemaining--;
53
+ if (this.stepsRemaining <= 0) {
54
+ this.isPaused = true;
55
+ this.stepMode = false;
56
+ this.emitJSON({ type: 'ui-control', action: 'pause' });
57
+ }
58
+ }
59
+ }
60
+ /** Called AFTER each adapter action. */
61
+ logActionComplete() {
62
+ this.emitJSON({ type: 'action', index: this.actionIndex, status: 'complete' });
63
+ }
64
+ /** Applies slow-mode delay between actions. */
65
+ async addSlowModeDelay() {
66
+ if (this.actionDelay <= 0)
67
+ return;
68
+ const interval = 50;
69
+ let remaining = this.actionDelay;
70
+ while (remaining > 0) {
71
+ await new Promise((resolve) => setTimeout(resolve, Math.min(interval, remaining)));
72
+ remaining -= interval;
73
+ }
74
+ }
75
+ /** Resolve relative URLs against the base URL (TEST_DOMAIN). */
76
+ resolveUrl(url) {
77
+ if (url.startsWith('http://') || url.startsWith('https://'))
78
+ return url;
79
+ const base = this.baseUrl.replace(/\/$/, '');
80
+ const path = url.startsWith('/') ? url : `/${url}`;
81
+ return `${base}${path}`;
82
+ }
83
+ /** Block execution while paused, polling for resume/step/config commands. */
84
+ async checkPauseState() {
85
+ while (this.isPaused) {
86
+ await new Promise((resolve) => setTimeout(resolve, 100));
87
+ }
88
+ }
89
+ emitJSON(data) {
90
+ process.stderr.write(`[JSON]${JSON.stringify(data)}\n`);
91
+ }
92
+ /** Handle an IPC command from the server (via stdin or signal). */
93
+ handleCommand(cmd) {
94
+ switch (cmd.command) {
95
+ case 'pause':
96
+ this.isPaused = true;
97
+ this.emitJSON({ type: 'ui-control', action: 'pause' });
98
+ break;
99
+ case 'resume':
100
+ this.isPaused = false;
101
+ this.stepMode = false;
102
+ this.emitJSON({ type: 'ui-control', action: 'resume' });
103
+ break;
104
+ case 'step':
105
+ this.isPaused = false;
106
+ this.stepMode = true;
107
+ this.stepsRemaining = cmd.stepsRemaining ?? 1;
108
+ break;
109
+ case 'config':
110
+ if (cmd.actionDelay !== undefined)
111
+ this.actionDelay = cmd.actionDelay;
112
+ if (cmd.breakpoints)
113
+ this.breakpoints = new Set(cmd.breakpoints);
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ exports.BaseAdapter = BaseAdapter;
119
+ /**
120
+ * Initialize process-level IPC (signals + stdin).
121
+ * Routes commands to whichever adapter instance is currently active.
122
+ * Called once per process lifetime.
123
+ */
124
+ function initializeIPC() {
125
+ try {
126
+ process.on('SIGUSR1', () => {
127
+ activeAdapter?.handleCommand({ command: 'pause' });
128
+ });
129
+ process.on('SIGUSR2', () => {
130
+ activeAdapter?.handleCommand({ command: 'resume' });
131
+ });
132
+ }
133
+ catch {
134
+ // Signals may not be available on all platforms
135
+ }
136
+ let stdinBuffer = '';
137
+ process.stdin.setEncoding('utf-8');
138
+ process.stdin.on('data', (chunk) => {
139
+ stdinBuffer += chunk;
140
+ const lines = stdinBuffer.split('\n');
141
+ stdinBuffer = lines.pop() ?? '';
142
+ for (const line of lines) {
143
+ if (!line.trim())
144
+ continue;
145
+ try {
146
+ const cmd = JSON.parse(line);
147
+ activeAdapter?.handleCommand(cmd);
148
+ }
149
+ catch {
150
+ // Ignore malformed JSON
151
+ }
152
+ }
153
+ });
154
+ }
155
+ //# sourceMappingURL=base-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-adapter.js","sourceRoot":"","sources":["../../../src/adapters/base-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * BrowserAdapter interface — the contract that page objects consume.
3
+ * The CDPAdapter is the sole implementation.
4
+ */
5
+ export interface DownloadResult {
6
+ filePath: string;
7
+ suggestedFilename: string;
8
+ }
9
+ export interface BrowserAdapter {
10
+ click(selector: string): Promise<void>;
11
+ fill(selector: string, value: string): Promise<void>;
12
+ type(selector: string, value: string, options?: {
13
+ delay?: number;
14
+ }): Promise<void>;
15
+ getText(selector: string): Promise<string>;
16
+ getInputValue(selector: string): Promise<string>;
17
+ getAttribute(selector: string, attribute: string): Promise<string | null>;
18
+ countElements(selector: string): Promise<number>;
19
+ isVisible(selector: string): Promise<boolean>;
20
+ isDisabled(selector: string): Promise<boolean>;
21
+ waitForSelector(selector: string, options?: {
22
+ timeout?: number;
23
+ }): Promise<void>;
24
+ waitForHidden(selector: string, options?: {
25
+ timeout?: number;
26
+ }): Promise<void>;
27
+ waitForTimeout(ms: number): Promise<void>;
28
+ goto(url: string): Promise<void>;
29
+ clickAndWaitForNavigation(selector: string): Promise<void>;
30
+ getCurrentUrl(): Promise<string>;
31
+ evaluate<T = unknown>(script: string | (() => T)): Promise<T>;
32
+ clearSession(origin?: string): Promise<void>;
33
+ readClipboard(): Promise<string>;
34
+ uploadFile(selector: string, filePath: string): Promise<void>;
35
+ selectByIndex(selector: string, index: number): Promise<void>;
36
+ selectByValue(selector: string, value: string): Promise<void>;
37
+ selectByText(selector: string, text: string, exact?: boolean): Promise<void>;
38
+ clickAndDownload(selector: string): Promise<DownloadResult>;
39
+ clearDownloads(): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=browser-adapter.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-adapter.interface.d.ts","sourceRoot":"","sources":["../../../src/adapters/browser-adapter.interface.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAE7B,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGnF,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1E,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAG/C,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG1C,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAGjC,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAG9D,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG9D,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7E,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC"}