testdriverai 7.9.21-test → 7.9.23-test

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.
@@ -372,7 +372,9 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
372
372
  step: 'discontinuity',
373
373
  message: 'Recovering missed messages after connection interruption...',
374
374
  });
375
- self._recoverFromDiscontinuity();
375
+ self._recoverFromDiscontinuity().catch(function (err) {
376
+ logger.debug('[realtime] Discontinuity recovery error (suppressed): ' + (err.message || err));
377
+ });
376
378
  }
377
379
 
378
380
  // When the channel is detached or failed (e.g. sandbox terminated — 404/90001),
@@ -881,11 +883,7 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
881
883
  // Also check channel history in case runner.ready was published
882
884
  // before we subscribed (race condition on fast-booting agents).
883
885
  try {
884
- self._sessionChannel.history({ limit: 50 }, function (err, page) {
885
- if (err) {
886
- logger.warn('History lookup failed (non-fatal): ' + (err.message || err));
887
- return;
888
- }
886
+ self._sessionChannel.history({ limit: 50 }).then(function (page) {
889
887
  if (page && page.items) {
890
888
  for (var i = 0; i < page.items.length; i++) {
891
889
  var item = page.items[i];
@@ -896,6 +894,8 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
896
894
  }
897
895
  }
898
896
  }
897
+ }).catch(function (err) {
898
+ logger.warn('History lookup failed (non-fatal): ' + (err.message || err));
899
899
  });
900
900
  } catch (histErr) {
901
901
  logger.warn('History call threw (non-fatal): ' + (histErr.message || histErr));
@@ -1033,11 +1033,7 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
1033
1033
  // Also check channel history in case runner.ready was published
1034
1034
  // before we subscribed (race condition on fast-booting agents).
1035
1035
  try {
1036
- self._sessionChannel.history({ limit: 50 }, function (err, page) {
1037
- if (err) {
1038
- logger.warn('History lookup failed (non-fatal): ' + (err.message || err));
1039
- return;
1040
- }
1036
+ self._sessionChannel.history({ limit: 50 }).then(function (page) {
1041
1037
  if (page && page.items) {
1042
1038
  for (var i = 0; i < page.items.length; i++) {
1043
1039
  var item = page.items[i];
@@ -1048,6 +1044,8 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
1048
1044
  }
1049
1045
  }
1050
1046
  }
1047
+ }).catch(function (err) {
1048
+ logger.warn('History lookup failed (non-fatal): ' + (err.message || err));
1051
1049
  });
1052
1050
  } catch (histErr) {
1053
1051
  logger.warn('History call threw (non-fatal): ' + (histErr.message || histErr));
@@ -192,6 +192,29 @@ await dashcam.addApplicationLog(application, name)
192
192
  await dashcam.addApplicationLog('Google Chrome', 'Browser Logs');
193
193
  ```
194
194
 
195
+ ### addWebLog()
196
+
197
+ Track web request logs by URL pattern:
198
+
199
+ ```javascript
200
+ await dashcam.addWebLog(pattern, name)
201
+ ```
202
+
203
+ <ParamField path="pattern" type="string" required>
204
+ URL pattern to match (e.g., `"*example.com*"`)
205
+ </ParamField>
206
+
207
+ <ParamField path="name" type="string" required>
208
+ Display name for the log
209
+ </ParamField>
210
+
211
+ **Returns:** `Promise<void>`
212
+
213
+ **Example:**
214
+ ```javascript
215
+ await dashcam.addWebLog('*example.com*', 'Web Logs');
216
+ ```
217
+
195
218
  ### addLog()
196
219
 
197
220
  Generic method to add any type of log:
@@ -209,7 +232,7 @@ await dashcam.addLog(config)
209
232
  </ParamField>
210
233
 
211
234
  <ParamField path="type" type="string" required>
212
- Log type: `'file'`, `'stdout'`, or `'application'`
235
+ Log type: `'file'`, `'application'`, or `'web'`
213
236
  </ParamField>
214
237
 
215
238
  <ParamField path="path" type="string">
@@ -219,6 +242,10 @@ await dashcam.addLog(config)
219
242
  <ParamField path="application" type="string">
220
243
  Application name (required for type='application')
221
244
  </ParamField>
245
+
246
+ <ParamField path="pattern" type="string">
247
+ URL pattern to match (required for type='web', e.g., `"*example.com*"`)
248
+ </ParamField>
222
249
  </Expandable>
223
250
  </ParamField>
224
251
 
@@ -237,6 +264,12 @@ await dashcam.addLog({
237
264
  type: 'application',
238
265
  application: 'Google Chrome'
239
266
  });
267
+
268
+ await dashcam.addLog({
269
+ name: 'Web Logs',
270
+ type: 'web',
271
+ pattern: '*example.com*'
272
+ });
240
273
  ```
241
274
 
242
275
  ### isRecording()
@@ -193,6 +193,29 @@ await dashcam.addApplicationLog(application, name)
193
193
  await dashcam.addApplicationLog('Google Chrome', 'Browser Logs');
194
194
  ```
195
195
 
196
+ ### addWebLog()
197
+
198
+ Track web request logs by URL pattern:
199
+
200
+ ```javascript
201
+ await dashcam.addWebLog(pattern, name)
202
+ ```
203
+
204
+ <ParamField path="pattern" type="string" required>
205
+ URL pattern to match (e.g., `"*example.com*"`)
206
+ </ParamField>
207
+
208
+ <ParamField path="name" type="string" required>
209
+ Display name for the log
210
+ </ParamField>
211
+
212
+ **Returns:** `Promise<void>`
213
+
214
+ **Example:**
215
+ ```javascript
216
+ await dashcam.addWebLog('*example.com*', 'Web Logs');
217
+ ```
218
+
196
219
  ### addLog()
197
220
 
198
221
  Generic method to add any type of log:
@@ -210,7 +233,7 @@ await dashcam.addLog(config)
210
233
  </ParamField>
211
234
 
212
235
  <ParamField path="type" type="string" required>
213
- Log type: `'file'`, `'stdout'`, or `'application'`
236
+ Log type: `'file'`, `'application'`, or `'web'`
214
237
  </ParamField>
215
238
 
216
239
  <ParamField path="path" type="string">
@@ -220,6 +243,10 @@ await dashcam.addLog(config)
220
243
  <ParamField path="application" type="string">
221
244
  Application name (required for type='application')
222
245
  </ParamField>
246
+
247
+ <ParamField path="pattern" type="string">
248
+ URL pattern to match (required for type='web', e.g., `"*example.com*"`)
249
+ </ParamField>
223
250
  </Expandable>
224
251
  </ParamField>
225
252
 
@@ -238,6 +265,12 @@ await dashcam.addLog({
238
265
  type: 'application',
239
266
  application: 'Google Chrome'
240
267
  });
268
+
269
+ await dashcam.addLog({
270
+ name: 'Web Logs',
271
+ type: 'web',
272
+ pattern: '*example.com*'
273
+ });
241
274
  ```
242
275
 
243
276
  ### isRecording()
@@ -0,0 +1,39 @@
1
+ /**
2
+ * TestDriver SDK - Web Logs Test (Vitest)
3
+ * Opens Notion, adds web logs via dashcam, then navigates to several URLs.
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../lib/vitest/hooks.mjs";
8
+ import { getDefaults } from "./config.mjs";
9
+
10
+ /**
11
+ * Navigate Chrome to a new URL using Ctrl+L
12
+ * @param {import('../../sdk.js').default} client - TestDriver client instance
13
+ * @param {string} url - URL to navigate to
14
+ */
15
+ async function navigateTo(client, url) {
16
+ await client.pressKeys(["ctrl", "l"]);
17
+ await client.type(url);
18
+ await client.pressKeys(["enter"]);
19
+ }
20
+
21
+ describe("Web Logs Test", () => {
22
+ it("should open Notion, add web logs, and navigate to multiple URLs", async (context) => {
23
+ const testdriver = TestDriver(context, { ...getDefaults(context) });
24
+
25
+ // Add web logs for all domains
26
+ await testdriver.dashcam.addWebLog("http*://*github.com*");
27
+
28
+ // Launch Chrome to notion.so
29
+ await testdriver.provision.chrome({
30
+ url: "https://www.notion.so",
31
+ });
32
+
33
+ // Navigate to GitHub
34
+ await navigateTo(testdriver, "https://github.com");
35
+ const githubLoaded = await testdriver.assert("the GitHub homepage is visible");
36
+ expect(githubLoaded).toBeTruthy();
37
+
38
+ });
39
+ });
@@ -38,6 +38,13 @@ export class Dashcam {
38
38
  */
39
39
  addApplicationLog(application: string, name: string): Promise<void>;
40
40
 
41
+ /**
42
+ * Add a web log to Dashcam
43
+ * @param pattern - URL pattern to match (e.g., "*example.com*")
44
+ * @param name - Name/description for the log entry
45
+ */
46
+ addWebLog(pattern: string, name: string): Promise<void>;
47
+
41
48
  /**
42
49
  * Start recording
43
50
  * @returns Promise that resolves when recording starts
@@ -68,7 +75,7 @@ export interface LogConfig {
68
75
  /**
69
76
  * Type of log entry
70
77
  */
71
- type: 'file' | 'application';
78
+ type: 'file' | 'application' | 'web';
72
79
 
73
80
  /**
74
81
  * Path to file (for file logs)
@@ -80,6 +87,11 @@ export interface LogConfig {
80
87
  */
81
88
  application?: string;
82
89
 
90
+ /**
91
+ * URL pattern (for web logs, e.g., "*example.com*")
92
+ */
93
+ pattern?: string;
94
+
83
95
  /**
84
96
  * Name/description for the log entry
85
97
  */
@@ -447,16 +447,6 @@ jobs:
447
447
  if (copiedCount > 0) {
448
448
  progress(`✓ Copied ${copiedCount} agent(s) to .github/agents/`);
449
449
  }
450
-
451
- // Also set testdriver.md as copilot-instructions.md if it doesn't already exist
452
- const copilotInstructionsPath = path.join(targetDir, ".github", "copilot-instructions.md");
453
- const testdriverAgentSource = path.join(agentsSourceDir, "testdriver.md");
454
- if (!fs.existsSync(copilotInstructionsPath) && fs.existsSync(testdriverAgentSource)) {
455
- fs.copyFileSync(testdriverAgentSource, copilotInstructionsPath);
456
- progress("✓ Created .github/copilot-instructions.md");
457
- } else if (fs.existsSync(copilotInstructionsPath)) {
458
- progress("⊘ copilot-instructions.md already exists, skipping");
459
- }
460
450
  } else {
461
451
  progress("⚠ Agents directory not found (will be available after npm install)");
462
452
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.9.21-test",
3
+ "version": "7.9.23-test",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
6
  "types": "sdk.d.ts",