testdriverai 7.1.4 → 7.2.2

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 (72) hide show
  1. package/.github/workflows/acceptance.yaml +81 -0
  2. package/.github/workflows/publish.yaml +44 -0
  3. package/agent/index.js +18 -19
  4. package/agent/interface.js +4 -0
  5. package/agent/lib/commands.js +321 -121
  6. package/agent/lib/redraw.js +99 -39
  7. package/agent/lib/sandbox.js +98 -6
  8. package/agent/lib/sdk.js +25 -0
  9. package/agent/lib/system.js +2 -1
  10. package/agent/lib/validation.js +6 -6
  11. package/docs/docs.json +211 -101
  12. package/docs/snippets/tests/type-repeated-replay.mdx +1 -1
  13. package/docs/v7/_drafts/caching-selectors.mdx +24 -0
  14. package/docs/v7/api/act.mdx +1 -1
  15. package/docs/v7/api/assert.mdx +1 -1
  16. package/docs/v7/api/assertions.mdx +7 -7
  17. package/docs/v7/api/elements.mdx +78 -0
  18. package/docs/v7/api/find.mdx +38 -0
  19. package/docs/v7/api/focusApplication.mdx +2 -2
  20. package/docs/v7/api/hover.mdx +2 -2
  21. package/docs/v7/features/ai-native.mdx +57 -71
  22. package/docs/v7/features/application-logs.mdx +353 -0
  23. package/docs/v7/features/browser-logs.mdx +414 -0
  24. package/docs/v7/features/cache-management.mdx +402 -0
  25. package/docs/v7/features/continuous-testing.mdx +346 -0
  26. package/docs/v7/features/coverage.mdx +508 -0
  27. package/docs/v7/features/data-driven-testing.mdx +441 -0
  28. package/docs/v7/features/easy-to-write.mdx +2 -73
  29. package/docs/v7/features/enterprise.mdx +155 -39
  30. package/docs/v7/features/fast.mdx +63 -81
  31. package/docs/v7/features/managed-sandboxes.mdx +384 -0
  32. package/docs/v7/features/network-monitoring.mdx +568 -0
  33. package/docs/v7/features/observable.mdx +3 -22
  34. package/docs/v7/features/parallel-execution.mdx +381 -0
  35. package/docs/v7/features/powerful.mdx +1 -1
  36. package/docs/v7/features/reports.mdx +414 -0
  37. package/docs/v7/features/sandbox-customization.mdx +229 -0
  38. package/docs/v7/features/scalable.mdx +217 -2
  39. package/docs/v7/features/stable.mdx +106 -147
  40. package/docs/v7/features/system-performance.mdx +616 -0
  41. package/docs/v7/features/test-analytics.mdx +373 -0
  42. package/docs/v7/features/test-cases.mdx +393 -0
  43. package/docs/v7/features/test-replays.mdx +408 -0
  44. package/docs/v7/features/test-reports.mdx +308 -0
  45. package/docs/v7/getting-started/{running-and-debugging.mdx → debugging-tests.mdx} +12 -142
  46. package/docs/v7/getting-started/quickstart.mdx +22 -305
  47. package/docs/v7/getting-started/running-tests.mdx +173 -0
  48. package/docs/v7/overview/what-is-testdriver.mdx +2 -14
  49. package/docs/v7/presets/chrome-extension.mdx +147 -122
  50. package/interfaces/cli/commands/init.js +3 -3
  51. package/interfaces/cli/lib/base.js +3 -2
  52. package/interfaces/logger.js +0 -2
  53. package/interfaces/shared-test-state.mjs +0 -5
  54. package/interfaces/vitest-plugin.mjs +70 -50
  55. package/lib/core/Dashcam.js +60 -85
  56. package/lib/vitest/hooks.mjs +42 -50
  57. package/package.json +1 -1
  58. package/sdk-log-formatter.js +350 -175
  59. package/sdk.d.ts +36 -3
  60. package/sdk.js +431 -116
  61. package/setup/aws/cloudformation.yaml +2 -2
  62. package/setup/aws/self-hosted.yml +1 -1
  63. package/test/testdriver/chrome-extension.test.mjs +55 -72
  64. package/test/testdriver/element-not-found.test.mjs +2 -1
  65. package/test/testdriver/hover-image.test.mjs +1 -1
  66. package/test/testdriver/scroll-until-text.test.mjs +10 -6
  67. package/test/testdriver/setup/lifecycleHelpers.mjs +19 -24
  68. package/test/testdriver/setup/testHelpers.mjs +18 -23
  69. package/vitest.config.mjs +3 -3
  70. package/.github/workflows/linux-tests.yml +0 -28
  71. package/docs/v7/getting-started/generating-tests.mdx +0 -525
  72. package/test/testdriver/auto-cache-key-demo.test.mjs +0 -56
