testdriverai 7.1.3 → 7.2.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 (78) hide show
  1. package/.github/workflows/acceptance.yaml +81 -0
  2. package/.github/workflows/publish.yaml +44 -0
  3. package/.github/workflows/test-init.yml +145 -0
  4. package/agent/index.js +18 -19
  5. package/agent/lib/commander.js +2 -2
  6. package/agent/lib/commands.js +324 -124
  7. package/agent/lib/redraw.js +99 -39
  8. package/agent/lib/sandbox.js +98 -6
  9. package/agent/lib/sdk.js +25 -0
  10. package/agent/lib/system.js +2 -1
  11. package/agent/lib/validation.js +6 -6
  12. package/docs/docs.json +211 -101
  13. package/docs/snippets/tests/type-repeated-replay.mdx +1 -1
  14. package/docs/v7/_drafts/caching-selectors.mdx +24 -0
  15. package/docs/v7/_drafts/migration.mdx +3 -3
  16. package/docs/v7/api/act.mdx +2 -2
  17. package/docs/v7/api/assert.mdx +2 -2
  18. package/docs/v7/api/assertions.mdx +21 -21
  19. package/docs/v7/api/elements.mdx +78 -0
  20. package/docs/v7/api/find.mdx +38 -0
  21. package/docs/v7/api/focusApplication.mdx +2 -2
  22. package/docs/v7/api/hover.mdx +2 -2
  23. package/docs/v7/features/ai-native.mdx +57 -71
  24. package/docs/v7/features/application-logs.mdx +353 -0
  25. package/docs/v7/features/browser-logs.mdx +414 -0
  26. package/docs/v7/features/cache-management.mdx +402 -0
  27. package/docs/v7/features/continuous-testing.mdx +346 -0
  28. package/docs/v7/features/coverage.mdx +508 -0
  29. package/docs/v7/features/data-driven-testing.mdx +441 -0
  30. package/docs/v7/features/easy-to-write.mdx +2 -73
  31. package/docs/v7/features/enterprise.mdx +155 -39
  32. package/docs/v7/features/fast.mdx +63 -81
  33. package/docs/v7/features/managed-sandboxes.mdx +384 -0
  34. package/docs/v7/features/network-monitoring.mdx +568 -0
  35. package/docs/v7/features/observable.mdx +3 -22
  36. package/docs/v7/features/parallel-execution.mdx +381 -0
  37. package/docs/v7/features/powerful.mdx +1 -1
  38. package/docs/v7/features/reports.mdx +414 -0
  39. package/docs/v7/features/sandbox-customization.mdx +229 -0
  40. package/docs/v7/features/scalable.mdx +217 -2
  41. package/docs/v7/features/stable.mdx +106 -147
  42. package/docs/v7/features/system-performance.mdx +616 -0
  43. package/docs/v7/features/test-analytics.mdx +373 -0
  44. package/docs/v7/features/test-cases.mdx +393 -0
  45. package/docs/v7/features/test-replays.mdx +408 -0
  46. package/docs/v7/features/test-reports.mdx +308 -0
  47. package/docs/v7/getting-started/{running-and-debugging.mdx → debugging-tests.mdx} +12 -142
  48. package/docs/v7/getting-started/quickstart.mdx +22 -305
  49. package/docs/v7/getting-started/running-tests.mdx +173 -0
  50. package/docs/v7/overview/readme.mdx +1 -1
  51. package/docs/v7/overview/what-is-testdriver.mdx +2 -14
  52. package/docs/v7/presets/chrome-extension.mdx +147 -122
  53. package/interfaces/cli/commands/init.js +78 -20
  54. package/interfaces/cli/lib/base.js +3 -2
  55. package/interfaces/logger.js +0 -2
  56. package/interfaces/shared-test-state.mjs +0 -5
  57. package/interfaces/vitest-plugin.mjs +69 -42
  58. package/lib/core/Dashcam.js +65 -66
  59. package/lib/vitest/hooks.mjs +42 -50
  60. package/manual/test-init-command.js +223 -0
  61. package/package.json +2 -2
  62. package/schema.json +5 -5
  63. package/sdk-log-formatter.js +351 -176
  64. package/sdk.d.ts +8 -8
  65. package/sdk.js +436 -121
  66. package/setup/aws/cloudformation.yaml +2 -2
  67. package/setup/aws/self-hosted.yml +1 -1
  68. package/test/testdriver/chrome-extension.test.mjs +55 -72
  69. package/test/testdriver/element-not-found.test.mjs +2 -1
  70. package/test/testdriver/hover-image.test.mjs +1 -1
  71. package/test/testdriver/hover-text-with-description.test.mjs +0 -3
  72. package/test/testdriver/scroll-until-text.test.mjs +10 -6
  73. package/test/testdriver/setup/lifecycleHelpers.mjs +19 -24
  74. package/test/testdriver/setup/testHelpers.mjs +18 -23
  75. package/vitest.config.mjs +3 -3
  76. package/.github/workflows/linux-tests.yml +0 -28
  77. package/docs/v7/getting-started/generating-tests.mdx +0 -525
  78. package/test/testdriver/auto-cache-key-demo.test.mjs +0 -56
