testdriverai 7.0.0 → 7.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 (112) hide show
  1. package/AGENTS.md +550 -0
  2. package/CODEOWNERS +0 -1
  3. package/README.md +126 -0
  4. package/agent/index.js +43 -18
  5. package/agent/lib/commands.js +794 -135
  6. package/agent/lib/redraw.js +124 -39
  7. package/agent/lib/sandbox.js +10 -1
  8. package/agent/lib/sdk.js +21 -0
  9. package/docs/MIGRATION.md +425 -0
  10. package/docs/PRESETS.md +210 -0
  11. package/docs/docs.json +91 -37
  12. package/docs/guide/best-practices-polling.mdx +154 -0
  13. package/docs/v7/api/dashcam.mdx +497 -0
  14. package/docs/v7/api/doubleClick.mdx +102 -0
  15. package/docs/v7/api/mouseDown.mdx +161 -0
  16. package/docs/v7/api/mouseUp.mdx +164 -0
  17. package/docs/v7/api/rightClick.mdx +123 -0
  18. package/docs/v7/getting-started/configuration.mdx +380 -0
  19. package/docs/v7/getting-started/quickstart.mdx +273 -140
  20. package/docs/v7/guides/best-practices.mdx +486 -0
  21. package/docs/v7/guides/caching-ai.mdx +215 -0
  22. package/docs/v7/guides/caching-selectors.mdx +292 -0
  23. package/docs/v7/guides/caching.mdx +366 -0
  24. package/docs/v7/guides/ci-cd/azure.mdx +587 -0
  25. package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
  26. package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
  27. package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
  28. package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
  29. package/docs/v7/guides/ci-cd/travis.mdx +438 -0
  30. package/docs/v7/guides/debugging.mdx +349 -0
  31. package/docs/v7/guides/faq.mdx +393 -0
  32. package/docs/v7/guides/performance.mdx +517 -0
  33. package/docs/v7/guides/troubleshooting.mdx +526 -0
  34. package/docs/v7/guides/vitest-plugin.mdx +477 -0
  35. package/docs/v7/guides/vitest.mdx +535 -0
  36. package/docs/v7/platforms/linux.mdx +308 -0
  37. package/docs/v7/platforms/macos.mdx +433 -0
  38. package/docs/v7/platforms/windows.mdx +430 -0
  39. package/docs/v7/presets/chrome-extension.mdx +223 -0
  40. package/docs/v7/presets/chrome.mdx +287 -0
  41. package/docs/v7/presets/electron.mdx +435 -0
  42. package/docs/v7/presets/vscode.mdx +398 -0
  43. package/docs/v7/presets/webapp.mdx +396 -0
  44. package/docs/v7/progressive-apis/CORE.md +459 -0
  45. package/docs/v7/progressive-apis/HOOKS.md +360 -0
  46. package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
  47. package/docs/v7/progressive-apis/PROVISION.md +266 -0
  48. package/interfaces/vitest-plugin.mjs +186 -100
  49. package/package.json +12 -1
  50. package/sdk.d.ts +335 -42
  51. package/sdk.js +756 -95
  52. package/src/core/Dashcam.js +469 -0
  53. package/src/core/index.d.ts +150 -0
  54. package/src/core/index.js +12 -0
  55. package/src/presets/index.mjs +331 -0
  56. package/src/vitest/extended.mjs +108 -0
  57. package/src/vitest/hooks.d.ts +119 -0
  58. package/src/vitest/hooks.mjs +298 -0
  59. package/src/vitest/index.mjs +64 -0
  60. package/src/vitest/lifecycle.mjs +277 -0
  61. package/src/vitest/utils.mjs +150 -0
  62. package/test/dashcam.test.js +137 -0
  63. package/testdriver/acceptance-sdk/assert.test.mjs +13 -31
  64. package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
  65. package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
  66. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +7 -19
  67. package/testdriver/acceptance-sdk/element-not-found.test.mjs +6 -19
  68. package/testdriver/acceptance-sdk/exec-js.test.mjs +6 -18
  69. package/testdriver/acceptance-sdk/exec-output.test.mjs +8 -20
  70. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +13 -25
  71. package/testdriver/acceptance-sdk/focus-window.test.mjs +8 -20
  72. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +5 -20
  73. package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
  74. package/testdriver/acceptance-sdk/hover-image.test.mjs +10 -19
  75. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +7 -19
  76. package/testdriver/acceptance-sdk/hover-text.test.mjs +5 -19
  77. package/testdriver/acceptance-sdk/match-image.test.mjs +7 -19
  78. package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
  79. package/testdriver/acceptance-sdk/press-keys.test.mjs +5 -19
  80. package/testdriver/acceptance-sdk/prompt.test.mjs +6 -18
  81. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +6 -20
  82. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +6 -18
  83. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +9 -23
  84. package/testdriver/acceptance-sdk/scroll.test.mjs +12 -21
  85. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +124 -352
  86. package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
  87. package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
  88. package/testdriver/acceptance-sdk/type.test.mjs +19 -58
  89. package/vitest.config.mjs +1 -0
  90. package/.vscode/mcp.json +0 -9
  91. package/MIGRATION.md +0 -389
  92. package/PLUGIN_MIGRATION.md +0 -222
  93. package/PROMPT_CACHE.md +0 -200
  94. package/SDK_LOGGING.md +0 -222
  95. package/SDK_MIGRATION.md +0 -474
  96. package/SDK_README.md +0 -1122
  97. package/debug-screenshot-1763401388589.png +0 -0
  98. package/examples/run-tests-with-recording.sh +0 -70
  99. package/examples/screenshot-example.js +0 -63
  100. package/examples/sdk-awesome-logs-demo.js +0 -177
  101. package/examples/sdk-cache-thresholds.js +0 -96
  102. package/examples/sdk-element-properties.js +0 -155
  103. package/examples/sdk-simple-example.js +0 -65
  104. package/examples/test-recording-example.test.js +0 -166
  105. package/mcp-server/AI_GUIDELINES.md +0 -57
  106. package/test-find-api.js +0 -73
  107. package/test-prompt-cache.js +0 -96
  108. package/test-sandbox-render.js +0 -28
  109. package/test-sdk-methods.js +0 -15
  110. package/test-sdk-refactor.js +0 -53
  111. package/test-stack-trace.mjs +0 -57
  112. package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
