testdriverai 7.2.40 → 7.2.41

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.
@@ -20,7 +20,7 @@ describe('Login Flow', () => {
20
20
  os: 'linux'
21
21
  });
22
22
  await client.auth();
23
- await client.connect({ newSandbox: true });
23
+ await client.connect();
24
24
  testdriver = client;
25
25
  });
26
26
 
@@ -49,7 +49,6 @@ const client = await TestDriver.create({
49
49
  // Sandbox Configuration
50
50
  os: 'linux',
51
51
  resolution: '1920x1080',
52
- newSandbox: true,
53
52
  sandboxId: null,
54
53
 
55
54
  // API Configuration
@@ -137,7 +136,6 @@ const { testdriver, dashcam } = await chrome(context, {
137
136
  resolution: '1920x1080',
138
137
 
139
138
  // Chrome-specific options
140
- headless: false,
141
139
  incognito: false,
142
140
  });
143
141
  ```
@@ -389,7 +389,6 @@ import { TestDriver, Dashcam, TestDriverOptions, DashcamOptions } from 'testdriv
389
389
  const options: TestDriverOptions = {
390
390
  os: 'linux',
391
391
  resolution: '1366x768',
392
- newSandbox: true,
393
392
  analytics: true
394
393
  };
395
394
 
@@ -61,7 +61,7 @@ describe('Login Test', () => {
61
61
  os: 'windows'
62
62
  });
63
63
  await testdriver.auth();
64
- await testdriver.connect({ newSandbox: true });
64
+ await testdriver.connect();
65
65
  });
66
66
 
67
67
  afterAll(async () => {
@@ -489,7 +489,7 @@ describe('Login Flow', () => {
489
489
  });
490
490
 
491
491
  await testdriver.auth();
492
- await testdriver.connect({ newSandbox: true });
492
+ await testdriver.connect();
493
493
 
494
494
  // Prerun
495
495
  await testdriver.exec('pwsh', 'dashcam start', 5000, true);
@@ -10,7 +10,7 @@ import { TestDriver } from 'testdriverai/lib/vitest/hooks.mjs';
10
10
 
11
11
  describe('My Test Suite', () => {
12
12
  it('should test Chrome browser', async (context) => {
13
- const testdriver = TestDriver(context, { newSandbox: true });
13
+ const testdriver = TestDriver(context, ());
14
14
 
15
15
  await testdriver.provision.chrome({
16
16
  url: 'https://example.com'
@@ -53,7 +53,7 @@ await testdriver.provision.chrome({
53
53
 
54
54
  ```javascript
55
55
  it('should login to my app', async (context) => {
56
- const testdriver = TestDriver(context, { newSandbox: true });
56
+ const testdriver = TestDriver(context, ());
57
57
 
58
58
  await testdriver.provision.chrome({
59
59
  url: 'https://myapp.com/login'
@@ -91,7 +91,7 @@ await testdriver.provision.vscode({
91
91
 
92
92
  ```javascript
93
93
  it('should launch VS Code', async (context) => {
94
- const testdriver = TestDriver(context, { newSandbox: true });
94
+ const testdriver = TestDriver(context, ());
95
95
 
96
96
  await testdriver.provision.vscode();
97
97
 
@@ -106,7 +106,7 @@ it('should launch VS Code', async (context) => {
106
106
 
107
107
  ```javascript
108
108
  it('should install and use a VS Code extension', async (context) => {
109
- const testdriver = TestDriver(context, { newSandbox: true });
109
+ const testdriver = TestDriver(context, ());
110
110
 
111
111
  // Launch VS Code with extensions installed
112
112
  await testdriver.provision.vscode({
@@ -164,7 +164,7 @@ const filePath = await testdriver.provision.installer({
164
164
 
165
165
  ```javascript
166
166
  it('should install a .deb package', async (context) => {
167
- const testdriver = TestDriver(context, { newSandbox: true });
167
+ const testdriver = TestDriver(context, ());
168
168
 
169
169
  const filePath = await testdriver.provision.installer({
170
170
  url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb'
@@ -179,7 +179,7 @@ it('should install a .deb package', async (context) => {
179
179
 
180
180
  ```javascript
181
181
  it('should download a script', async (context) => {
182
- const testdriver = TestDriver(context, { newSandbox: true });
182
+ const testdriver = TestDriver(context, ());
183
183
 
184
184
  const filePath = await testdriver.provision.installer({
185
185
  url: 'https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh',
@@ -195,7 +195,7 @@ it('should download a script', async (context) => {
195
195
 
196
196
  ```javascript
197
197
  it('should run AppImage with custom flags', async (context) => {
198
- const testdriver = TestDriver(context, { newSandbox: true });
198
+ const testdriver = TestDriver(context, ());
199
199
 
200
200
  const filePath = await testdriver.provision.installer({
201
201
  url: 'https://example.com/app.AppImage',
@@ -235,7 +235,7 @@ await testdriver.provision.electron({
235
235
 
236
236
  ```javascript
237
237
  it('should launch Electron app', async (context) => {
238
- const testdriver = TestDriver(context, { newSandbox: true });
238
+ const testdriver = TestDriver(context, ());
239
239
 
240
240
  await testdriver.provision.electron({
241
241
  appPath: '/path/to/my-electron-app',
@@ -271,7 +271,7 @@ import { TestDriver } from 'testdriverai/lib/vitest/hooks.mjs';
271
271
 
272
272
  describe('Application Testing', () => {
273
273
  it('should test Chrome login flow', async (context) => {
274
- const testdriver = TestDriver(context, { newSandbox: true });
274
+ const testdriver = TestDriver(context, ());
275
275
 
276
276
  await testdriver.provision.chrome({
277
277
  url: 'https://myapp.com/login'
@@ -286,7 +286,7 @@ describe('Application Testing', () => {
286
286
  });
287
287
 
288
288
  it('should test VS Code extension', async (context) => {
289
- const testdriver = TestDriver(context, { newSandbox: true });
289
+ const testdriver = TestDriver(context, ());
290
290
 
291
291
  await testdriver.provision.vscode({
292
292
  extensions: ['ms-python.python']
@@ -301,7 +301,7 @@ describe('Application Testing', () => {
301
301
  });
302
302
 
303
303
  it('should install and test CLI tool', async (context) => {
304
- const testdriver = TestDriver(context, { newSandbox: true });
304
+ const testdriver = TestDriver(context, ());
305
305
 
306
306
  await testdriver.provision.installer({
307
307
  url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb'
@@ -315,7 +315,7 @@ describe('Application Testing', () => {
315
315
 
316
316
  ## Best Practices
317
317
 
318
- 1. **Use `newSandbox: true`** - Each test gets a clean environment
318
+ 1. **Use clean environments** - Each test gets a fresh sandbox by default
319
319
  2. **Enable Dashcam** - Great for debugging test failures (enabled by default)
320
320
  3. **Check assertions** - Always verify the expected state after actions
321
321
  4. **Use appropriate provision method** - Match the method to your test target
@@ -113,7 +113,7 @@ const screenshot = await testdriver.screenshot(1, false, true);
113
113
 
114
114
  ```javascript
115
115
  it('should complete checkout', async (context) => {
116
- const testdriver = TestDriver(context, { newSandbox: true });
116
+ const testdriver = TestDriver(context, ());
117
117
  await testdriver.provision.chrome({ url: 'https://shop.example.com' });
118
118
 
119
119
  try {
@@ -84,7 +84,7 @@ const client = await TestDriver.create({
84
84
  let attempts = 0;
85
85
  while (attempts < 3) {
86
86
  try {
87
- await client.connect({ newSandbox: true });
87
+ await client.connect();
88
88
  break;
89
89
  } catch (error) {
90
90
  attempts++;
package/docs/v7/ai.mdx CHANGED
@@ -167,7 +167,7 @@ describe('E-commerce Flow with AI', () => {
167
167
  beforeAll(async () => {
168
168
  client = new TestDriver(process.env.TD_API_KEY);
169
169
  await testdriver.auth();
170
- await testdriver.connect({ newSandbox: true });
170
+ await testdriver.connect(());
171
171
  });
172
172
 
173
173
  afterAll(async () => {
@@ -214,7 +214,7 @@ describe('Assertions', () => {
214
214
  beforeAll(async () => {
215
215
  client = new TestDriver(process.env.TD_API_KEY);
216
216
  await testdriver.auth();
217
- await testdriver.connect({ newSandbox: true });
217
+ await testdriver.connect(());
218
218
  });
219
219
 
220
220
  afterAll(async () => {
package/docs/v7/ci-cd.mdx CHANGED
@@ -579,8 +579,6 @@ describe("Cross-platform tests", () => {
579
579
  const os = process.env.TD_OS || 'linux';
580
580
 
581
581
  const testdriver = TestDriver(context, {
582
- newSandbox: true,
583
- headless: false,
584
582
  os: os // 'linux' or 'windows'
585
583
  });
586
584
 
package/docs/v7/click.mdx CHANGED
@@ -235,7 +235,7 @@ describe('Click Interactions', () => {
235
235
  beforeAll(async () => {
236
236
  client = new TestDriver(process.env.TD_API_KEY);
237
237
  await testdriver.auth();
238
- await testdriver.connect({ newSandbox: true });
238
+ await testdriver.connect(());
239
239
  });
240
240
 
241
241
  afterAll(async () => {
@@ -133,7 +133,7 @@ await testdriver.connect(options)
133
133
 
134
134
  **Basic connection:**
135
135
  ```javascript
136
- await testdriver.connect({ newSandbox: true });
136
+ await testdriver.connect(());
137
137
  ```
138
138
 
139
139
  **Reconnect to existing sandbox:**
@@ -273,7 +273,7 @@ describe('My Test Suite', () => {
273
273
 
274
274
  // Authenticate and connect
275
275
  await testdriver.auth();
276
- const instance = await testdriver.connect({ newSandbox: true });
276
+ const instance = await testdriver.connect(());
277
277
 
278
278
  console.log('Connected to sandbox:', instance.instanceId);
279
279
  });
@@ -300,7 +300,7 @@ describe('My Test Suite', () => {
300
300
 
301
301
  ```javascript
302
302
  try {
303
- await testdriver.connect({ newSandbox: true });
303
+ await testdriver.connect(());
304
304
  } catch (error) {
305
305
  console.error('Failed to connect:', error.message);
306
306
  throw error;
@@ -10,7 +10,6 @@ Configure TestDriver behavior with options passed to the `TestDriver()` function
10
10
 
11
11
  ```javascript
12
12
  const testdriver = TestDriver(context, {
13
- headless: false,
14
13
  reconnect: false,
15
14
  });
16
15
  ```
@@ -72,7 +71,6 @@ If self-hosting TestDriver, use `ip` to specify the device IP. See [Self-Hosting
72
71
 
73
72
  ```javascript
74
73
  const testdriver = TestDriver(context, {
75
- newSandbox: true,
76
74
  ip: "203.0.113.42", // Your allowlisted IP
77
75
  });
78
76
  ```
@@ -97,8 +95,6 @@ Split your test into two files: one for known-good steps that set up the desired
97
95
 
98
96
  ```javascript known-good.test.mjs
99
97
  const testdriver = TestDriver(context, {
100
- newSandbox: true,
101
- headless: false,
102
98
  keepAlive: 60000, // Keep sandbox alive for 60 seconds after test
103
99
  });
104
100
  ```
@@ -106,8 +102,6 @@ const testdriver = TestDriver(context, {
106
102
  ```javascript work-in-progress.test.mjs
107
103
  // Second test file: experiment.test.mjs (run within keepAlive window)
108
104
  const testdriver = TestDriver(context, {
109
- newSandbox: true,
110
- headless: false,
111
105
  reconnect: true, // Reconnect to existing sandbox
112
106
  });
113
107
  ```
@@ -32,7 +32,7 @@ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
32
32
 
33
33
  describe("Login Flow", () => {
34
34
  it("should log in successfully", async (context) => {
35
- const testdriver = TestDriver(context, { newSandbox: true });
35
+ const testdriver = TestDriver(context, ());
36
36
 
37
37
  await testdriver.provision.chrome({
38
38
  url: 'https://myapp.com/login',
@@ -117,7 +117,7 @@ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
117
117
 
118
118
  describe("Chrome Extension Test", () => {
119
119
  it("should load and interact with extension", async (context) => {
120
- const testdriver = TestDriver(context, { newSandbox: true });
120
+ const testdriver = TestDriver(context, ());
121
121
 
122
122
  // Clone extension from GitHub
123
123
  await testdriver.ready();
@@ -192,7 +192,7 @@ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
192
192
 
193
193
  describe("Desktop App Test", () => {
194
194
  it("should install and launch app", async (context) => {
195
- const testdriver = TestDriver(context, { newSandbox: true });
195
+ const testdriver = TestDriver(context, ());
196
196
 
197
197
  // Download and install
198
198
  const installerPath = await testdriver.provision.installer({
@@ -215,7 +215,6 @@ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
215
215
  describe("Windows App Test", () => {
216
216
  it("should install on Windows", async (context) => {
217
217
  const testdriver = TestDriver(context, {
218
- newSandbox: true,
219
218
  os: 'windows'
220
219
  });
221
220
 
@@ -282,7 +281,7 @@ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
282
281
 
283
282
  describe("VS Code Test", () => {
284
283
  it("should open workspace with extensions", async (context) => {
285
- const testdriver = TestDriver(context, { newSandbox: true });
284
+ const testdriver = TestDriver(context, ());
286
285
 
287
286
  // Create a test project
288
287
  await testdriver.ready();
package/docs/v7/exec.mdx CHANGED
@@ -282,7 +282,7 @@ describe('Code Execution', () => {
282
282
  beforeAll(async () => {
283
283
  client = new TestDriver(process.env.TD_API_KEY);
284
284
  await testdriver.auth();
285
- await testdriver.connect({ newSandbox: true });
285
+ await testdriver.connect(());
286
286
  });
287
287
 
288
288
  afterAll(async () => {
package/docs/v7/find.mdx CHANGED
@@ -299,7 +299,7 @@ describe('Element Finding', () => {
299
299
  beforeAll(async () => {
300
300
  client = new TestDriver(process.env.TD_API_KEY);
301
301
  await testdriver.auth();
302
- await testdriver.connect({ newSandbox: true });
302
+ await testdriver.connect(());
303
303
  });
304
304
 
305
305
  afterAll(async () => {
@@ -209,7 +209,7 @@ describe('Multi-Application Workflow', () => {
209
209
  beforeAll(async () => {
210
210
  client = new TestDriver(process.env.TD_API_KEY);
211
211
  await testdriver.auth();
212
- await testdriver.connect({ newSandbox: true });
212
+ await testdriver.connect(());
213
213
  });
214
214
 
215
215
  afterAll(async () => {
package/docs/v7/hover.mdx CHANGED
@@ -204,7 +204,7 @@ describe('Hover Interactions', () => {
204
204
  beforeAll(async () => {
205
205
  client = new TestDriver(process.env.TD_API_KEY);
206
206
  await testdriver.auth();
207
- await testdriver.connect({ newSandbox: true });
207
+ await testdriver.connect(());
208
208
  });
209
209
 
210
210
  afterAll(async () => {
@@ -286,7 +286,7 @@ describe('Keyboard Navigation', () => {
286
286
  beforeAll(async () => {
287
287
  client = new TestDriver(process.env.TD_API_KEY);
288
288
  await testdriver.auth();
289
- await testdriver.connect({ newSandbox: true });
289
+ await testdriver.connect(());
290
290
  });
291
291
 
292
292
  afterAll(async () => {
@@ -45,7 +45,7 @@ import { login } from './helpers/auth.js';
45
45
 
46
46
  describe("Checkout", () => {
47
47
  it("should complete checkout as logged in user", async (context) => {
48
- const testdriver = TestDriver(context, { newSandbox: true });
48
+ const testdriver = TestDriver(context, ());
49
49
 
50
50
  await testdriver.provision.chrome({
51
51
  url: 'https://shop.example.com',
@@ -116,7 +116,7 @@ import { LoginPage } from './pages/LoginPage.js';
116
116
 
117
117
  describe("Authentication", () => {
118
118
  it("should show error for invalid credentials", async (context) => {
119
- const testdriver = TestDriver(context, { newSandbox: true });
119
+ const testdriver = TestDriver(context, ());
120
120
 
121
121
  await testdriver.provision.chrome({
122
122
  url: 'https://app.example.com/login',
@@ -131,7 +131,7 @@ describe("Authentication", () => {
131
131
  });
132
132
 
133
133
  it("should redirect to dashboard on success", async (context) => {
134
- const testdriver = TestDriver(context, { newSandbox: true });
134
+ const testdriver = TestDriver(context, ());
135
135
 
136
136
  await testdriver.provision.chrome({
137
137
  url: 'https://app.example.com/login',
@@ -186,7 +186,7 @@ import { testUsers, testUrls, setupAuthenticatedSession } from './fixtures/index
186
186
 
187
187
  describe("Admin Panel", () => {
188
188
  it("should access admin settings", async (context) => {
189
- const testdriver = TestDriver(context, { newSandbox: true });
189
+ const testdriver = TestDriver(context, ());
190
190
 
191
191
  await testdriver.provision.chrome({
192
192
  url: `${testUrls.staging}/login`,
@@ -242,7 +242,7 @@ describe('Scrolling', () => {
242
242
  beforeAll(async () => {
243
243
  client = new TestDriver(process.env.TD_API_KEY);
244
244
  await testdriver.auth();
245
- await testdriver.connect({ newSandbox: true });
245
+ await testdriver.connect(());
246
246
  });
247
247
 
248
248
  afterAll(async () => {
package/docs/v7/type.mdx CHANGED
@@ -296,7 +296,7 @@ describe('Form Filling with Type', () => {
296
296
  beforeAll(async () => {
297
297
  client = new TestDriver(process.env.TD_API_KEY);
298
298
  await testdriver.auth();
299
- await testdriver.connect({ newSandbox: true });
299
+ await testdriver.connect(());
300
300
  });
301
301
 
302
302
  afterAll(async () => {
@@ -117,14 +117,6 @@ class Dashcam {
117
117
  const shell = this._getShell();
118
118
  const apiRoot = this._getApiRoot();
119
119
 
120
- let install = await this.client.exec(
121
- shell,
122
- 'npm ls dashcam -g || echo "not installed"',
123
- 40000,
124
- true
125
- );
126
- this._log('debug', 'Dashcam install check:', install);
127
-
128
120
  if (this.client.os === 'windows') {
129
121
 
130
122
  const dashcamPath = await this._getDashcamPath();
@@ -275,18 +267,6 @@ class Dashcam {
275
267
 
276
268
  if (this.client.os === 'windows') {
277
269
 
278
- const dashcamPath = await this._getDashcamPath();
279
- this._log('debug', 'Dashcam path:', dashcamPath);
280
-
281
- // Verify dashcam exists
282
- const dashcamExists = await this.client.exec(
283
- shell,
284
- `Test-Path "${dashcamPath}"`,
285
- 10000,
286
- true
287
- );
288
- this._log('debug', 'Dashcam.cmd exists:', dashcamExists);
289
-
290
270
  // Start dashcam record and redirect output with TD_API_ROOT
291
271
  const outputFile = 'C:\\Users\\testdriver\\.dashcam-cli\\dashcam-start.log';
292
272
  // const titleArg = this.title ? ` --title=\`"${this.title.replace(/"/g, '`"')}\`"` : '';
@@ -3,7 +3,8 @@
3
3
  * @module testdriverai/vitest/hooks
4
4
  */
5
5
 
6
- import TestDriverSDK, { TestDriverOptions } from '../../sdk';
6
+ import type TestDriverSDK from '../../sdk';
7
+ import type { TestDriverOptions } from '../../sdk';
7
8
 
8
9
  /**
9
10
  * Vitest test context (from test function parameter)
@@ -21,23 +22,10 @@ export interface VitestContext {
21
22
  }
22
23
 
23
24
  /**
24
- * Options for TestDriver hook
25
+ * Options for TestDriver hook (includes all TestDriverOptions)
25
26
  */
26
27
  export interface TestDriverHookOptions extends TestDriverOptions {
27
- /**
28
- * Force creation of a new sandbox (default: true)
29
- */
30
- newSandbox?: boolean;
31
-
32
- /**
33
- * Reconnect to the last used sandbox
34
- */
35
- reconnect?: boolean;
36
-
37
- /**
38
- * Direct IP address to connect to a running sandbox instance
39
- */
40
- ip?: string;
28
+ // All TestDriverOptions are already included via extends
41
29
  }
42
30
 
43
31
  /**
@@ -169,14 +169,9 @@ const lifecycleHandlers = new WeakMap();
169
169
  /**
170
170
  * Create a TestDriver client in a Vitest test with automatic lifecycle management
171
171
  *
172
- * @param {object} context - Vitest test context (from async (context) => {})
173
- * @param {object} options - TestDriver options (passed directly to TestDriver constructor)
174
- * @param {string} [options.apiKey] - TestDriver API key (defaults to process.env.TD_API_KEY)
175
- * @param {boolean} [options.headless] - Run sandbox in headless mode
176
- * @param {boolean} [options.newSandbox] - Create new sandbox
177
- * @param {number} [options.timeout=0] - Sandbox timeout (TTL) in milliseconds. 0 = use provider default (5 min for E2B Linux)
178
- * @param {boolean} [options.autoConnect=true] - Automatically connect to sandbox
179
- * @returns {TestDriver} TestDriver client instance
172
+ * @param {import('vitest').TestContext} context - Vitest test context (from async (context) => {})
173
+ * @param {import('../../sdk.js').TestDriverOptions} [options] - TestDriver options (passed directly to TestDriver constructor)
174
+ * @returns {import('../../sdk.js').default} TestDriver client instance
180
175
  *
181
176
  * @example
182
177
  * test('my test', async (context) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.2.40",
3
+ "version": "7.2.41",
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",
package/sdk.d.ts CHANGED
@@ -13,7 +13,7 @@ export type ClickAction =
13
13
  export type ScrollDirection = "up" | "down" | "left" | "right";
14
14
  export type ScrollMethod = "keyboard" | "mouse";
15
15
  export type TextMatchMethod = "ai" | "turbo";
16
- export type ExecLanguage = "js" | "pwsh";
16
+ export type ExecLanguage = "js" | "pwsh" | "sh";
17
17
  export type KeyboardKey =
18
18
  | "\t"
19
19
  | "\n"
package/sdk.js CHANGED
@@ -1365,6 +1365,22 @@ class TestDriverSDK {
1365
1365
  * Automatically skips provisioning when reconnect mode is enabled
1366
1366
  * @private
1367
1367
  */
1368
+ /**
1369
+ * Get the path to the dashcam-chrome extension
1370
+ * Uses preinstalled dashcam-chrome on both Linux and Windows
1371
+ * @returns {Promise<string>} Path to dashcam-chrome/build directory
1372
+ * @private
1373
+ */
1374
+ async _getDashcamChromeExtensionPath() {
1375
+ if (this.os !== 'windows') {
1376
+ return '/usr/lib/node_modules/dashcam-chrome/build';
1377
+ }
1378
+
1379
+ // dashcam-chrome is preinstalled on Windows at C:\Program Files\nodejs\node_modules\dashcam-chrome\build
1380
+ // Use the actual long path - we'll handle quoting in the chrome launch
1381
+ return 'C:\\PROGRA~1\\nodejs\\node_modules\\dashcam-chrome\\build';
1382
+ }
1383
+
1368
1384
  _createProvisionAPI() {
1369
1385
  const self = this;
1370
1386
 
@@ -1476,9 +1492,10 @@ class TestDriverSDK {
1476
1492
  if (guest) chromeArgs.push('--guest');
1477
1493
  chromeArgs.push('--disable-fre', '--no-default-browser-check', '--no-first-run', '--no-experiments', '--disable-infobars', `--user-data-dir=${userDataDir}`);
1478
1494
 
1479
- // Add dashcam-chrome extension on Linux
1480
- if (this.os === 'linux') {
1481
- chromeArgs.push('--load-extension=/usr/lib/node_modules/dashcam-chrome/build');
1495
+ // Add dashcam-chrome extension
1496
+ const dashcamChromePath = await this._getDashcamChromeExtensionPath();
1497
+ if (dashcamChromePath) {
1498
+ chromeArgs.push(`--load-extension=${dashcamChromePath}`);
1482
1499
  }
1483
1500
 
1484
1501
  // Launch Chrome
@@ -1487,7 +1504,7 @@ class TestDriverSDK {
1487
1504
  const argsString = chromeArgs.map(arg => `"${arg}"`).join(', ');
1488
1505
  await this.exec(
1489
1506
  shell,
1490
- `Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList ${argsString}, "${url}"`,
1507
+ `Start-Process "C:\\ChromeForTesting\\chrome-win64\\chrome.exe" -ArgumentList ${argsString}, "${url}"`,
1491
1508
  30000
1492
1509
  );
1493
1510
  } else {
@@ -1746,11 +1763,12 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
1746
1763
  chromeArgs.push('--disable-fre', '--no-default-browser-check', '--no-first-run', '--no-experiments', '--disable-infobars', '--disable-features=ChromeLabs', `--user-data-dir=${userDataDir}`);
1747
1764
 
1748
1765
  // Add user extension and dashcam-chrome extension
1749
- if (this.os === 'linux') {
1766
+ const dashcamChromePath = await this._getDashcamChromeExtensionPath();
1767
+ if (dashcamChromePath) {
1750
1768
  // Load both user extension and dashcam-chrome for web log capture
1751
- chromeArgs.push(`--load-extension=${extensionPath},/usr/lib/node_modules/dashcam-chrome/build`);
1752
- } else if (this.os === 'windows') {
1753
- // On Windows, just load the user extension (dashcam-chrome not available)
1769
+ chromeArgs.push(`--load-extension=${extensionPath},${dashcamChromePath}`);
1770
+ } else {
1771
+ // If dashcam-chrome unavailable, just load user extension
1754
1772
  chromeArgs.push(`--load-extension=${extensionPath}`);
1755
1773
  }
1756
1774
 
@@ -1759,7 +1777,7 @@ with zipfile.ZipFile(io.BytesIO(zip_data)) as zf:
1759
1777
  const argsString = chromeArgs.map(arg => `"${arg}"`).join(', ');
1760
1778
  await this.exec(
1761
1779
  shell,
1762
- `Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList ${argsString}`,
1780
+ `Start-Process "C:\\ChromeForTesting\\chrome-win64\\chrome.exe" -ArgumentList ${argsString}`,
1763
1781
  30000
1764
1782
  );
1765
1783
  } else {
@@ -8,7 +8,7 @@ import { TestDriver } from "../../lib/vitest/hooks.mjs";
8
8
 
9
9
  describe("AI Test", () => {
10
10
  it("should use ai to search for testdriver on Google", async (context) => {
11
- const testdriver = TestDriver(context, { newSandbox: true });
11
+ const testdriver = TestDriver(context);
12
12
 
13
13
  // provision.chrome() automatically calls ready() and starts dashcam
14
14
  await testdriver.provision.chrome({
@@ -8,7 +8,7 @@ import { TestDriver } from "../../lib/vitest/hooks.mjs";
8
8
 
9
9
  describe("Assert Test", () => {
10
10
  it("should assert the testdriver login page shows", async (context) => {
11
- const testdriver = TestDriver(context, { newSandbox: true, headless: false });
11
+ const testdriver = TestDriver(context, {ip: process.env.TD_IP});
12
12
 
13
13
  // provision.chrome() automatically calls ready() and starts dashcam
14
14
  await testdriver.provision.chrome({
@@ -23,7 +23,7 @@ describe("Assert Test", () => {
23
23
  expect(result).toBeTruthy();
24
24
  });
25
25
  // it("should assert the testdriver login page shows 2", async (context) => {
26
- // const testdriver = TestDriver(context, { newSandbox: true });
26
+ // const testdriver = TestDriver(context);
27
27
 
28
28
  // // provision.chrome() automatically calls ready() and starts dashcam
29
29
  // await testdriver.provision.chrome({
@@ -10,39 +10,52 @@
10
10
  import { describe, expect, it } from "vitest";
11
11
  import { TestDriver } from "../../lib/vitest/hooks.mjs";
12
12
 
13
- const isLinux = (process.env.TD_OS || "linux") === "linux";
13
+ describe("Chrome Extension Test", () => {
14
+ it("should load hello-world Chrome extension from local path", async (context) => {
14
15
 
16
+ console.log('connecting to', process.env.TD_IP)
15
17
 
16
- describe("Chrome Extension Test", () => {
17
- it.skipIf(!isLinux)("should load hello-world Chrome extension from local path", async (context) => {
18
- const testdriver = TestDriver(context, { headless: false, newSandbox: true });
18
+ const testdriver = TestDriver(context, { ip: process.env.TD_IP });
19
19
 
20
20
  // Wait for connection to be ready before running exec
21
21
  await testdriver.ready();
22
22
 
23
+ // Determine OS-specific paths and commands
24
+ const shell = testdriver.os === 'windows' ? 'pwsh' : 'sh';
25
+ const extensionsDir = testdriver.os === 'windows'
26
+ ? 'C:\\Users\\testdriver\\Downloads\\chrome-extensions-samples'
27
+ : '/tmp/chrome-extensions-samples';
28
+ const extensionPath = testdriver.os === 'windows'
29
+ ? `${extensionsDir}\\functional-samples\\tutorial.hello-world`
30
+ : `${extensionsDir}/functional-samples/tutorial.hello-world`;
31
+
23
32
  // Clone the Chrome extensions samples repo
24
- await testdriver.exec(
25
- 'sh',
26
- 'git clone --depth 1 https://github.com/GoogleChrome/chrome-extensions-samples.git /tmp/chrome-extensions-samples',
27
- 60000,
28
- true
29
- );
33
+ const cloneCmd = testdriver.os === 'windows'
34
+ ? `git clone --depth 1 https://github.com/GoogleChrome/chrome-extensions-samples.git "${extensionsDir}"`
35
+ : `git clone --depth 1 https://github.com/GoogleChrome/chrome-extensions-samples.git ${extensionsDir}`;
36
+
37
+ await testdriver.exec(shell, cloneCmd, 60000, true);
30
38
 
31
39
  // Launch Chrome with the hello-world extension loaded
32
40
  await testdriver.provision.chromeExtension({
33
- extensionPath: '/tmp/chrome-extensions-samples/functional-samples/tutorial.hello-world',
34
- url: 'https://testdriver.ai'
41
+ extensionPath: extensionPath
35
42
  });
36
43
 
44
+ // Navigate to testdriver.ai (extensions don't load on New Tab)
45
+ const addressBar = await testdriver.find("Chrome address bar");
46
+ await addressBar.click();
47
+ await testdriver.type("testdriver.ai");
48
+ await testdriver.pressKeys(["enter"]);
49
+
50
+ // Wait for page to load
51
+ const pageResult = await testdriver.assert("I can see testdriver.ai");
52
+ expect(pageResult).toBeTruthy();
53
+
37
54
  // The hello-world extension adds a puzzle piece icon to the toolbar
38
55
  // When clicked, it shows a popup with "Hello Extensions"
39
-
40
- // First, let's verify Chrome loaded and we can see the page
41
- const pageResult = await testdriver.assert("chrome is running");
42
- expect(pageResult).toBeTruthy();
43
56
 
44
57
  // Click on the extensions button (puzzle piece icon) in Chrome toolbar
45
- const extensionsButton = await testdriver.find("The puzzle-shaped icon in the Chrome toolbar.");
58
+ const extensionsButton = await testdriver.find("The extensions button in the Chrome toolbar");
46
59
  await extensionsButton.click();
47
60
 
48
61
  // Look for the hello world extension in the extensions menu
@@ -54,8 +67,8 @@ describe("Chrome Extension Test", () => {
54
67
  expect(popupResult).toBeTruthy();
55
68
  });
56
69
 
57
- it.skipIf(!isLinux)("should load Loom from Chrome Web Store by extensionId", async (context) => {
58
- const testdriver = TestDriver(context, { headless: false, newSandbox: true});
70
+ it("should load Loom from Chrome Web Store by extensionId", async (context) => {
71
+ const testdriver = TestDriver(context);
59
72
 
60
73
  // Launch Chrome with Loom loaded by its Chrome Web Store ID
61
74
  // Loom ID: liecbddmkiiihnedobmlmillhodjkdmb
@@ -63,6 +76,16 @@ describe("Chrome Extension Test", () => {
63
76
  extensionId: 'liecbddmkiiihnedobmlmillhodjkdmb'
64
77
  });
65
78
 
79
+ // Navigate to testdriver.ai (extensions don't load on New Tab)
80
+ const addressBar = await testdriver.find("Chrome address bar");
81
+ await addressBar.click();
82
+ await testdriver.type("testdriver.ai");
83
+ await testdriver.pressKeys(["enter"]);
84
+
85
+ // Wait for page to load
86
+ const pageResult = await testdriver.assert("I can see testdriver.ai");
87
+ expect(pageResult).toBeTruthy();
88
+
66
89
  // Click on the extensions button (puzzle piece icon) in Chrome toolbar
67
90
  const extensionsButton = await testdriver.find("The puzzle-shaped icon in the Chrome toolbar.");
68
91
  await extensionsButton.click();
@@ -8,7 +8,7 @@ import { TestDriver } from "../../lib/vitest/hooks.mjs";
8
8
 
9
9
  /**
10
10
  * Perform login flow for SauceLabs demo app
11
- * @param {TestDriver} client - TestDriver client
11
+ * @param {import('../../sdk.js').default} client - TestDriver client instance
12
12
  * @param {string} username - Username (default: 'standard_user')
13
13
  */
14
14
  async function performLogin(client, username = "standard_user") {
@@ -27,11 +27,11 @@ async function performLogin(client, username = "standard_user") {
27
27
 
28
28
  describe("Hover Image Test", () => {
29
29
  it("should click on shopping cart icon and verify empty cart", async (context) => {
30
- const testdriver = TestDriver(context, { headless: true });
30
+ const testdriver = TestDriver(context, { ip: process.env.TD_IP });
31
31
 
32
32
  // provision.chrome() automatically calls ready() and starts dashcam
33
33
  await testdriver.provision.chrome({
34
- url: 'http://testdriver-sandbox.vercel.app/login',
34
+ url: 'http://testdriver-sandbox.vercel.app/login'
35
35
  });
36
36
 
37
37
  // Perform login first
@@ -8,7 +8,7 @@ import { TestDriver } from "../../lib/vitest/hooks.mjs";
8
8
 
9
9
  describe("Hover Text Test", () => {
10
10
  it("should click Sign In and verify error message", async (context) => {
11
- const testdriver = TestDriver(context, { headless: false, ip: '3.138.116.105'});
11
+ const testdriver = TestDriver(context, { ip: '3.138.116.105'});
12
12
  await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
13
13
 
14
14
  // Click on Sign In button using new find() API
@@ -12,7 +12,7 @@ describe("Provision Installer", () => {
12
12
  it.skipIf(!isLinux)(
13
13
  "should download and install a .deb package on Linux",
14
14
  async (context) => {
15
- const testdriver = TestDriver(context, { newSandbox: true });
15
+ const testdriver = TestDriver(context);
16
16
 
17
17
  // Install bat (a cat clone with syntax highlighting) using provision.installer
18
18
  const filePath = await testdriver.provision.installer({
@@ -30,7 +30,7 @@ describe("Provision Installer", () => {
30
30
  it.skipIf(!isLinux)(
31
31
  "should download a shell script and verify it exists",
32
32
  async (context) => {
33
- const testdriver = TestDriver(context, { newSandbox: true });
33
+ const testdriver = TestDriver(context);
34
34
 
35
35
  // Download a shell script (nvm installer)
36
36
  const filePath = await testdriver.provision.installer({
@@ -7,7 +7,7 @@ describe("Launch VS Code on Linux", () => {
7
7
  it.skipIf(!isLinux)(
8
8
  "should launch VS Code on Debian/Ubuntu",
9
9
  async (context) => {
10
- const testdriver = TestDriver(context, { newSandbox: true });
10
+ const testdriver = TestDriver(context);
11
11
 
12
12
  // provision.vscode() automatically calls ready() and starts dashcam
13
13
  await testdriver.provision.vscode();
@@ -24,7 +24,7 @@ describe("Launch VS Code on Linux", () => {
24
24
  it.skipIf(!isLinux)(
25
25
  "should install and use a VS Code extension",
26
26
  async (context) => {
27
- const testdriver = TestDriver(context, { newSandbox: true });
27
+ const testdriver = TestDriver(context);
28
28
 
29
29
  // Launch VS Code with the Prettier extension installed
30
30
  await testdriver.provision.vscode({