@@ -75,7 +75,7 @@ v7/
75
75
  - Basic assertions
76
76
  - Negative assertions (invert parameter)
77
77
  - Async assertions
78
- - `remember()` - Extract information from screen
78
+ - `extract()` - Extract information from screen
79
79
  - Testing patterns:
80
80
  - Polling assertions
81
81
  - Multi-step validation
@@ -2,6 +2,7 @@
2
2
  title: "What is TestDriver?"
3
3
  description: "AI-powered end-to-end testing for web, desktop, and mobile applications"
4
4
  icon: "circle-info"
5
+ mode: "wide"
5
6
  ---
6
7
 
7
8
  TestDriver is an AI-native testing platform that lets you write tests in natural language. It uses computer vision and AI to understand your application like a human would, eliminating brittle selectors and making tests easy to write and maintain.
@@ -10,7 +11,7 @@ TestDriver is an AI-native testing platform that lets you write tests in natural
10
11
 
11
12
  Traditional E2E testing tools require:
12
13
 
13
- <CardGroup cols={2}>
14
+ <CardGroup cols={1}>
14
15
  <Card title="Brittle Selectors" icon="triangle-exclamation">
15
16
  ```javascript
16
17
  // ❌ Breaks when DOM changes
@@ -18,19 +19,6 @@ Traditional E2E testing tools require:
18
19
  ```
19
20
  </Card>
20
21
 
21
- <Card title="Complex Setup" icon="wrench">
22
- ```javascript
23
- // ❌ Manual lifecycle management
24
- await browser.launch()
25
- await page.goto(url)
26
- try {
27
- // Test code
28
- } finally {
29
- await browser.close()
30
- }
31
- ```
32
- </Card>
33
-
34
22
  <Card title="Flaky Tests" icon="shuffle">
35
23
  ```javascript
36
24
  // ❌ Arbitrary waits
@@ -7,50 +7,97 @@ icon: "puzzle-piece"
7
7
 
8
8
  ## Overview
9
9
 
10
- Test Chrome extensions by loading them into Chrome for Testing. This preset uses the `launchChromeExtension()` helper to launch Chrome with a specific extension loaded by its Chrome Web Store ID.
10
+ Test Chrome extensions by loading them into Chrome for Testing. Use `testdriver.provision.chromeExtension()` to launch Chrome with either:
11
+ - A **local unpacked extension** via `extensionPath`
12
+ - A **Chrome Web Store extension** via `extensionId`
13
+
14
+ The dashcam-chrome extension is automatically included on Linux for web log capture.
11
15
 
12
16
  ## Quick Start
13
17
 
18
+ ### Using a Local Extension Path
19
+
14
20
  ```javascript
