@testivai/witness-cdp 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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +405 -0
  3. package/dist/__tests__/setup.d.ts +4 -0
  4. package/dist/__tests__/setup.d.ts.map +1 -0
  5. package/dist/__tests__/setup.js +24 -0
  6. package/dist/__tests__/setup.js.map +1 -0
  7. package/dist/cdp/binding.d.ts +44 -0
  8. package/dist/cdp/binding.d.ts.map +1 -0
  9. package/dist/cdp/binding.js +183 -0
  10. package/dist/cdp/binding.js.map +1 -0
  11. package/dist/cdp/capture.d.ts +42 -0
  12. package/dist/cdp/capture.d.ts.map +1 -0
  13. package/dist/cdp/capture.js +235 -0
  14. package/dist/cdp/capture.js.map +1 -0
  15. package/dist/cdp/client.d.ts +63 -0
  16. package/dist/cdp/client.d.ts.map +1 -0
  17. package/dist/cdp/client.js +279 -0
  18. package/dist/cdp/client.js.map +1 -0
  19. package/dist/cdp/discovery.d.ts +33 -0
  20. package/dist/cdp/discovery.d.ts.map +1 -0
  21. package/dist/cdp/discovery.js +157 -0
  22. package/dist/cdp/discovery.js.map +1 -0
  23. package/dist/commands/auth.d.ts +3 -0
  24. package/dist/commands/auth.d.ts.map +1 -0
  25. package/dist/commands/auth.js +122 -0
  26. package/dist/commands/auth.js.map +1 -0
  27. package/dist/commands/capture.d.ts +3 -0
  28. package/dist/commands/capture.d.ts.map +1 -0
  29. package/dist/commands/capture.js +143 -0
  30. package/dist/commands/capture.js.map +1 -0
  31. package/dist/commands/init.d.ts +3 -0
  32. package/dist/commands/init.d.ts.map +1 -0
  33. package/dist/commands/init.js +140 -0
  34. package/dist/commands/init.js.map +1 -0
  35. package/dist/commands/run.d.ts +3 -0
  36. package/dist/commands/run.d.ts.map +1 -0
  37. package/dist/commands/run.js +307 -0
  38. package/dist/commands/run.js.map +1 -0
  39. package/dist/index.d.ts +20 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +77 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/types.d.ts +244 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +7 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/utils/file-naming.d.ts +31 -0
  48. package/dist/utils/file-naming.d.ts.map +1 -0
  49. package/dist/utils/file-naming.js +137 -0
  50. package/dist/utils/file-naming.js.map +1 -0
  51. package/dist/utils/framework-detect.d.ts +31 -0
  52. package/dist/utils/framework-detect.d.ts.map +1 -0
  53. package/dist/utils/framework-detect.js +379 -0
  54. package/dist/utils/framework-detect.js.map +1 -0
  55. package/dist/utils/logger.d.ts +29 -0
  56. package/dist/utils/logger.d.ts.map +1 -0
  57. package/dist/utils/logger.js +114 -0
  58. package/dist/utils/logger.js.map +1 -0
  59. package/dist/utils/process.d.ts +61 -0
  60. package/dist/utils/process.d.ts.map +1 -0
  61. package/dist/utils/process.js +208 -0
  62. package/dist/utils/process.js.map +1 -0
  63. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TestivAI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,405 @@