@@ -19,6 +19,7 @@ import fs from 'fs';
19
19
  import os from 'os';
20
20
  import path from 'path';
21
21
  import { vi } from 'vitest';
22
+ import chalk from 'chalk';
22
23
  import TestDriverSDK from '../../sdk.js';
23
24
 
24
25
  /**
@@ -103,7 +104,6 @@ function setupConsoleSpy(client, taskId) {
103
104
  // Store spies on client for cleanup
104
105
  client._consoleSpies = { logSpy, errorSpy, warnSpy, infoSpy };
105
106
 
106
- console.log(`[testdriver] Console spy set up for task: ${taskId}`);
107
107
  }
108
108
 
109
109
  /**
@@ -162,6 +162,13 @@ export function TestDriver(context, options = {}) {
162
162
  // Merge options: plugin global options < test-specific options
163
163
  const mergedOptions = { ...pluginOptions, ...options };
164
164
 
165
+ // Support TD_OS environment variable for specifying target OS (linux, mac, windows)
166
+ // Priority: test options > plugin options > environment variable > default (linux)
167
+ if (!mergedOptions.os && process.env.TD_OS) {
168
+ mergedOptions.os = process.env.TD_OS;
169
+ console.log(`[testdriver] Set mergedOptions.os = ${mergedOptions.os} from TD_OS environment variable`);
170
+ }
171
+
165
172
  // Extract TestDriver-specific options
166
173
  const apiKey = mergedOptions.apiKey || process.env.TD_API_KEY;
167
174
 
@@ -191,9 +198,7 @@ export function TestDriver(context, options = {}) {
191
198
 
192
199
  await testdriver.auth();
193
200
  await testdriver.connect();
194
-
195
- console.log('[testdriver] ✅ Connected to sandbox');
196
-
201
+
197
202
  if (debugConsoleSpy) {
198
203
  console.log('[DEBUG] After connect - sandbox.instanceSocketConnected:', testdriver.sandbox?.instanceSocketConnected);
199
204
  console.log('[DEBUG] After connect - sandbox.send:', typeof testdriver.sandbox?.send);
@@ -213,7 +218,6 @@ export function TestDriver(context, options = {}) {
213
218
  : `touch ${logPath}`;
214
219
 
215
220
  await testdriver.exec(shell, createLogCmd, 10000, true);
216
- console.log('[testdriver] ✅ Created log file:', logPath);
217
221
 
218
222
  // Add automatic log tracking when dashcam starts
219
223
  // Store original start method
@@ -226,56 +230,45 @@ export function TestDriver(context, options = {}) {
226
230
  // Register cleanup handler with dashcam.stop()
227
231
  if (!lifecycleHandlers.has(context.task)) {
228
232
  const cleanup = async () => {
229
- console.log('[testdriver] Cleaning up TestDriver client...');
230
233
  try {
231
234
  // Stop dashcam if it was started - with timeout to prevent hanging
232
235
  if (testdriver._dashcam && testdriver._dashcam.recording) {
233
236
  try {
234
- // Add a timeout wrapper to prevent dashcam.stop from hanging indefinitely
235
- const stopWithTimeout = Promise.race([
236
- testdriver.dashcam.stop(),
237
- new Promise((_, reject) =>
238
- setTimeout(() => reject(new Error('Dashcam stop timed out after 30s')), 30000)
239
- )
240
- ]);
237
+ const dashcamUrl = await testdriver.dashcam.stop();
238
+ console.log('');
239
+ console.log('🎥' + chalk.yellow(` Dashcam URL`) + `: ${dashcamUrl}`);
240
+ console.log('');
241
+ // Write test result to file for the reporter (cross-process communication)
242
+ // This should happen regardless of whether dashcam succeeded, to ensure platform info is available
243
+ const testId = context.task.id;
244
+ const platform = testdriver.os || 'linux';
245
+ const absolutePath = context.task.file?.filepath || context.task.file?.name || 'unknown';
246
+ const projectRoot = process.cwd();
247
+ const testFile = absolutePath !== 'unknown'
248
+ ? path.relative(projectRoot, absolutePath)
249
+ : absolutePath;
250
+
251
+ // Create results directory if it doesn't exist
252
+ const resultsDir = path.join(os.tmpdir(), 'testdriver-results');
253
+ if (!fs.existsSync(resultsDir)) {
254
+ fs.mkdirSync(resultsDir, { recursive: true });
255
+ }
256
+
257
+ // Write test result file
258
+ const testResultFile = path.join(resultsDir, `${testId}.json`);
259
+ const testResult = {
260
+ dashcamUrl: dashcamUrl || null,
261
+ platform,
262
+ testFile,
263
+ testOrder: 0,
264
+ sessionId: testdriver.getSessionId(),
265
+ };
241
266
 
242
- const dashcamUrl = await stopWithTimeout;
243
- console.log('🎥 Dashcam URL:', dashcamUrl);
267
+ fs.writeFileSync(testResultFile, JSON.stringify(testResult, null, 2));
244
268
 
245
- // Write dashcam URL to file for the reporter (cross-process communication)
246
- if (dashcamUrl) {
247
- const testId = context.task.id;
248
- const platform = testdriver.os || 'linux';
249
- const absolutePath = context.task.file?.filepath || context.task.file?.name || 'unknown';
250
- const projectRoot = process.cwd();
251
- const testFile = absolutePath !== 'unknown'
252
- ? path.relative(projectRoot, absolutePath)
253
- : absolutePath;
254
-
255
- // Create results directory if it doesn't exist
256
- const resultsDir = path.join(os.tmpdir(), 'testdriver-results');
257
- if (!fs.existsSync(resultsDir)) {
258
- fs.mkdirSync(resultsDir, { recursive: true });
259
- }
260
-
261
- // Write test result file
262
- const testResultFile = path.join(resultsDir, `${testId}.json`);
263
- const testResult = {
264
- dashcamUrl,
265
- platform,
266
- testFile,
267
- testOrder: 0,
268
- sessionId: testdriver.getSessionId(),
269
- };
270
-
271
- fs.writeFileSync(testResultFile, JSON.stringify(testResult, null, 2));
272
- console.log(`[testdriver] ✅ Wrote dashcam URL to ${testResultFile}`);
273
-
274
- // Also register in memory if plugin is available
275
- if (globalThis.__testdriverPlugin?.registerDashcamUrl) {
276
- globalThis.__testdriverPlugin.registerDashcamUrl(testId, dashcamUrl, platform);
277
- console.log(`[testdriver] ✅ Registered dashcam URL in memory for test ${testId}`);
278
- }
269
+ // Also register in memory if plugin is available
270
+ if (globalThis.__testdriverPlugin?.registerDashcamUrl) {
271
+ globalThis.__testdriverPlugin.registerDashcamUrl(testId, dashcamUrl, platform);
279
272
  }
280
273
  } catch (error) {
281
274
  // Log more detailed error information for debugging
@@ -305,7 +298,6 @@ export function TestDriver(context, options = {}) {
305
298
  testdriver.disconnect(),
306
299
  new Promise((resolve) => setTimeout(resolve, 5000)) // 5s timeout for disconnect
307
300
  ]);
308
- console.log('✅ Client disconnected');
309
301
  } catch (error) {
310
302
  console.error('Error disconnecting client:', error);
311
303
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.1.4",
3
+ "version": "7.2.2",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
6
  "exports": {