@@ -4,6 +4,38 @@ import os from "os";
4
4
  import path from "path";
5
5
  import { setTestRunInfo } from "./shared-test-state.mjs";
6
6
 
7
+ /**
8
+ * Simple logger for the vitest plugin
9
+ * Supports log levels: debug, info, warn, error
10
+ * Control via TD_LOG_LEVEL environment variable (default: "info")
11
+ * Set TD_LOG_LEVEL=debug for verbose output
12
+ */
13
+ const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
14
+ const currentLogLevel = LOG_LEVELS[process.env.TD_LOG_LEVEL?.toLowerCase()] ?? LOG_LEVELS.info;
15
+
16
+ const logger = {
17
+ debug: (...args) => {
18
+ if (currentLogLevel <= LOG_LEVELS.debug) {
19
+ console.log("[TestDriver]", ...args);
20
+ }
21
+ },
22
+ info: (...args) => {
23
+ if (currentLogLevel <= LOG_LEVELS.info) {
24
+ console.log("[TestDriver]", ...args);
25
+ }
26
+ },
27
+ warn: (...args) => {
28
+ if (currentLogLevel <= LOG_LEVELS.warn) {
29
+ console.warn("[TestDriver]", ...args);
30
+ }
31
+ },
32
+ error: (...args) => {
33
+ if (currentLogLevel <= LOG_LEVELS.error) {
34
+ console.error("[TestDriver]", ...args);
35
+ }
36
+ },
37
+ };
38
+
7
39
  /**
8
40
  * Timeout wrapper for promises
9
41
  * @param {Promise} promise - Promise to wrap
@@ -58,6 +90,7 @@ function withTimeout(promise, timeoutMs, operationName) {
58
90
  export const pluginState = {
59
91
  testRun: null,
60
92
  testRunId: null,
93
+ testRunCompleted: false,
61
94
  client: null,
62
95
  startTime: null,
63
96
  testCases: new Map(),
@@ -68,6 +101,8 @@ export const pluginState = {
68
101
  gitInfo: {},
69
102
  apiKey: null,
70
103
  apiRoot: null,
104
+ // TestDriver options to pass to all instances
105
+ testDriverOptions: {},
71
106
  // Dashcam URL tracking (in-memory, no files needed!)
72
107
  dashcamUrls: new Map(), // testId -> dashcamUrl
73
108
  lastDashcamUrl: null, // Fallback for when test ID isn't available
@@ -77,7 +112,7 @@ export const pluginState = {
77
112
 
78
113
  // Export functions that can be used by the reporter or tests
79
114
  export function registerDashcamUrl(testId, url, platform) {
80
- console.log(`[Plugin] Registering dashcam URL for test ${testId}:`, url);
115
+ logger.debug(`Registering dashcam URL for test ${testId}:`, url);
81
116
  pluginState.dashcamUrls.set(testId, { url, platform });
82
117
  pluginState.lastDashcamUrl = url;
83
118
  }
@@ -96,7 +131,7 @@ export function getSuiteTestRun(suiteId) {
96
131
  }
97
132
 
98
133
  export function setSuiteTestRun(suiteId, runData) {
99
- console.log(`[Plugin] Setting test run for suite ${suiteId}:`, runData);
134
+ logger.debug(`Setting test run for suite ${suiteId}:`, runData);
100
135
  pluginState.suiteTestRuns.set(suiteId, runData);
101
136
  }
102
137
 
@@ -183,6 +218,75 @@ export async function recordTestCaseDirect(token, apiRoot, testCaseData) {
183
218
  return await response.json();
184
219
  }
185
220
 
221
+ /**
222
+ * Handle process termination and mark test run as cancelled
223
+ */
224
+ async function handleProcessExit() {
225
+ if (!pluginState.testRun || !pluginState.testRunId) {
226
+ return;
227
+ }
228
+
229
+ logger.info("Process interrupted, marking test run as cancelled...");
230
+
231
+ try {
232
+ const stats = {
233
+ totalTests: pluginState.testCases.size,
234
+ passedTests: 0,
235
+ failedTests: 0,
236
+ skippedTests: 0,
237
+ };
238
+
239
+ const completeData = {
240
+ runId: pluginState.testRunId,
241
+ status: "cancelled",
242
+ totalTests: stats.totalTests,
243
+ passedTests: stats.passedTests,
244
+ failedTests: stats.failedTests,
245
+ skippedTests: stats.skippedTests,
246
+ duration: Date.now() - pluginState.startTime,
247
+ };
248
+
249
+ // Update platform if detected
250
+ const platform = getPlatform();
251
+ if (platform) {
252
+ completeData.platform = platform;
253
+ }
254
+
255
+ await completeTestRun(completeData);
256
+ logger.info("✅ Test run marked as cancelled");
257
+ } catch (error) {
258
+ logger.error("Failed to mark test run as cancelled:", error.message);
259
+ }
260
+ }
261
+
262
+ // Set up process exit handlers
263
+ let exitHandlersRegistered = false;
264
+
265
+ function registerExitHandlers() {
266
+ if (exitHandlersRegistered) return;
267
+ exitHandlersRegistered = true;
268
+
269
+ // Handle Ctrl+C
270
+ process.on("SIGINT", async () => {
271
+ await handleProcessExit();
272
+ process.exit(130); // Standard exit code for SIGINT
273
+ });
274
+
275
+ // Handle kill command
276
+ process.on("SIGTERM", async () => {
277
+ await handleProcessExit();
278
+ process.exit(143); // Standard exit code for SIGTERM
279
+ });
280
+
281
+ // Handle unexpected exits
282
+ process.on("beforeExit", async () => {
283
+ // Only handle if test run is still running (hasn't been completed normally)
284
+ if (pluginState.testRun && !pluginState.testRunCompleted) {
285
+ await handleProcessExit();
286
+ }
287
+ });
288
+ }
289
+
186
290
  /**
187
291
  * Create the TestDriver Vitest plugin
188
292
  * This sets up global state and provides the registration API
@@ -194,12 +298,19 @@ export default function testDriverPlugin(options = {}) {
194
298
  options.apiRoot || process.env.TD_API_ROOT || "http://localhost:1337";
195
299
  pluginState.ciProvider = detectCI();
196
300
  pluginState.gitInfo = getGitInfo();
301
+
302
+ // Store TestDriver-specific options (excluding plugin-specific ones)
303
+ const { apiKey, apiRoot, ...testDriverOptions } = options;
304
+ pluginState.testDriverOptions = testDriverOptions;
305
+
306
+ // Register process exit handlers to handle cancellation
307
+ registerExitHandlers();
197
308
 
198
309
  // Note: globalThis setup happens in vitestSetup.mjs for worker processes
199
- console.log(
200
- "[TestDriver Plugin] Initialized with API root:",
201
- pluginState.apiRoot,
202
- );
310
+ logger.debug("Initialized with API root:", pluginState.apiRoot);
311
+ if (Object.keys(testDriverOptions).length > 0) {
312
+ logger.debug("Global TestDriver options:", testDriverOptions);
313
+ }
203
314
 
204
315
  return new TestDriverReporter(options);
205
316
  }
@@ -211,25 +322,23 @@ export default function testDriverPlugin(options = {}) {
211
322
  class TestDriverReporter {
212
323
  constructor(options = {}) {
213
324
  this.options = options;
214
- console.log("[TestDriver Reporter] Created");
325
+ logger.debug("Reporter created");
215
326
  }
216
327
 
217
328
  async onInit(ctx) {
218
329
  this.ctx = ctx;
219
- console.log("[TestDriver Reporter] onInit called");
330
+ logger.debug("onInit called");
220
331
 
221
332
  // Initialize test run
222
333
  await this.initializeTestRun();
223
334
  }
224
335
 
225
336
  async initializeTestRun() {
226
- console.log("[TestDriver Reporter] Initializing test run...");
337
+ logger.debug("Initializing test run...");
227
338
 
228
339
  // Check if we should enable the reporter
229
340
  if (!pluginState.apiKey) {
230
- console.log(
231
- "[TestDriver Reporter] No API key provided, skipping test recording",
232
- );
341
+ logger.debug("No API key provided, skipping test recording");
233
342
  return;
234
343
  }
235
344
 
@@ -240,6 +349,7 @@ class TestDriverReporter {
240
349
  // Generate unique run ID
241
350
  pluginState.testRunId = generateRunId();
242
351
  pluginState.startTime = Date.now();
352
+ pluginState.testRunCompleted = false; // Reset completion flag
243
353
 
244
354
  // Create test run via direct API call
245
355
  const testRunData = {
@@ -248,6 +358,8 @@ class TestDriverReporter {
248
358
  ...pluginState.gitInfo,
249
359
  };
250
360
 
361
+ // Session ID will be added from the first test result file that includes it
362
+
251
363
  // Only add ciProvider if it's not null
252
364
  if (pluginState.ciProvider) {
253
365
  testRunData.ciProvider = pluginState.ciProvider;
@@ -274,31 +386,24 @@ class TestDriverReporter {
274
386
  startTime: pluginState.startTime,
275
387
  });
276
388
 
277
- console.log(
278
- `[TestDriver Reporter] Test run created: ${pluginState.testRunId}`,
279
- );
389
+ logger.info(`Test run created: ${pluginState.testRunId}`);
280
390
  } catch (error) {
281
- console.error(
282
- "[TestDriver Reporter] Failed to initialize:",
283
- error.message,
284
- );
391
+ logger.error("Failed to initialize:", error.message);
285
392
  pluginState.apiKey = null;
286
393
  pluginState.token = null;
287
394
  }
288
395
  }
289
396
 
290
397
  async onTestRunEnd(testModules, unhandledErrors, reason) {
291
- console.log("[TestDriver Reporter] Test run ending with reason:", reason);
398
+ logger.debug("Test run ending with reason:", reason);
292
399
 
293
400
  if (!pluginState.apiKey) {
294
- console.log("[TestDriver Reporter] Skipping completion - no API key");
401
+ logger.debug("Skipping completion - no API key");
295
402
  return;
296
403
  }
297
404
 
298
405
  if (!pluginState.testRun) {
299
- console.log(
300
- "[TestDriver Reporter] Skipping completion - no test run created",
301
- );
406
+ logger.debug("Skipping completion - no test run created");
302
407
  return;
303
408
  }
304
409
 
@@ -306,7 +411,7 @@ class TestDriverReporter {
306
411
  // Calculate statistics from testModules
307
412
  const stats = calculateStatsFromModules(testModules);
308
413
 
309
- console.log(`[TestDriver Reporter] Stats:`, stats);
414
+ logger.debug("Stats:", stats);
310
415
 
311
416
  // Determine overall status based on reason and stats
312
417
  let status = "passed";
@@ -319,9 +424,7 @@ class TestDriverReporter {
319
424
  }
320
425
 
321
426
  // Complete test run via API
322
- console.log(
323
- `[TestDriver Reporter] Completing test run ${pluginState.testRunId} with status: ${status}`,
324
- );
427
+ logger.debug(`Completing test run ${pluginState.testRunId} with status: ${status}`);
325
428
 
326
429
  const completeData = {
327
430
  runId: pluginState.testRunId,
@@ -337,39 +440,28 @@ class TestDriverReporter {
337
440
  const platform = getPlatform();
338
441
  if (platform) {
339
442
  completeData.platform = platform;
340
- console.log(
341
- `[TestDriver Reporter] Updating test run with platform: ${platform}`,
342
- );
443
+ logger.debug(`Updating test run with platform: ${platform}`);
343
444
  }
344
445
 
345
446
  // Wait for any pending operations (shouldn't be any, but just in case)
346
447
  if (pluginState.pendingTestCaseRecords.size > 0) {
347
- console.log(
348
- `[TestDriver Reporter] Waiting for ${pluginState.pendingTestCaseRecords.size} pending operations...`,
349
- );
448
+ logger.debug(`Waiting for ${pluginState.pendingTestCaseRecords.size} pending operations...`);
350
449
  await Promise.all(Array.from(pluginState.pendingTestCaseRecords));
351
450
  }
352
451
 
353
452
  // Test cases are reported directly from teardownTest
354
- console.log(
355
- `[TestDriver Reporter] All test cases reported from teardown`,
356
- );
453
+ logger.debug("All test cases reported from teardown");
357
454
 
358
455
  const completeResponse = await completeTestRun(completeData);
359
- console.log(
360
- `[TestDriver Reporter] ✅ Test run completion API response:`,
361
- completeResponse,
362
- );
456
+ logger.debug("Test run completion API response:", completeResponse);
363
457
 
364
- console.log(
365
- `[TestDriver Reporter] Test run completed: ${stats.passedTests}/${stats.totalTests} passed`,
366
- );
458
+ // Mark test run as completed to prevent duplicate completion
459
+ pluginState.testRunCompleted = true;
460
+
461
+ logger.info(`✅ Test run completed: ${stats.passedTests}/${stats.totalTests} passed`);
367
462
  } catch (error) {
368
- console.error(
369
- "[TestDriver Reporter] Failed to complete test run:",
370
- error.message,
371
- );
372
- console.error("[TestDriver Reporter] Error stack:", error.stack);
463
+ logger.error("Failed to complete test run:", error.message);
464
+ logger.debug("Error stack:", error.stack);
373
465
  }
374
466
  }
375
467
 
@@ -396,15 +488,19 @@ class TestDriverReporter {
396
488
  ? "skipped"
397
489
  : "failed";
398
490
 
399
- console.log(
400
- `[TestDriver Reporter] Test case completed: ${test.name} (${status})`,
401
- );
491
+ logger.info(`Test case completed: ${test.name} (${status})`);
492
+
493
+ // Calculate duration from tracked start time
494
+ const testCase = pluginState.testCases.get(test.id);
495
+ const duration = testCase ? Date.now() - testCase.startTime : 0;
496
+
497
+ logger.debug(`Calculated duration: ${duration}ms (startTime: ${testCase?.startTime}, now: ${Date.now()})`);
402
498
 
403
499
  // Read test metadata from file (cross-process communication)
404
500
  let dashcamUrl = null;
501
+ let sessionId = null;
405
502
  let testFile = "unknown";
406
503
  let testOrder = 0;
407
- let duration = result.duration || 0;
408
504
 
409
505
  const testResultFile = path.join(
410
506
  os.tmpdir(),
@@ -412,11 +508,15 @@ class TestDriverReporter {
412
508
  `${test.id}.json`,
413
509
  );
414
510
 
511
+ logger.debug(`Looking for test result file with test.id: ${test.id}`);
512
+ logger.debug(`Test result file path: ${testResultFile}`);
513
+
415
514
  try {
416
515
  if (fs.existsSync(testResultFile)) {
417
516
  const testResult = JSON.parse(fs.readFileSync(testResultFile, "utf-8"));
418
517
  dashcamUrl = testResult.dashcamUrl || null;
419
518
  const platform = testResult.platform || null;
519
+ sessionId = testResult.sessionId || null;
420
520
  testFile =
421
521
  testResult.testFile ||
422
522
  test.file?.filepath ||
@@ -424,18 +524,15 @@ class TestDriverReporter {
424
524
  "unknown";
425
525
  testOrder =
426
526
  testResult.testOrder !== undefined ? testResult.testOrder : 0;
427
- duration = testResult.duration || result.duration || 0;
527
+ // Don't override duration from file - use Vitest's result.duration
528
+ // duration is already set above from result.duration
428
529
 
429
- console.log(
430
- `[TestDriver Reporter] ✅ Read from file - dashcam: ${dashcamUrl}, platform: ${platform}, testFile: ${testFile}, testOrder: ${testOrder}, duration: ${duration}ms`,
431
- );
530
+ logger.debug(`Read from file - dashcam: ${dashcamUrl}, platform: ${platform}, sessionId: ${sessionId}, testFile: ${testFile}, testOrder: ${testOrder}, duration: ${duration}ms`);
432
531
 
433
532
  // Update test run platform from first test that reports it
434
533
  if (platform && !pluginState.detectedPlatform) {
435
534
  pluginState.detectedPlatform = platform;
436
- console.log(
437
- `[TestDriver Reporter] 🖥️ Detected platform from test: ${platform}`,
438
- );
535
+ logger.debug(`Detected platform from test: ${platform}`);
439
536
  }
440
537
 
441
538
  // Clean up the file after reading
@@ -445,37 +542,36 @@ class TestDriverReporter {
445
542
  // Ignore cleanup errors
446
543
  }
447
544
  } else {
448
- console.log(
449
- `[TestDriver Reporter] ⚠️ No result file found for test: ${test.id}`,
450
- );
545
+ logger.debug(`No result file found for test: ${test.id}`);
451
546
  // Fallback to test object properties - try multiple sources
452
- // In Vitest, the file path is typically on the module, not the test itself
453
- const module = test.module || test.suite;
547
+ // In Vitest, the file path is on test.module.task.filepath
454
548
  testFile =
549
+ test.module?.task?.filepath ||
550
+ test.module?.file?.filepath ||
551
+ test.module?.file?.name ||
455
552
  test.file?.filepath ||
456
553
  test.file?.name ||
457
- module?.file?.filepath ||
458
- module?.file?.name ||
554
+ test.suite?.file?.filepath ||
555
+ test.suite?.file?.name ||
459
556
  test.location?.file ||
460
557
  "unknown";
461
- console.log(
462
- `[TestDriver Reporter] 📂 Resolved testFile for skipped test: ${testFile}`,
463
- );
558
+ logger.debug(`Resolved testFile: ${testFile}`);
464
559
  }
465
560
  } catch (error) {
466
- console.error(
467
- `[TestDriver Reporter] ❌ Failed to read test result file:`,
468
- error.message,
469
- );
561
+ logger.error("Failed to read test result file:", error.message);
470
562
  // Fallback to test object properties - try multiple sources
471
- const module = test.module || test.suite;
563
+ // In Vitest, the file path is on test.module.task.filepath
472
564
  testFile =
565
+ test.module?.task?.filepath ||
566
+ test.module?.file?.filepath ||
567
+ test.module?.file?.name ||
473
568
  test.file?.filepath ||
474
569
  test.file?.name ||
475
- module?.file?.filepath ||
476
- module?.file?.name ||
570
+ test.suite?.file?.filepath ||
571
+ test.suite?.file?.name ||
477
572
  test.location?.file ||
478
573
  "unknown";
574
+ logger.debug(`Resolved testFile from fallback: ${testFile}`);
479
575
  }
480
576
 
481
577
  // Get test run info from environment variables
@@ -483,9 +579,7 @@ class TestDriverReporter {
483
579
  const token = process.env.TD_TEST_RUN_TOKEN;
484
580
 
485
581
  if (!testRunId || !token) {
486
- console.warn(
487
- `[TestDriver Reporter] ⚠️ Test run not initialized, skipping test case recording for: ${test.name}`,
488
- );
582
+ logger.warn(`Test run not initialized, skipping test case recording for: ${test.name}`);
489
583
  return;
490
584
  }
491
585
 
@@ -519,6 +613,11 @@ class TestDriverReporter {
519
613
  retries: result.retryCount || 0,
520
614
  };
521
615
 
616
+ // Add sessionId if available
617
+ if (sessionId) {
618
+ testCaseData.sessionId = sessionId;
619
+ }
620
+
522
621
  // Only include replayUrl if we have a valid dashcam URL
523
622
  if (dashcamUrl) {
524
623
  testCaseData.replayUrl = dashcamUrl;
@@ -528,9 +627,7 @@ class TestDriverReporter {
528
627
  if (errorMessage) testCaseData.errorMessage = errorMessage;
529
628
  if (errorStack) testCaseData.errorStack = errorStack;
530
629
 
531
- console.log(
532
- `[TestDriver Reporter] Recording test case: ${test.name} (${status}) with testFile: ${testFile}, testOrder: ${testOrder}, duration: ${duration}ms, replay: ${dashcamUrl ? "yes" : "no"}`,
533
- );
630
+ logger.debug(`Recording test case: ${test.name} (${status}) with testFile: ${testFile}, testOrder: ${testOrder}, duration: ${duration}ms, replay: ${dashcamUrl ? "yes" : "no"}`);
534
631
 
535
632
  const testCaseResponse = await recordTestCaseDirect(
536
633
  token,
@@ -541,17 +638,10 @@ class TestDriverReporter {
541
638
  const testCaseDbId = testCaseResponse.data?.id;
542
639
  const testRunDbId = process.env.TD_TEST_RUN_DB_ID;
543
640
 
544
- console.log(
545
- `[TestDriver Reporter] ✅ Reported test case to API${dashcamUrl ? " with dashcam URL" : ""}`,
546
- );
547
- console.log(
548
- `[TestDriver Reporter] 🔗 View test: ${pluginState.apiRoot.replace("testdriver-api.onrender.com", "app.testdriver.ai")}/test-runs/${testRunDbId}/${testCaseDbId}`,
549
- );
641
+ logger.debug(`Reported test case to API${dashcamUrl ? " with dashcam URL" : ""}`);
642
+ logger.info(`🔗 View test: ${pluginState.apiRoot.replace("testdriver-api.onrender.com", "app.testdriver.ai")}/runs/${testRunDbId}/${testCaseDbId}`);
550
643
  } catch (error) {
551
- console.error(
552
- `[TestDriver Reporter] ❌ Failed to report test case:`,
553
- error.message,
554
- );
644
+ logger.error("Failed to report test case:", error.message);
555
645
  }
556
646
  }
557
647
  }
@@ -571,13 +661,11 @@ function getSuiteName() {
571
661
  function getPlatform() {
572
662
  // First try to get platform from SDK client detected during test execution
573
663
  if (pluginState.detectedPlatform) {
574
- console.log(
575
- `[TestDriver Plugin] Using platform from SDK client: ${pluginState.detectedPlatform}`,
576
- );
664
+ logger.debug(`Using platform from SDK client: ${pluginState.detectedPlatform}`);
577
665
  return pluginState.detectedPlatform;
578
666
  }
579
667
 
580
- console.log(`[TestDriver Plugin] Platform not yet detected from client`);
668
+ logger.debug("Platform not yet detected from client");
581
669
  return null;
582
670
  }
583
671
 
@@ -594,9 +682,7 @@ function detectPlatformFromTest(test) {
594
682
  else if (platform === "linux") platform = "linux";
595
683
 
596
684
  pluginState.detectedPlatform = platform;
597
- console.log(
598
- `[TestDriver Plugin] Detected platform from test context: ${platform}`,
599
- );
685
+ logger.debug(`Detected platform from test context: ${platform}`);
600
686
  }
601
687
  }
602
688
 
package/package.json CHANGED
@@ -1,8 +1,19 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
+ "exports": {
7
+ ".": "./sdk.js",
8
+ "./core": "./src/core/index.js",
9
+ "./vitest": "./src/vitest/index.mjs",
10
+ "./vitest/hooks": "./src/vitest/hooks.mjs",
11
+ "./vitest/extended": "./src/vitest/extended.mjs",
12
+ "./vitest/lifecycle": "./src/vitest/lifecycle.mjs",
13
+ "./vitest/utils": "./src/vitest/utils.mjs",
14
+ "./vitest/plugin": "./interfaces/vitest-plugin.mjs",
15
+ "./presets": "./src/presets/index.mjs"
16
+ },
6
17
  "bin": {
7
18
  "testdriverai": "bin/testdriverai.js"
8
19
  },