1
+ # @testivai/witness-cdp
2
+
3
+ Framework-agnostic visual regression testing SDK using Chrome DevTools Protocol.
4
+
5
+ ## Overview
6
+
7
+ The TestivAI CDP SDK allows you to integrate visual regression testing into any test framework that can control Chrome/Chromium browsers. It works by connecting directly to the Chrome DevTools Protocol (CDP) and injecting a `window.testivaiWitness` function that triggers visual captures.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install -g @testivai/witness-cdp
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ 1. **Initialize your project**
18
+ ```bash
19
+ testivai init
20
+ ```
21
+
22
+ 2. **Authenticate with your API key**
23
+ ```bash
24
+ testivai auth <your-api-key>
25
+ ```
26
+
27
+ 3. **Add visual captures to your tests**
28
+ ```javascript
29
+ // In your test code
30
+ await window.testivaiWitness('my-snapshot');
31
+ ```
32
+
33
+ 4. **Run your tests**
34
+ ```bash
35
+ # Make sure Chrome is running with remote debugging
36
+ chrome --remote-debugging-port=9222
37
+
38
+ # Run your tests with TestivAI
39
+ testivai run "npm test"
40
+ ```
41
+
42
+ ## Framework Integration
43
+
44
+ ### Cypress
45
+
46
+ Add this custom command to `cypress/support/commands.js`:
47
+
48
+ ```javascript
49
+ // testivai-witness-cdp.js
50
+ Cypress.Commands.add('witness', (name) => {
51
+ return cy.window().invoke('testivaiWitness', name);
52
+ });
53
+ ```
54
+
55
+ Use in your tests:
56
+
57
+ ```javascript
58
+ it('should capture visual snapshot', () => {
59
+ cy.visit('/my-page');
60
+ cy.witness('my-snapshot');
61
+ });
62
+ ```
63
+
64
+ Run tests:
65
+ ```bash
66
+ testivai run "cypress run"
67
+ ```
68
+
69
+ ### Selenium (Python)
70
+
71
+ ```python
72
+ from selenium import webdriver
73
+
74
+ def capture_snapshot(driver, name):
75
+ driver.execute_script(f"return window.testivaiWitness('{name}')")
76
+
77
+ def test_visual_snapshot():
78
+ driver = webdriver.Chrome()
79
+ driver.get("http://localhost:3000")
80
+ capture_snapshot(driver, "my-snapshot")
81
+ ```
82
+
83
+ Run tests:
84
+ ```bash
85
+ testivai run "pytest tests/"
86
+ ```
87
+
88
+ ### Selenium (JavaScript)
89
+
90
+ ```javascript
91
+ const { Builder, By } = require('selenium-webdriver');
92
+
93
+ async function captureSnapshot(driver, name) {
94
+ await driver.executeScript(`return window.testivaiWitness('${name}')`);
95
+ }
96
+
97
+ it('should capture visual snapshot', async () => {
98
+ const driver = await new Builder().forBrowser('chrome').build();
99
+ await driver.get('http://localhost:3000');
100
+ await captureSnapshot(driver, 'my-snapshot');
101
+ });
102
+ ```
103
+
104
+ Run tests:
105
+ ```bash
106
+ testivai run "npm test"
107
+ ```
108
+
109
+ ### WebdriverIO
110
+
111
+ Add this custom command to your test setup:
112
+
113
+ ```javascript
114
+ // In wdio.conf.js or test setup
115
+ browser.addCommand('witness', function(name) {
116
+ return this.executeScript('return window.testivaiWitness(arguments[0])', name);
117
+ });
118
+ ```
119
+
120
+ Use in your tests:
121
+
122
+ ```javascript
123
+ it('should capture visual snapshot', async () => {
124
+ await browser.url('/my-page');
125
+ await browser.witness('my-snapshot');
126
+ });
127
+ ```
128
+
129
+ Run tests:
130
+ ```bash
131
+ testivai run "npx wdio"
132
+ ```
133
+
134
+ ## How It Works
135
+
136
+ 1. **CDP Connection**: The SDK connects to Chrome's DevTools Protocol (usually on port 9222)
137
+ 2. **Binding Injection**: Using `Runtime.addBinding`, it injects a native function `window.testivaiWitness`
138
+ 3. **Promise Wrapper**: A client-side script wraps the native binding in a Promise for async/await support
139
+ 4. **Capture Trigger**: When `window.testivaiWitness('name')` is called, it triggers:
140
+ - Screenshot capture
141
+ - DOM extraction
142
+ - Layout analysis
143
+ - Performance metrics
144
+ 5. **Batch Upload**: All captures are batched and uploaded to TestivAI for analysis
145
+
146
+ ## Configuration
147
+
148
+ Create a `testivai.config.ts` file in your project root:
149
+
150
+ ```typescript
151
+ import type { CdpConfig } from '@testivai/witness-cdp';
152
+
153
+ const config: CdpConfig = {
154
+ // API key (set via TESTIVAI_API_KEY environment variable)
155
+ // apiKey: 'your-api-key-here',
156
+
157
+ // Project ID from TestivAI dashboard
158
+ // projectId: 'your-project-id-here',
159
+
160
+ // Chrome DevTools Protocol port
161
+ cdpPort: 9222,
162
+
163
+ // Auto-launch Chrome if not running (experimental)
164
+ autoLaunch: false,
165
+
166
+ // Chrome executable path (for auto-launch)
167
+ // chromePath: '/path/to/chrome',
168
+
169
+ // Additional Chrome arguments
170
+ chromeArgs: [
171
+ '--no-sandbox',
172
+ '--disable-dev-shm-usage',
173
+ '--disable-gpu',
174
+ ],
175
+
176
+ // Connection settings
177
+ connectionTimeout: 5000,
178
+ connectionRetries: 3,
179
+ };
180
+
181
+ export default config;
182
+ ```
183
+
184
+ ## CLI Commands
185
+
186
+ ### `testivai init`
187
+ Initialize TestivAI in your project. Detects your framework and provides setup instructions.
188
+
189
+ ### `testivai auth <api-key>`
190
+ Authenticate with your TestivAI API key. Get your key from the [dashboard](https://dashboard.testiv.ai).
191
+
192
+ ### `testivai run <command>`
193
+ Run your test command with automatic visual capture.
194
+
195
+ ```bash
196
+ testivai run "npm test"
197
+ testivai run "cypress run"
198
+ testivai run "pytest tests/"
199
+ ```
200
+
201
+ Options:
202
+ - `-p, --port <number>` - Specify CDP port (default: 9222)
203
+ - `-b, --batch-id <id>` - Specify batch ID (auto-generated if not provided)
204
+
205
+ ### `testivai capture <name>`
206
+ Capture a single snapshot without running tests.
207
+
208
+ ```bash
209
+ testivai capture "my-snapshot" --format json
210
+ ```
211
+
212
+ Options:
213
+ - `-p, --port <number>` - Specify CDP port
214
+ - `-o, --output <path>` - Output directory (default: .testivai/captures)
215
+ - `-f, --format <format>` - Output format: json|png (default: json)
216
+
217
+ ## Chrome Setup
218
+
219
+ ### Manual Launch
220
+
221
+ Launch Chrome with remote debugging enabled:
222
+
223
+ ```bash
224
+ # macOS
225
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222
226
+
227
+ # Windows
228
+ "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
229
+
230
+ # Linux
231
+ google-chrome --remote-debugging-port=9222
232
+ ```
233
+
234
+ ### Common Chrome Arguments
235
+
236
+ ```bash
237
+ chrome \
238
+ --remote-debugging-port=9222 \
239
+ --no-sandbox \
240
+ --disable-dev-shm-usage \
241
+ --disable-gpu \
242
+ --headless # For CI environments
243
+ ```
244
+
245
+ ## CI/CD Integration
246
+
247
+ ### GitHub Actions
248
+
249
+ ```yaml
250
+ name: Visual Tests
251
+ on: [push, pull_request]
252
+
253
+ jobs:
254
+ visual:
255
+ runs-on: ubuntu-latest
256
+ steps:
257
+ - uses: actions/checkout@v3
258
+
259
+ - name: Setup Node.js
260
+ uses: actions/setup-node@v3
261
+ with:
262
+ node-version: '18'
263
+
264
+ - name: Install dependencies
265
+ run: npm ci
266
+
267
+ - name: Install TestivAI CDP SDK
268
+ run: npm install -g @testivai/witness-cdp
269
+
270
+ - name: Start Chrome
271
+ run: |
272
+ google-chrome \
273
+ --remote-debugging-port=9222 \
274
+ --no-sandbox \
275
+ --disable-dev-shm-usage \
276
+ --headless \
277
+ --disable-gpu &
278
+
279
+ - name: Authenticate
280
+ run: testivai auth ${{ secrets.TESTIVAI_API_KEY }}
281
+
282
+ - name: Run visual tests
283
+ run: testivai run "npm test"
284
+ ```
285
+
286
+ ### Jenkins
287
+
288
+ ```groovy
289
+ pipeline {
290
+ agent any
291
+
292
+ stages {
293
+ stage('Setup') {
294
+ steps {
295
+ sh 'npm ci'
296
+ sh 'npm install -g @testivai/witness-cdp'
297
+ }
298
+ }
299
+
300
+ stage('Start Chrome') {
301
+ steps {
302
+ sh '''
303
+ google-chrome \
304
+ --remote-debugging-port=9222 \
305
+ --no-sandbox \
306
+ --disable-dev-shm-usage \
307
+ --headless &
308
+ '''
309
+ }
310
+ }
311
+
312
+ stage('Visual Tests') {
313
+ steps {
314
+ withCredentials([string(credentialsId: 'testivai-api-key', variable: 'API_KEY')]) {
315
+ sh 'testivai auth $API_KEY'
316
+ sh 'testivai run "npm test"'
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ ```
323
+
324
+ ## Troubleshooting
325
+
326
+ ### Chrome not found
327
+ ```
328
+ ❌ Chrome DevTools Protocol not found
329
+ ```
330
+
331
+ **Solution**: Make sure Chrome is running with remote debugging:
332
+ ```bash
333
+ chrome --remote-debugging-port=9222
334
+ ```
335
+
336
+ ### Connection timeout
337
+ ```
338
+ ❌ Failed to connect to CDP: Connection timeout
339
+ ```
340
+
341
+ **Solution**:
342
+ 1. Check if Chrome is running
343
+ 2. Verify the port number (default: 9222)
344
+ 3. Check for firewall issues
345
+
346
+ ### Tests hang after calling testivaiWitness
347
+ **Solution**: The Promise wrapper might not be working. Check browser console for errors and ensure CDP is properly connected.
348
+
349
+ ### No snapshots captured
350
+ **Solution**:
351
+ 1. Verify `window.testivaiWitness` is available in your tests
352
+ 2. Check that the SDK is connected before running tests
353
+ 3. Enable verbose logging: `testivai run "npm test" --verbose`
354
+
355
+ ## Performance
356
+
357
+ - **Package size**: ~270KB (no browser binaries included)
358
+ - **Memory usage**: ~50MB additional overhead
359
+ - **Capture time**: ~100-500ms per snapshot
360
+ - **Upload time**: Depends on network and snapshot size
361
+
362
+ ## API Reference
363
+
364
+ ### CdpClient
365
+ Main class for connecting to Chrome DevTools Protocol.
366
+
367
+ ```typescript
368
+ import { CdpClient } from '@testivai/witness-cdp';
369
+
370
+ const client = new CdpClient();
371
+ await client.connect(9222);
372
+ await client.send('Page.navigate', { url: 'https://example.com' });
373
+ await client.disconnect();
374
+ ```
375
+
376
+ ### CdpCapture
377
+ Handles screenshot and data capture.
378
+
379
+ ```typescript
380
+ import { CdpCapture } from '@testivai/witness-cdp';
381
+
382
+ const capture = new CdpCapture(client);
383
+ const snapshot = await capture.captureSnapshot('my-snapshot');
384
+ ```
385
+
386
+ ### CdpBinding
387
+ Manages the `window.testivaiWitness` binding.
388
+
389
+ ```typescript
390
+ import { CdpBinding } from '@testivai/witness-cdp';
391
+
392
+ const binding = new CdpBinding(client);
393
+ await binding.setupBindings();
394
+ const snapshots = binding.getSnapshots();
395
+ ```
396
+
397
+ ## License
398
+
399
+ MIT
400
+
401
+ ## Support
402
+
403
+ - Documentation: https://docs.testiv.ai/cdp
404
+ - Issues: https://github.com/testivai/testivai-monorepo/issues
405
+ - Email: support@testiv.ai
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Jest test setup
3
+ */
4
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Jest test setup
4
+ */
5
+ // Mock console methods to reduce noise in tests
6
+ global.console = {
7
+ ...console,
8
+ // Uncomment to suppress console.log during tests
9
+ // log: jest.fn(),
10
+ // debug: jest.fn(),
11
+ // info: jest.fn(),
12
+ // warn: jest.fn(),
13
+ // error: jest.fn(),
14
+ };
15
+ // Set test timeout
16
+ jest.setTimeout(10000);
17
+ // Mock environment variables
18
+ process.env.NODE_ENV = 'test';
19
+ process.env.TESTIVAI_API_URL = 'http://localhost:3000';
20
+ // Global test utilities
21
+ global.mockFetch = jest.fn();
22
+ // Mock fetch globally
23
+ global.fetch = global.mockFetch;
24
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":";AAAA;;GAEG;AAEH,gDAAgD;AAChD,MAAM,CAAC,OAAO,GAAG;IACf,GAAG,OAAO;IACV,iDAAiD;IACjD,kBAAkB;IAClB,oBAAoB;IACpB,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;CACrB,CAAC;AAEF,mBAAmB;AACnB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAEvB,6BAA6B;AAC7B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC;AAC9B,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,uBAAuB,CAAC;AAEvD,wBAAwB;AACvB,MAAc,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;AAEtC,sBAAsB;AACrB,MAAc,CAAC,KAAK,GAAI,MAAc,CAAC,SAAS,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { CdpClient } from './client';
2
+ /**
3
+ * CDP Binding management
4
+ */
5
+ export declare class CdpBinding {
6
+ private client;
7
+ private capture;
8
+ private snapshots;
9
+ private isBindingRegistered;
10
+ constructor(client: CdpClient);
11
+ /**
12
+ * Set up the Runtime bindings
13
+ */
14
+ setupBindings(): Promise<void>;
15
+ /**
16
+ * Inject the client-side script into all pages
17
+ */
18
+ private injectClientScript;
19
+ /**
20
+ * Set up event listeners for binding events
21
+ */
22
+ private setupEventListeners;
23
+ /**
24
+ * Handle a witness binding call
25
+ */
26
+ private handleWitnessCall;
27
+ /**
28
+ * Send ACK to resolve the Promise
29
+ */
30
+ private sendAck;
31
+ /**
32
+ * Get all captured snapshots
33
+ */
34
+ getSnapshots(): any[];
35
+ /**
36
+ * Clear all captured snapshots
37
+ */
38
+ clearSnapshots(): void;
39
+ /**
40
+ * Check if bindings are registered
41
+ */
42
+ isRegistered(): boolean;
43
+ }
44
+ //# sourceMappingURL=binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/cdp/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AA8CrC;;GAEG;AACH,qBAAa,UAAU;IAKT,OAAO,CAAC,MAAM;IAJ1B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,mBAAmB,CAAS;gBAEhB,MAAM,EAAE,SAAS;IAKrC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BpC;;OAEG;YACW,kBAAkB;IAwBhC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;YACW,iBAAiB;IAuB/B;;OAEG;YACW,OAAO;IAWrB;;OAEG;IACH,YAAY,IAAI,GAAG,EAAE;IAIrB;;OAEG;IACH,cAAc,IAAI,IAAI;IAKtB;;OAEG;IACH,YAAY,IAAI,OAAO;CAGxB"}
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CdpBinding = void 0;
4
+ const capture_1 = require("./capture");
5
+ const logger_1 = require("../utils/logger");
6
+ /**
7
+ * Client-side script injected into the browser
8
+ * This wraps the native binding in a Promise
9
+ */
10
+ const CLIENT_SCRIPT = `
11
+ (function() {
12
+ // Store the native binding
13
+ const _nativeWitness = window.testivaiWitness;
14
+
15
+ // Create the Promise wrapper
16
+ window.testivaiWitness = function(name) {
17
+ return new Promise(function(resolve) {
18
+ // Store resolve function for ACK
19
+ window.__testivaiResolve = resolve;
20
+
21
+ // Call the native binding
22
+ if (_nativeWitness) {
23
+ _nativeWitness(name);
24
+ } else {
25
+ console.error('TestivAI: Native binding not found');
26
+ resolve();
27
+ }
28
+ });
29
+ };
30
+
31
+ // Log that the binding is ready
32
+ console.log('TestivAI: Binding ready');
33
+ })();
34
+ `;
35
+ /**
36
+ * ACK script to resolve the Promise
37
+ */
38
+ const ACK_SCRIPT = `
39
+ (function() {
40
+ if (window.__testivaiResolve) {
41
+ window.__testivaiResolve();
42
+ window.__testivaiResolve = null;
43
+ }
44
+ })();
45
+ `;
46
+ /**
47
+ * CDP Binding management
48
+ */
49
+ class CdpBinding {
50
+ constructor(client) {
51
+ this.client = client;
52
+ this.snapshots = [];
53
+ this.isBindingRegistered = false;
54
+ this.capture = new capture_1.CdpCapture(client);
55
+ this.setupEventListeners();
56
+ }
57
+ /**
58
+ * Set up the Runtime bindings
59
+ */
60
+ async setupBindings() {
61
+ try {
62
+ // Enable Runtime domain
63
+ await this.client.enableDomain('Runtime');
64
+ // Register the main binding for triggering captures
65
+ await this.client.send('Runtime.addBinding', {
66
+ name: 'testivaiWitness',
67
+ });
68
+ logger_1.logger.bindingRegistered('testivaiWitness');
69
+ // Register the ACK binding for resolving Promises
70
+ await this.client.send('Runtime.addBinding', {
71
+ name: 'testivaiWitnessAck',
72
+ });
73
+ logger_1.logger.bindingRegistered('testivaiWitnessAck');
74
+ // Inject the client-side script
75
+ await this.injectClientScript();
76
+ this.isBindingRegistered = true;
77
+ logger_1.logger.success('CDP bindings registered successfully');
78
+ }
79
+ catch (error) {
80
+ logger_1.logger.error('Failed to setup CDP bindings:', error);
81
+ throw error;
82
+ }
83
+ }
84
+ /**
85
+ * Inject the client-side script into all pages
86
+ */
87
+ async injectClientScript() {
88
+ try {
89
+ // Enable Page domain
90
+ await this.client.enableDomain('Page');
91
+ // Add script to evaluate on new documents
92
+ await this.client.send('Page.addScriptToEvaluateOnNewDocument', {
93
+ source: CLIENT_SCRIPT,
94
+ });
95
+ // Also evaluate on current document if it exists
96
+ try {
97
+ await this.client.send('Page.reload', {});
98
+ }
99
+ catch {
100
+ // Page might not be loaded yet, which is fine
101
+ }
102
+ logger_1.logger.debug('Client script injected');
103
+ }
104
+ catch (error) {
105
+ logger_1.logger.error('Failed to inject client script:', error);
106
+ throw error;
107
+ }
108
+ }
109
+ /**
110
+ * Set up event listeners for binding events
111
+ */
112
+ setupEventListeners() {
113
+ // Listen for binding called events
114
+ this.client.on('bindingCalled', async (params) => {
115
+ if (params.name === 'testivaiWitness') {
116
+ await this.handleWitnessCall(params.payload);
117
+ }
118
+ });
119
+ // Listen for frame navigation to re-inject script
120
+ this.client.on('frameNavigated', async () => {
121
+ if (this.isBindingRegistered) {
122
+ logger_1.logger.debug('Frame navigated, re-injecting client script');
123
+ await this.injectClientScript();
124
+ }
125
+ });
126
+ }
127
+ /**
128
+ * Handle a witness binding call
129
+ */
130
+ async handleWitnessCall(payload) {
131
+ try {
132
+ const snapshotName = payload || 'snapshot';
133
+ logger_1.logger.bindingCalled('testivaiWitness', snapshotName);
134
+ // Capture the snapshot
135
+ const snapshot = await this.capture.captureSnapshot(snapshotName);
136
+ // Add to snapshots array
137
+ this.snapshots.push(snapshot);
138
+ // Send ACK to resolve the Promise
139
+ await this.sendAck();
140
+ logger_1.logger.debug(`Captured and ACK'd: ${snapshotName}`);
141
+ }
142
+ catch (error) {
143
+ logger_1.logger.error(`Failed to handle witness call for ${payload}:`, error);
144
+ // Still send ACK to avoid hanging the test
145
+ await this.sendAck();
146
+ }
147
+ }
148
+ /**
149
+ * Send ACK to resolve the Promise
150
+ */
151
+ async sendAck() {
152
+ try {
153
+ await this.client.send('Runtime.evaluate', {
154
+ expression: ACK_SCRIPT,
155
+ });
156
+ logger_1.logger.debug('Sent ACK');
157
+ }
158
+ catch (error) {
159
+ logger_1.logger.error('Failed to send ACK:', error);
160
+ }
161
+ }
162
+ /**
163
+ * Get all captured snapshots
164
+ */
165
+ getSnapshots() {
166
+ return this.snapshots;
167
+ }
168
+ /**
169
+ * Clear all captured snapshots
170
+ */
171
+ clearSnapshots() {
172
+ this.snapshots = [];
173
+ logger_1.logger.debug('Cleared snapshots');
174
+ }
175
+ /**
176
+ * Check if bindings are registered
177
+ */
178
+ isRegistered() {
179
+ return this.isBindingRegistered;
180
+ }
181
+ }
182
+ exports.CdpBinding = CdpBinding;
183
+ //# sourceMappingURL=binding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/cdp/binding.ts"],"names":[],"mappings":"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"}