15
- import { test } from 'vitest';
16
- import TestDriver from 'testdriverai';
17
- import {
18
- runPrerunChromeExtension,
19
- runPostrun
20
- } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
21
-
22
- test('test chrome extension', async () => {
23
- const client = await TestDriver.create({
24
- apiKey: process.env.TD_API_KEY,
25
- os: "linux",
26
- verbosity: 1,
21
+ import { describe, it, expect } from 'vitest';
22
+ import { TestDriver } from 'testdriverai/vitest/hooks';
23
+
24
+ describe('Chrome Extension Test', () => {
25
+ it('should load and test a Chrome extension', async (context) => {
26
+ const testdriver = TestDriver(context, { headless: true });
27
+
28
+ // Wait for connection
29
+ await testdriver.ready();
30
+
31
+ // Clone an extension repo
32
+ await testdriver.exec(
33
+ 'sh',
34
+ 'git clone --depth 1 https://github.com/GoogleChrome/chrome-extensions-samples.git /tmp/chrome-extensions-samples',
35
+ 60000,
36
+ true
37
+ );
38
+
39
+ // Launch Chrome with the extension loaded
40
+ await testdriver.provision.chromeExtension({
41
+ extensionPath: '/tmp/chrome-extensions-samples/functional-samples/tutorial.hello-world',
42
+ url: 'https://example.com'
43
+ });
44
+
45
+ // Your test code here
46
+ const result = await testdriver.assert("the page is visible");
47
+ expect(result).toBeTruthy();
27
48
  });
49
+ });
50
+ ```
28
51
 
29
- // Launch Chrome with extension loaded
30
- // Extension ID from Chrome Web Store
31
- await runPrerunChromeExtension(client, "cjpalhdlnbpafiamejdnhcphjbkeiagm");
52
+ ### Using a Chrome Web Store Extension ID
32
53
 
33
- // Your test code here
34
- await client.focusApplication("Google Chrome");
35
-
36
- // ... test extension functionality
54
+ ```javascript
55
+ import { describe, it, expect } from 'vitest';
56
+ import { TestDriver } from 'testdriverai/vitest/hooks';
57
+
58
+ describe('Chrome Extension Test', () => {
59
+ it('should load uBlock Origin and verify it works', async (context) => {
60
+ const testdriver = TestDriver(context, { headless: true });
61
+
62
+ // Launch Chrome with uBlock Origin loaded by its Chrome Web Store ID
63
+ await testdriver.provision.chromeExtension({
64
+ extensionId: 'cjpalhdlnbpafiamejdnhcphjbkeiagm', // uBlock Origin
65
+ url: 'https://example.com'
66
+ });
37
67
 
38
- await runPostrun(client);
39
- await client.cleanup();
68
+ // Your test code here
69
+ const result = await testdriver.assert("the page is visible");
70
+ expect(result).toBeTruthy();
71
+ });
40
72
  });
41
73
  ```
42
74
 
75
+ ## API Reference
76
+
77
+ ### `testdriver.provision.chromeExtension(options)`
78
+
79
+ Launches Chrome for Testing with a custom extension loaded.
80
+
81
+ | Option | Type | Default | Description |
82
+ |--------|------|---------|-------------|
83
+ | `extensionPath` | `string` | - | Local filesystem path to the unpacked extension directory |
84
+ | `extensionId` | `string` | - | Chrome Web Store extension ID (e.g., `cjpalhdlnbpafiamejdnhcphjbkeiagm`) |
85
+ | `url` | `string` | `'http://testdriver-sandbox.vercel.app/'` | URL to navigate to after launch |
86
+ | `maximized` | `boolean` | `true` | Start Chrome maximized |
87
+
88
+ **Note:** Either `extensionPath` or `extensionId` is required. On Linux, the dashcam-chrome extension is automatically loaded alongside your extension for web log capture.
89
+
43
90
  ## Finding Extension IDs
44
91
 
45
92
  Extension IDs can be found in the Chrome Web Store URL:
46
93
 
47
94
  ```
48
95
  https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm
49
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50
- This is the extension ID
96
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
97
+ This is the extension ID
51
98
  ```
52
99
 
53
- ## Popular Extensions
100
+ ### Popular Extensions
54
101
 
55
102
  | Extension | ID |
56
103
  |-----------|---|
@@ -59,73 +106,67 @@ https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcph
59
106
  | Redux DevTools | `lmhkpmbekcpmknklioeibfkpmmfibljd` |
60
107
  | Bitwarden | `nngceckbapebfimnlniiiahkandclblb` |
61
108
 
62
- ## Loading Multiple Extensions
109
+ ## Using Your Own Extension
63
110
 
64
- Load multiple extensions by separating IDs with commas:
111
+ To test your own extension, you can either:
65
112
 
113
+ 1. **Clone from a repository:**
66
114
  ```javascript
67
- await launchChromeExtension(
68
- client,
69
- "cjpalhdlnbpafiamejdnhcphjbkeiagm,nngceckbapebfimnlniiiahkandclblb"
70
- );
115
+ await testdriver.ready();
116
+ await testdriver.exec('sh', 'git clone https://github.com/your/extension.git /tmp/my-extension', 60000, true);
117
+ await testdriver.provision.chromeExtension({
118
+ extensionPath: '/tmp/my-extension',
119
+ url: 'https://example.com'
120
+ });
71
121
  ```
72
122
 
123
+ 2. **Upload your extension files** (if supported by your test setup)
124
+
125
+ 3. **Use a pre-built extension** in a known location
126
+
73
127
  ## Complete Example
74
128
 
75
129
  ```javascript
76
- import { describe, it, beforeAll, afterAll } from 'vitest';
77
- import TestDriver from 'testdriverai';
78
- import {
79
- runPrerunChromeExtension,
80
- runPostrun
81
- } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
82
-
83
- describe('Chrome Extension Testing', () => {
84
- let client;
85
- let dashcamUrl;
86
-
87
- beforeAll(async () => {
88
- client = await TestDriver.create({
89
- apiKey: process.env.TD_API_KEY,
90
- os: "linux",
91
- verbosity: 1,
130
+ import { describe, it, expect } from 'vitest';
131
+ import { TestDriver } from 'testdriverai/vitest/hooks';
132
+
133
+ describe('Chrome Extension - Hello World', () => {
134
+ it('should load extension and verify popup', async (context) => {
135
+ const testdriver = TestDriver(context, {
136
+ headless: true,
137
+ newSandbox: true,
138
+ cacheKey: 'chrome-extension-test'
92
139
  });
140
+
141
+ // Clone the Chrome extensions samples repo
142
+ await testdriver.exec(
143
+ 'sh',
144
+ 'git clone --depth 1 https://github.com/GoogleChrome/chrome-extensions-samples.git /tmp/chrome-extensions-samples',
145
+ 60000,
146
+ true
147
+ );
93
148
 
94
- // Load uBlock Origin extension
95
- await runPrerunChromeExtension(client, "cjpalhdlnbpafiamejdnhcphjbkeiagm");
96
- });
97
-
98
- afterAll(async () => {
99
- if (client) {
100
- dashcamUrl = await runPostrun(client);
101
- await client.cleanup();
102
- }
103
- });
104
-
105
- it('should verify extension is loaded', async () => {
106
- await client.focusApplication("Google Chrome");
149
+ // Launch Chrome with the hello-world extension loaded
150
+ await testdriver.provision.chromeExtension({
151
+ extensionPath: '/tmp/chrome-extensions-samples/functional-samples/tutorial.hello-world',
152
+ url: 'https://testdriver.ai'
153
+ });
107
154
 
108
- // Navigate to a page
109
- const element = await client.find("TestDriver.ai Sandbox");
110
- expect(element.found()).toBe(true);
155
+ // Verify the page loaded
156
+ const pageResult = await testdriver.assert("the testdriver.ai website is visible");
157
+ expect(pageResult).toBeTruthy();
111
158
 
112
- // Test extension-specific functionality
113
- // For example, checking if ads are blocked with uBlock
114
- });
159
+ // Click on the extensions button in Chrome toolbar
160
+ const extensionsButton = await testdriver.find("Extensions button, puzzle piece icon in Chrome toolbar");
161
+ await extensionsButton.click();
115
162
 
116
- it('should access extension popup', async () => {
117
- await client.focusApplication("Google Chrome");
118
-
119
- // Open extension management
120
- await client.exec(
121
- "sh",
122
- `xdotool key --clearmodifiers ctrl+shift+e`,
123
- 5000,
124
- true
125
- );
163
+ // Find and click the hello world extension
164
+ const helloExtension = await testdriver.find("Hello World extension in the extensions dropdown");
165
+ await helloExtension.click();
126
166
 
127
- // Wait for extensions page
128
- await new Promise((resolve) => setTimeout(resolve, 2000));
167
+ // Verify the extension popup shows
168
+ const popupResult = await testdriver.assert("a popup shows with the text 'Hello Extensions'");
169
+ expect(popupResult).toBeTruthy();
129
170
  });
130
171
  });
131
172
  ```
@@ -139,19 +180,9 @@ Chrome for Testing is pre-installed in the E2B sandbox environment at:
139
180
  /usr/local/bin/chrome-for-testing (symlink)
140
181
  ```
141
182
 
142
- ## Direct API Usage
143
-
144
- Use the lower-level API for more control:
145
-
146
- ```javascript
147
- import { launchChromeExtension } from 'testdriverai/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs';
148
-
149
- // Launch with specific extension and URL
150
- await launchChromeExtension(
151
- client,
152
- "cjpalhdlnbpafiamejdnhcphjbkeiagm",
153
- "https://example.com"
154
- );
183
+ The dashcam-chrome extension is pre-installed at:
184
+ ```
185
+ /usr/lib/node_modules/dashcam-chrome/build
155
186
  ```
156
187
 
157
188
  ## Testing Extension Features
@@ -159,44 +190,39 @@ await launchChromeExtension(
159
190
  ### Test Extension Popup
160
191
 
161
192
  ```javascript
162
- it('opens extension popup', async () => {
163
- // Click extension icon (varies by extension)
164
- await client.click('extension icon in toolbar');
193
+ it('opens extension popup', async (context) => {
194
+ const testdriver = TestDriver(context, { headless: true });
165
195
 
166
- // Interact with popup
167
- const popup = await client.find('extension popup window');
168
- expect(popup.found()).toBe(true);
169
- });
170
- ```
171
-
172
- ### Test Extension Settings
173
-
174
- ```javascript
175
- it('configures extension settings', async () => {
176
- // Right-click extension icon
177
- await client.rightClick('extension icon');
196
+ // Setup extension...
197
+ await testdriver.provision.chromeExtension({
198
+ extensionPath: '/path/to/extension',
199
+ url: 'https://example.com'
200
+ });
178
201
 
179
- // Click options
180
- await client.click('Options');
202
+ // Click extension icon in toolbar
203
+ const extensionIcon = await testdriver.find('extension icon in toolbar');
204
+ await extensionIcon.click();
181
205
 
182
- // Configure settings
183
- await client.click('Enable feature X');
184
- await client.click('Save');
206
+ // Interact with popup
207
+ const result = await testdriver.assert('extension popup is visible');
208
+ expect(result).toBeTruthy();
185
209
  });
186
210
  ```
187
211
 
188
212
  ### Test Content Scripts
189
213
 
190
214
  ```javascript
191
- it('verifies content script injection', async () => {
192
- // Navigate to a page
193
- await client.exec('sh', 'xdotool key ctrl+l', 5000, true);
194
- await client.type('https://example.com');
195
- await client.pressKeys('Enter');
215
+ it('verifies content script injection', async (context) => {
216
+ const testdriver = TestDriver(context, { headless: true });
217
+
218
+ await testdriver.provision.chromeExtension({
219
+ extensionPath: '/path/to/extension',
220
+ url: 'https://example.com'
221
+ });
196
222
 
197
223
  // Check for extension-injected elements
198
- const injected = await client.find('element added by extension');
199
- expect(injected.found()).toBe(true);
224
+ const result = await testdriver.assert('element added by extension is visible');
225
+ expect(result).toBeTruthy();
200
226
  });
201
227
  ```
202
228
 
@@ -204,9 +230,9 @@ it('verifies content script injection', async () => {
204
230
 
205
231
  ### Extension Not Loading
206
232
 
207
- 1. Verify the extension ID is correct
233
+ 1. Verify the extension path exists and contains a valid `manifest.json`
208
234
  2. Check Chrome for Testing is installed in the sandbox
209
- 3. Ensure extension is compatible with Chrome for Testing version
235
+ 3. Ensure extension is compatible with Chrome for Testing version (Manifest V3 recommended)
210
236
 
211
237
  ### Extension Permissions
212
238
 
@@ -219,5 +245,4 @@ Some extensions may require additional permissions or setup. You may need to:
219
245
  ## See Also
220
246
 
221
247
  - [Web Apps (Chrome)](/v7/presets/chrome) - Regular Chrome browser testing
222
- - [Desktop Apps (Electron)](/v7/presets/electron) - Electron app testing
223
- - [Lifecycle Helpers](/v7/guides/lifecycle) - Prerun/postrun functions
248
+ - [Desktop Apps (Electron)](/v7/presets/electron) - Electron app testing- [Lifecycle Helpers](/v7/guides/lifecycle) - Prerun/postrun functions
@@ -143,7 +143,10 @@ class InitCommand extends BaseCommand {
143
143
  },
144
144
  keywords: ["testdriver", "testing", "e2e"],
145
145
  author: "",
146
- license: "ISC"
146
+ license: "ISC",
147
+ engines: {
148
+ node: ">=20.19.0"
149
+ }
147
150
  };
148
151
 
149
152
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
@@ -159,6 +162,7 @@ class InitCommand extends BaseCommand {
159
162
  async createVitestExample() {
160
163
  const testDir = path.join(process.cwd(), "tests");
161
164
  const testFile = path.join(testDir, "example.test.js");
165
+ const loginSnippetFile = path.join(testDir, "login.js");
162
166
  const configFile = path.join(process.cwd(), "vitest.config.js");
163
167
 
164
168
  // Create test directory if it doesn't exist
@@ -167,23 +171,73 @@ class InitCommand extends BaseCommand {
167
171
  console.log(chalk.gray(` Created directory: ${testDir}`));
168
172
  }
169
173
 
170
- // Create example Vitest test
174
+ // Create login snippet file
175
+ const loginSnippetContent = `/**
176
+ * Login snippet - reusable login function
177
+ *
178
+ * This demonstrates how to create reusable test snippets that can be
179
+ * imported and used across multiple test files.
180
+ */
181
+ export async function login(testdriver) {
182
+
183
+ // The password is displayed on screen, have TestDriver extract it
184
+ const password = await testdriver.extract('the password');
185
+
186
+ // Find the username field
187
+ const usernameField = await testdriver.find(
188
+ 'Username, label above the username input field on the login form'
189
+ );
190
+ await usernameField.click();
191
+
192
+ // Type username
193
+ await testdriver.type('standard_user');
194
+
195
+ // Enter password form earlier
196
+ // Marked as secret so it's not logged or stored
197
+ await testdriver.pressKeys(['tab']);
198
+ await testdriver.type(password, { secret: true });
199
+
200
+ // Submit the form
201
+ await testdriver.find('submit button on the login form').click();
202
+ }
203
+ `;
204
+
205
+ fs.writeFileSync(loginSnippetFile, loginSnippetContent);
206
+ console.log(chalk.green(` Created login snippet: ${loginSnippetFile}`));
207
+
208
+ // Create example Vitest test that uses the login snippet
171
209
  const vitestContent = `import { test, expect } from 'vitest';
172
- import { chrome } from 'testdriverai/presets';
210
+ import { TestDriver } from 'testdriverai/vitest/hooks';
211
+ import { login } from './login.js';
212
+
213
+ test('should login and add item to cart', async (context) => {
214
+
215
+ // Create TestDriver instance - automatically connects to sandbox
216
+ const testdriver = TestDriver(context);
217
+
218
+ // Launch chrome and navigate to demo app
219
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
220
+
221
+ // Use the login snippet to handle authentication
222
+ // This demonstrates how to reuse test logic across multiple tests
223
+ await login(testdriver);
173
224
 
174
- test('should navigate to example.com and find elements', async (context) => {
175
- // The chrome preset handles connection, browser launch, and cleanup automatically
176
- const { testdriver } = await chrome(context, {
177
- url: 'https://example.com'
178
- // apiKey automatically read from process.env.TD_API_KEY via .env file
179
- });
225
+ // Add item to cart
226
+ const addToCartButton = await testdriver.find(
227
+ 'add to cart button under TestDriver Hat'
228
+ );
229
+ await addToCartButton.click();
180
230
 
181
- // Find and verify elements
182
- const heading = await testdriver.find('heading that says Example Domain');
183
- expect(heading.found()).toBe(true);
231
+ // Open cart
232
+ const cartButton = await testdriver.find(
233
+ 'cart button in the top right corner'
234
+ );
235
+ await cartButton.click();
184
236
 
185
- const link = await testdriver.find('More information link');
186
- expect(link.found()).toBe(true);
237
+ // Verify item in cart
238
+ const result = await testdriver.assert('TestDriver Hat is in the cart');
239
+ expect(result).toBeTruthy();
240
+
187
241
  });
188
242
  `;
189
243
 
@@ -194,16 +248,20 @@ test('should navigate to example.com and find elements', async (context) => {
194
248
  if (!fs.existsSync(configFile)) {
195
249
  const configContent = `import { defineConfig } from 'vitest/config';
196
250
  import TestDriver from 'testdriverai/vitest';
197
- import dotenv from 'dotenv';
251
+ import { config } from 'dotenv';
198
252
 
199
253
  // Load environment variables from .env file
200
- dotenv.config();
254
+ config();
201
255
 
202
256
  export default defineConfig({
203
- plugins: [TestDriver()],
204
257
  test: {
205
258
  testTimeout: 300000,
206
259
  hookTimeout: 300000,
260
+ reporters: [
261
+ 'default',
262
+ TestDriver(),
263
+ ],
264
+ setupFiles: ['testdriverai/vitest/setup'],
207
265
  },
208
266
  });
209
267
  `;
@@ -290,7 +348,7 @@ jobs:
290
348
  - name: Run TestDriver.ai tests
291
349
  env:
292
350
  TD_API_KEY: \${{ secrets.TD_API_KEY }}
293
- run: npm test
351
+ run: npx vitest run
294
352
 
295
353
  - name: Upload test results
296
354
  if: always()
@@ -337,11 +395,11 @@ jobs:
337
395
  printNextSteps() {
338
396
  console.log(chalk.cyan("Next steps:\n"));
339
397
  console.log(" 1. Run your tests:");
340
- console.log(chalk.gray(" npm test\n"));
398
+ console.log(chalk.gray(" npx vitest run\n"));
341
399
  console.log(" 2. For CI/CD, add TD_API_KEY to your GitHub repository secrets");
342
400
  console.log(chalk.gray(" Settings → Secrets → Actions → New repository secret\n"));
343
401
  console.log(
344
- chalk.cyan("Learn more at https://docs.testdriver.ai/getting-started\n"),
402
+ chalk.cyan("Learn more at https://docs.testdriver.ai/v7/getting-started/\n"),
345
403
  );
346
404
  }
347
405
  }
@@ -73,12 +73,13 @@ class BaseCommand extends Command {
73
73
  };
74
74
 
75
75
  let isConnected = false;
76
+ const debugMode = process.env.VERBOSE || process.env.DEBUG || process.env.TD_DEBUG;
76
77
 
77
- // Use pattern matching for log events, but skip log:Debug
78
+ // Use pattern matching for log events, but skip log:Debug unless debug mode is enabled
78
79
  this.agent.emitter.on("log:*", (message) => {
79
80
  const event = this.agent.emitter.event;
80
81
 
81
- if (event === events.log.debug) return;
82
+ if (event === events.log.debug && !debugMode) return;
82
83
 
83
84
  if (event === events.log.narration && isConnected) return;
84
85
  console.log(message);
@@ -21,8 +21,6 @@ class CustomTransport extends Transport {
21
21
  this.sandbox = require("../agent/lib/sandbox");
22
22
  }
23
23
 
24
- console.log("CustomTransport log message:", message);
25
-
26
24
  if (this.sandbox && this.sandbox.instanceSocketConnected) {
27
25
  if (typeof message === "object") {
28
26
  console.log(chalk.cyan("protecting against base64 error"));
@@ -22,11 +22,6 @@ const sharedState = {
22
22
  * Set the test run information
23
23
  */
24
24
  export function setTestRunInfo(info) {
25
- console.log("[SharedState] Setting test run info:", {
26
- testRunId: info.testRunId,
27
- hasToken: !!info.token,
28
- hasTestRun: !!info.testRun,
29
- });
30
25
 
31
26
  if (info.testRun) sharedState.testRun = info.testRun;
32
27
  if (info.testRunId) sharedState.testRunId = info.testRunId;