testdriverai 7.3.11 → 7.3.13

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 (133) hide show
  1. package/.github/skills/testdriver:ai/SKILL.md +204 -0
  2. package/.github/skills/testdriver:assert/SKILL.md +284 -0
  3. package/.github/skills/testdriver:aws-setup/SKILL.md +515 -0
  4. package/.github/skills/testdriver:caching/SKILL.md +124 -0
  5. package/.github/skills/testdriver:captcha/SKILL.md +159 -0
  6. package/.github/skills/testdriver:ci-cd/SKILL.md +602 -0
  7. package/.github/skills/testdriver:click/SKILL.md +286 -0
  8. package/.github/skills/testdriver:client/SKILL.md +339 -0
  9. package/.github/skills/testdriver:cloud/SKILL.md +119 -0
  10. package/.github/skills/testdriver:customizing-devices/SKILL.md +153 -0
  11. package/.github/skills/testdriver:dashcam/SKILL.md +418 -0
  12. package/.github/skills/testdriver:debugging-with-screenshots/SKILL.md +271 -0
  13. package/.github/skills/testdriver:device-config/SKILL.md +317 -0
  14. package/.github/skills/testdriver:double-click/SKILL.md +102 -0
  15. package/.github/skills/testdriver:elements/SKILL.md +605 -0
  16. package/.github/skills/testdriver:enterprise/SKILL.md +114 -0
  17. package/.github/skills/testdriver:examples/SKILL.md +7 -0
  18. package/.github/skills/testdriver:exec/SKILL.md +345 -0
  19. package/.github/skills/testdriver:find/SKILL.md +721 -0
  20. package/.github/skills/testdriver:focus-application/SKILL.md +293 -0
  21. package/.github/skills/testdriver:generating-tests/SKILL.md +36 -0
  22. package/.github/skills/testdriver:hover/SKILL.md +278 -0
  23. package/.github/skills/testdriver:locating-elements/SKILL.md +71 -0
  24. package/.github/skills/testdriver:making-assertions/SKILL.md +32 -0
  25. package/.github/skills/testdriver:mcp-workflow/SKILL.md +410 -0
  26. package/.github/skills/testdriver:mouse-down/SKILL.md +161 -0
  27. package/.github/skills/testdriver:mouse-up/SKILL.md +164 -0
  28. package/.github/skills/testdriver:performing-actions/SKILL.md +51 -0
  29. package/.github/skills/testdriver:press-keys/SKILL.md +348 -0
  30. package/.github/skills/testdriver:quickstart/SKILL.md +161 -0
  31. package/.github/skills/testdriver:reusable-code/SKILL.md +240 -0
  32. package/.github/skills/testdriver:right-click/SKILL.md +123 -0
  33. package/.github/skills/testdriver:running-tests/SKILL.md +181 -0
  34. package/.github/skills/testdriver:screenshot/SKILL.md +167 -0
  35. package/.github/skills/testdriver:scroll/SKILL.md +299 -0
  36. package/.github/skills/testdriver:secrets/SKILL.md +115 -0
  37. package/.github/skills/testdriver:self-hosted/SKILL.md +65 -0
  38. package/.github/skills/testdriver:test-writer/SKILL.md +451 -0
  39. package/.github/skills/testdriver:testdriver/SKILL.md +523 -0
  40. package/.github/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
  41. package/.github/skills/testdriver:type/SKILL.md +357 -0
  42. package/.github/skills/testdriver:variables/SKILL.md +111 -0
  43. package/.github/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
  44. package/.github/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  45. package/.github/workflows/acceptance-windows-scheduled.yaml +6 -1
  46. package/.github/workflows/acceptance.yaml +0 -36
  47. package/.github/workflows/update-examples.yaml +53 -0
  48. package/CHANGELOG.md +8 -0
  49. package/agent/events.js +1 -0
  50. package/agent/index.js +8 -0
  51. package/agent/lib/commands.js +48 -29
  52. package/agent/lib/redraw.js +3 -1
  53. package/agent/lib/sandbox.js +166 -14
  54. package/agent/lib/sdk.js +142 -3
  55. package/agent/lib/system.js +4 -6
  56. package/ai/skills/testdriver:ai/SKILL.md +204 -0
  57. package/ai/skills/testdriver:assert/SKILL.md +315 -0
  58. package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
  59. package/ai/skills/testdriver:caching/SKILL.md +124 -0
  60. package/ai/skills/testdriver:captcha/SKILL.md +159 -0
  61. package/ai/skills/testdriver:ci-cd/SKILL.md +602 -0
  62. package/ai/skills/testdriver:click/SKILL.md +286 -0
  63. package/ai/skills/testdriver:client/SKILL.md +372 -0
  64. package/ai/skills/testdriver:cloud/SKILL.md +119 -0
  65. package/ai/skills/testdriver:customizing-devices/SKILL.md +153 -0
  66. package/ai/skills/testdriver:dashcam/SKILL.md +418 -0
  67. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +401 -0
  68. package/ai/skills/testdriver:device-config/SKILL.md +317 -0
  69. package/ai/skills/testdriver:double-click/SKILL.md +102 -0
  70. package/ai/skills/testdriver:elements/SKILL.md +605 -0
  71. package/ai/skills/testdriver:enterprise/SKILL.md +114 -0
  72. package/ai/skills/testdriver:examples/SKILL.md +7 -0
  73. package/ai/skills/testdriver:exec/SKILL.md +345 -0
  74. package/ai/skills/testdriver:find/SKILL.md +745 -0
  75. package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
  76. package/ai/skills/testdriver:generating-tests/SKILL.md +36 -0
  77. package/ai/skills/testdriver:hover/SKILL.md +278 -0
  78. package/ai/skills/testdriver:locating-elements/SKILL.md +71 -0
  79. package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
  80. package/ai/skills/testdriver:mcp-workflow/SKILL.md +410 -0
  81. package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
  82. package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
  83. package/ai/skills/testdriver:ocr/SKILL.md +235 -0
  84. package/ai/skills/testdriver:performing-actions/SKILL.md +51 -0
  85. package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
  86. package/ai/skills/testdriver:quickstart/SKILL.md +146 -0
  87. package/ai/skills/testdriver:reusable-code/SKILL.md +240 -0
  88. package/ai/skills/testdriver:right-click/SKILL.md +123 -0
  89. package/ai/skills/testdriver:running-tests/SKILL.md +185 -0
  90. package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
  91. package/ai/skills/testdriver:scroll/SKILL.md +335 -0
  92. package/ai/skills/testdriver:secrets/SKILL.md +115 -0
  93. package/ai/skills/testdriver:self-hosted/SKILL.md +65 -0
  94. package/ai/skills/testdriver:test-writer/SKILL.md +451 -0
  95. package/ai/skills/testdriver:testdriver/SKILL.md +631 -0
  96. package/ai/skills/testdriver:testdriver-mechanic/SKILL.md +165 -0
  97. package/ai/skills/testdriver:type/SKILL.md +357 -0
  98. package/ai/skills/testdriver:variables/SKILL.md +111 -0
  99. package/ai/skills/testdriver:waiting-for-elements/SKILL.md +66 -0
  100. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  101. package/debugger/index.html +12 -2
  102. package/docs/v7/examples/scroll-keyboard.mdx +1 -1
  103. package/docs/v7/find.mdx +1 -0
  104. package/examples/config.mjs +1 -1
  105. package/examples/findall-coffee-icons.test.mjs +42 -0
  106. package/examples/flake-diffthreshold-001.test.mjs +9 -0
  107. package/examples/flake-diffthreshold-01.test.mjs +9 -0
  108. package/examples/flake-diffthreshold-05.test.mjs +9 -0
  109. package/examples/{z_flake-noredraw-cache.test.mjs → flake-noredraw-cache.test.mjs} +2 -2
  110. package/examples/{z_flake-noredraw-nocache.test.mjs → flake-noredraw-nocache.test.mjs} +2 -2
  111. package/examples/{z_flake-redraw-cache.test.mjs → flake-redraw-cache.test.mjs} +2 -2
  112. package/examples/{z_flake-redraw-nocache.test.mjs → flake-redraw-nocache.test.mjs} +2 -2
  113. package/examples/flake-rocket-match.test.mjs +30 -0
  114. package/examples/{z_flake-shared.mjs → flake-shared.mjs} +2 -2
  115. package/examples/parse.test.mjs +19 -0
  116. package/examples/scroll-keyboard.test.mjs +1 -1
  117. package/interfaces/cli/lib/base.js +6 -0
  118. package/interfaces/logger.js +51 -13
  119. package/interfaces/vitest-plugin.mjs +137 -0
  120. package/lib/core/index.d.ts +22 -0
  121. package/lib/init-project.js +105 -6
  122. package/lib/vitest/hooks.mjs +2 -5
  123. package/lib/vitest/setup-disable-defender.mjs +52 -0
  124. package/package.json +2 -1
  125. package/sdk-log-formatter.js +90 -0
  126. package/sdk.d.ts +88 -51
  127. package/sdk.js +128 -21
  128. package/setup/aws/disable-defender.sh +42 -0
  129. package/vitest.config.mjs +1 -3
  130. package/examples/z_flake-diffthreshold-001.test.mjs +0 -9
  131. package/examples/z_flake-diffthreshold-01.test.mjs +0 -9
  132. package/examples/z_flake-diffthreshold-05.test.mjs +0 -9
  133. /package/{examples → manual}/captcha-api.test.mjs +0 -0
@@ -0,0 +1,286 @@
1
+ ---
2
+ name: testdriver:click
3
+ description: Click at specific coordinates or on elements
4
+ ---
5
+ <!-- Generated from click.mdx. DO NOT EDIT. -->
6
+
7
+ ## Element Click
8
+
9
+ When called on an Element object, clicks on the located element.
10
+
11
+ ### Syntax
12
+
13
+ ```javascript
14
+ await element.click(action)
15
+ ```
16
+
17
+ ### Parameters
18
+
19
+ <ParamField path="action" type="string" default="click">
20
+ Type of click action: `'click'`, `'double-click'`, `'right-click'`, `'hover'`, `'mouseDown'`, `'mouseUp'`
21
+ </ParamField>
22
+
23
+ ### Returns
24
+
25
+ `Promise<void>`
26
+
27
+ ### Examples
28
+
29
+ ```javascript
30
+ // Regular click
31
+ const button = await testdriver.find('submit button');
32
+ await button.click();
33
+
34
+ // Double-click
35
+ const file = await testdriver.find('README.txt file');
36
+ await file.click('double-click');
37
+
38
+ // Right-click
39
+ const item = await testdriver.find('menu item');
40
+ await item.click('right-click');
41
+
42
+ // Hover (same as element.hover())
43
+ const tooltip = await testdriver.find('info icon');
44
+ await button.click('hover');
45
+ ```
46
+
47
+ ## Coordinate Click
48
+
49
+ Click at specific screen coordinates.
50
+
51
+ ### Syntax
52
+
53
+ ```javascript
54
+ await testdriver.click(x, y, action)
55
+ ```
56
+
57
+ ### Parameters
58
+
59
+ <ParamField path="x" type="number" required>
60
+ X coordinate
61
+ </ParamField>
62
+
63
+ <ParamField path="y" type="number" required>
64
+ Y coordinate
65
+ </ParamField>
66
+
67
+ <ParamField path="action" type="string" default="click">
68
+ Type of click: `'click'`, `'double-click'`, `'right-click'`, `'mouseDown'`, `'mouseUp'`
69
+ </ParamField>
70
+
71
+ ### Returns
72
+
73
+ `Promise<void>`
74
+
75
+ ### Examples
76
+
77
+ ```javascript
78
+ // Click at coordinates
79
+ await testdriver.click(500, 300);
80
+
81
+ // Double-click at coordinates
82
+ await testdriver.click(500, 300, 'double-click');
83
+
84
+ // Right-click at coordinates
85
+ await testdriver.click(500, 300, 'right-click');
86
+ ```
87
+
88
+ ## Click Actions
89
+
90
+ ### Regular Click
91
+
92
+ Single left-click action.
93
+
94
+ ```javascript
95
+ const button = await testdriver.find('Login button');
96
+ await button.click();
97
+ ```
98
+
99
+ ### Double Click
100
+
101
+ Double-click action, commonly used to open files or select text.
102
+
103
+ ```javascript
104
+ const file = await testdriver.find('document.pdf');
105
+ await file.click('double-click');
106
+
107
+ // Or use the dedicated method
108
+ await file.doubleClick();
109
+ ```
110
+
111
+ ### Right Click
112
+
113
+ Right-click to open context menus.
114
+
115
+ ```javascript
116
+ const folder = await testdriver.find('Documents folder');
117
+ await folder.click('right-click');
118
+
119
+ // Or use the dedicated method
120
+ await folder.rightClick();
121
+ ```
122
+
123
+ ### Mouse Down / Mouse Up
124
+
125
+ For drag operations or custom click behavior.
126
+
127
+ ```javascript
128
+ const draggable = await testdriver.find('draggable item');
129
+ await draggable.click('mouseDown');
130
+
131
+ // Move to target
132
+ const dropZone = await testdriver.find('drop zone');
133
+ await dropZone.hover();
134
+ await dropZone.click('mouseUp');
135
+
136
+ // Or use dedicated methods
137
+ await draggable.mouseDown();
138
+ await dropZone.mouseUp();
139
+ ```
140
+
141
+ ## Best Practices
142
+
143
+ <Check>
144
+ **Prefer element clicks over coordinate clicks**
145
+
146
+ Element-based clicking is more reliable and resolution-independent:
147
+
148
+ ```javascript
149
+ // ✅ Preferred
150
+ const button = await testdriver.find('submit button');
151
+ await button.click();
152
+
153
+ // ❌ Avoid (fragile)
154
+ await testdriver.click(500, 300);
155
+ ```
156
+ </Check>
157
+
158
+ <Check>
159
+ **Verify element was found**
160
+
161
+ ```javascript
162
+ const element = await testdriver.find('button');
163
+ if (!element.found()) {
164
+ throw new Error('Element not found');
165
+ }
166
+ await element.click();
167
+ ```
168
+ </Check>
169
+
170
+ <Warning>
171
+ **Element must be found before clicking**
172
+
173
+ The `find()` method automatically locates elements, but clicking an element that wasn't found will throw an error:
174
+
175
+ ```javascript
176
+ const element = await testdriver.find('button');
177
+ // This will throw if element wasn't found
178
+ await element.click();
179
+ ```
180
+ </Warning>
181
+
182
+ ## Use Cases
183
+
184
+ <AccordionGroup>
185
+ <Accordion title="Button Clicks">
186
+ ```javascript
187
+ const submitBtn = await testdriver.find('submit button');
188
+ await submitBtn.click();
189
+
190
+ const cancelBtn = await testdriver.find('cancel button');
191
+ await cancelBtn.click();
192
+ ```
193
+ </Accordion>
194
+
195
+ <Accordion title="Opening Files">
196
+ ```javascript
197
+ const file = await testdriver.find('report.pdf file icon');
198
+ await file.doubleClick();
199
+ ```
200
+ </Accordion>
201
+
202
+ <Accordion title="Context Menus">
203
+ ```javascript
204
+ const item = await testdriver.find('file item');
205
+ await item.rightClick();
206
+
207
+ // Select menu option
208
+ const deleteOption = await testdriver.find('Delete option');
209
+ await deleteOption.click();
210
+ ```
211
+ </Accordion>
212
+
213
+ <Accordion title="Drag and Drop">
214
+ ```javascript
215
+ const source = await testdriver.find('source item');
216
+ await source.mouseDown();
217
+
218
+ const target = await testdriver.find('target zone');
219
+ await target.hover();
220
+ await target.mouseUp();
221
+ ```
222
+ </Accordion>
223
+ </AccordionGroup>
224
+
225
+ ## Complete Example
226
+
227
+ ```javascript
228
+ import { beforeAll, afterAll, describe, it } from 'vitest';
229
+ import TestDriver from 'testdriverai';
230
+
231
+ describe('Click Interactions', () => {
232
+ let testdriver;
233
+
234
+ beforeAll(async () => {
235
+ client = new TestDriver(process.env.TD_API_KEY);
236
+ await testdriver.auth();
237
+ await testdriver.connect();
238
+ });
239
+
240
+ afterAll(async () => {
241
+ await testdriver.disconnect();
242
+ });
243
+
244
+ it('should perform various click actions', async () => {
245
+ await testdriver.focusApplication('Google Chrome');
246
+
247
+ // Regular click
248
+ const loginBtn = await testdriver.find('login button');
249
+ await loginBtn.click();
250
+
251
+ // Right-click for context menu
252
+ const profileIcon = await testdriver.find('profile icon');
253
+ await profileIcon.rightClick();
254
+
255
+ const settingsOption = await testdriver.find('Settings menu option');
256
+ await settingsOption.click();
257
+
258
+ // Double-click to edit
259
+ const nameField = await testdriver.find('name display field');
260
+ await nameField.doubleClick();
261
+
262
+ // Verify state
263
+ await testdriver.assert('name field is now editable');
264
+ });
265
+
266
+ it('should perform drag and drop', async () => {
267
+ const item = await testdriver.find('draggable item');
268
+ await item.mouseDown();
269
+
270
+ // Drag to new location
271
+ const dropTarget = await testdriver.find('drop area');
272
+ await dropTarget.hover();
273
+ await dropTarget.mouseUp();
274
+
275
+ // Verify
276
+ await testdriver.assert('item is in the drop area');
277
+ });
278
+ });
279
+ ```
280
+
281
+ ## Related Methods
282
+
283
+ - [`find()`](/v7/find) - Locate elements to click
284
+ - [`hover()`](/v7/hover) - Hover without clicking
285
+ - [`doubleClick()`](/v7/double-click) - Dedicated double-click method
286
+ - [`rightClick()`](/v7/right-click) - Dedicated right-click method
@@ -0,0 +1,372 @@
1
+ ---
2
+ name: testdriver:client
3
+ description: Initialize and configure the TestDriver SDK client
4
+ ---
5
+ <!-- Generated from client.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ The `TestDriver` client is the main entry point for the SDK. It handles authentication, sandbox connection, and provides access to all testing methods.
10
+
11
+ ## Constructor
12
+
13
+ ```javascript
14
+ const testdriver = new TestDriver(apiKey, options)
15
+ ```
16
+
17
+ ### Parameters
18
+
19
+ <ParamField path="apiKey" type="string" required>
20
+ Your TestDriver API key from the [dashboard](https://console.testdriver.ai/team)
21
+ </ParamField>
22
+
23
+ <ParamField path="options" type="object">
24
+ Configuration options for the client
25
+
26
+ <Expandable title="properties">
27
+ <ParamField path="os" type="string" default="windows">
28
+ Operating system for the sandbox: `'windows'` or `'linux'`
29
+ </ParamField>
30
+
31
+ <ParamField path="resolution" type="string" default="1366x768">
32
+ Screen resolution for the sandbox (e.g., `'1920x1080'`, `'1366x768'`)
33
+ </ParamField>
34
+
35
+ <ParamField path="apiRoot" type="string" default="https://testdriver-api.onrender.com">
36
+ API endpoint URL (typically only changed for self-hosted deployments)
37
+ </ParamField>
38
+
39
+ <ParamField path="analytics" type="boolean" default="true">
40
+ Enable or disable usage analytics
41
+ </ParamField>
42
+
43
+ <ParamField path="logging" type="boolean" default="true">
44
+ Enable or disable console logging
45
+ </ParamField>
46
+
47
+ <ParamField path="autoScreenshots" type="boolean" default="true">
48
+ Automatically capture screenshots before and after each command. Screenshots are saved to `.testdriver/screenshots/<test>/` with descriptive filenames that include the line number and action name. Format: `<seq>-<action>-<phase>-L<line>-<description>.png`
49
+ </ParamField>
50
+
51
+ <ParamField path="environment" type="object">
52
+ Additional environment variables to pass to the sandbox
53
+ </ParamField>
54
+
55
+ <ParamField path="ai" type="object">
56
+ Global AI sampling configuration. Controls how the AI model generates responses for `find()` verification and `assert()` calls. Can be overridden per call.
57
+
58
+ <Expandable title="properties">
59
+ <ParamField path="temperature" type="number">
60
+ Controls randomness in AI responses. `0` = deterministic (best for verification), higher values = more creative. Default: `0` for find verification, model default for assert.
61
+ </ParamField>
62
+
63
+ <ParamField path="top" type="object">
64
+ Nucleus and top-k sampling parameters
65
+
66
+ <Expandable title="properties">
67
+ <ParamField path="p" type="number">
68
+ Top-P (nucleus sampling). Limits token choices to the smallest set whose cumulative probability exceeds P. Lower values = more focused responses. Range: 0-1.
69
+ </ParamField>
70
+
71
+ <ParamField path="k" type="number">
72
+ Top-K sampling. Limits token choices to the top K most likely tokens. `1` = always pick the most likely token. `0` = disabled (consider all tokens).
73
+ </ParamField>
74
+ </Expandable>
75
+ </ParamField>
76
+ </Expandable>
77
+ </ParamField>
78
+ </Expandable>
79
+ </ParamField>
80
+
81
+ ### Example
82
+
83
+ ```javascript
84
+ import TestDriver from 'testdriverai';
85
+
86
+ // API key is automatically loaded from TD_API_KEY in .env
87
+ const testdriver = new TestDriver({
88
+ os: 'windows',
89
+ resolution: '1920x1080',
90
+ logging: true,
91
+ analytics: true
92
+ });
93
+
94
+ // With AI config for stricter verification
95
+ const testdriver = new TestDriver({
96
+ ai: { temperature: 0, top: { p: 0.9, k: 40 } }
97
+ });
98
+
99
+ // Or pass API key explicitly
100
+ const testdriver = new TestDriver('your-api-key', {
101
+ os: 'windows'
102
+ });
103
+ ```
104
+
105
+ ## Authentication
106
+
107
+ ### auth()
108
+
109
+ Authenticate with the TestDriver API.
110
+
111
+ ```javascript
112
+ await testdriver.auth()
113
+ ```
114
+
115
+ **Returns:** `Promise<string>` - Authentication token
116
+
117
+ **Example:**
118
+ ```javascript
119
+ await testdriver.auth();
120
+ ```
121
+
122
+ <Note>
123
+ You must call `auth()` before `connect()`. Most examples call both sequentially.
124
+ </Note>
125
+
126
+ ## Connection Management
127
+
128
+ ### connect()
129
+
130
+ Connect to a sandbox environment. This creates or reconnects to a virtual machine where your tests will run.
131
+
132
+ ```javascript
133
+ await testdriver.connect(options)
134
+ ```
135
+
136
+ #### Parameters
137
+
138
+ <ParamField path="options" type="object">
139
+ Connection options
140
+
141
+ <Expandable title="properties">
142
+ <ParamField path="newSandbox" type="boolean" default="false">
143
+ Force creation of a new sandbox instead of reusing an existing one
144
+ </ParamField>
145
+
146
+ <ParamField path="sandboxId" type="string">
147
+ Existing sandbox ID to reconnect to
148
+ </ParamField>
149
+
150
+ <ParamField path="ip" type="string">
151
+ Direct IP address to connect to (for self-hosted sandboxes)
152
+ </ParamField>
153
+
154
+ <ParamField path="sandboxAmi" type="string">
155
+ AMI to use for the sandbox (AWS deployments)
156
+ </ParamField>
157
+
158
+ <ParamField path="sandboxInstance" type="string">
159
+ Instance type for the sandbox (AWS deployments)
160
+ </ParamField>
161
+
162
+ <ParamField path="preview" type="string" default="browser">
163
+ Preview mode for live test visualization:
164
+ - `"browser"` - Opens debugger in default browser (default)
165
+ - `"ide"` - Opens preview in IDE panel (VSCode, Cursor - requires TestDriver extension)
166
+ - `"none"` - Headless mode, no visual preview
167
+ </ParamField>
168
+
169
+ <ParamField path="headless" type="boolean" default="false">
170
+ **Deprecated**: Use `preview: "none"` instead. Run in headless mode without opening the debugger.
171
+ </ParamField>
172
+ </Expandable>
173
+ </ParamField>
174
+
175
+ **Returns:** `Promise&lt;Object&gt;` - Sandbox instance details including `instanceId`, `ip`, `vncPort`, etc.
176
+
177
+ #### Examples
178
+
179
+ **Basic connection:**
180
+ ```javascript
181
+ await testdriver.connect();
182
+ ```
183
+
184
+ **Reconnect to existing sandbox:**
185
+ ```javascript
186
+ const instance = await testdriver.connect({
187
+ sandboxId: 'existing-sandbox-id-123'
188
+ });
189
+ ```
190
+
191
+ **Self-hosted sandbox:**
192
+ ```javascript
193
+ await testdriver.connect({
194
+ ip: '192.168.1.100'
195
+ });
196
+ ```
197
+
198
+ ### disconnect()
199
+
200
+ Disconnect from the sandbox and clean up resources.
201
+
202
+ ```javascript
203
+ await testdriver.disconnect()
204
+ ```
205
+
206
+ **Returns:** `Promise<void>`
207
+
208
+ **Example:**
209
+ ```javascript
210
+ afterAll(async () => {
211
+ await testdriver.disconnect();
212
+ });
213
+ ```
214
+
215
+ ## Instance Information
216
+
217
+ ### getInstance()
218
+
219
+ Get the current sandbox instance details.
220
+
221
+ ```javascript
222
+ const instance = testdriver.getInstance()
223
+ ```
224
+
225
+ **Returns:** `Object | null` - Sandbox instance information
226
+
227
+ **Example:**
228
+ ```javascript
229
+ const instance = testdriver.getInstance();
230
+ console.log('Instance ID:', instance.instanceId);
231
+ console.log('IP Address:', instance.ip);
232
+ ```
233
+
234
+ ### getSessionId()
235
+
236
+ Get the current session ID for tracking and debugging.
237
+
238
+ ```javascript
239
+ const sessionId = testdriver.getSessionId()
240
+ ```
241
+
242
+ **Returns:** `string | null` - Session ID
243
+
244
+ **Example:**
245
+ ```javascript
246
+ const sessionId = testdriver.getSessionId();
247
+ console.log('Session:', sessionId);
248
+ ```
249
+
250
+ ## Logging & Events
251
+
252
+ ### setLogging()
253
+
254
+ Enable or disable console logging at runtime.
255
+
256
+ ```javascript
257
+ testdriver.setLogging(enabled)
258
+ ```
259
+
260
+ **Parameters:**
261
+ - `enabled` (boolean) - Whether to enable logging
262
+
263
+ **Example:**
264
+ ```javascript
265
+ // Disable logging for cleanup operations
266
+ testdriver.setLogging(false);
267
+ await testdriver.disconnect();
268
+ testdriver.setLogging(true);
269
+ ```
270
+
271
+ ### getEmitter()
272
+
273
+ Get the event emitter for custom event handling.
274
+
275
+ ```javascript
276
+ const emitter = testdriver.getEmitter()
277
+ ```
278
+
279
+ **Returns:** `EventEmitter2` - Event emitter instance
280
+
281
+ **Example:**
282
+ ```javascript
283
+ const emitter = testdriver.getEmitter();
284
+
285
+ emitter.on('command:start', (data) => {
286
+ console.log('Command started:', data);
287
+ });
288
+
289
+ emitter.on('command:success', (data) => {
290
+ console.log('Command succeeded:', data);
291
+ });
292
+
293
+ emitter.on('command:error', (error) => {
294
+ console.error('Command failed:', error);
295
+ });
296
+ ```
297
+
298
+ ## Complete Example
299
+
300
+ ```javascript
301
+ import { beforeAll, afterAll, describe, it } from 'vitest';
302
+ import TestDriver from 'testdriverai';
303
+
304
+ describe('My Test Suite', () => {
305
+ let testdriver;
306
+
307
+ beforeAll(async () => {
308
+ // Initialize client - API key loaded automatically from .env
309
+ testdriver = new TestDriver({
310
+ os: 'windows',
311
+ resolution: '1366x768',
312
+ logging: true
313
+ });
314
+
315
+ // Set up event listeners
316
+ const emitter = testdriver.getEmitter();
317
+ emitter.on('log:info', (msg) => console.log('[INFO]', msg));
318
+
319
+ // Authenticate and connect
320
+ await testdriver.auth();
321
+ const instance = await testdriver.connect();
322
+
323
+ console.log('Connected to sandbox:', instance.instanceId);
324
+ });
325
+
326
+ afterAll(async () => {
327
+ await testdriver.disconnect();
328
+ });
329
+
330
+ it('runs a test', async () => {
331
+ // Your test code here
332
+ });
333
+ });
334
+ ```
335
+
336
+ ## Best Practices
337
+
338
+ <AccordionGroup>
339
+ <Accordion title="Reuse sandboxes across tests">
340
+ Use `beforeAll`/`afterAll` to create one sandbox per test suite rather than per test. This significantly reduces execution time.
341
+ </Accordion>
342
+
343
+ <Accordion title="Handle connection errors gracefully">
344
+ Wrap `connect()` in a try-catch block to handle network issues or quota limits:
345
+
346
+ ```javascript
347
+ try {
348
+ await testdriver.connect();
349
+ } catch (error) {
350
+ console.error('Failed to connect:', error.message);
351
+ throw error;
352
+ }
353
+ ```
354
+ </Accordion>
355
+
356
+ <Accordion title="Always disconnect">
357
+ Use `afterAll` or try-finally blocks to ensure `disconnect()` is called even if tests fail. This prevents orphaned sandboxes.
358
+ </Accordion>
359
+
360
+ <Accordion title="Use environment variables for API keys">
361
+ Never hardcode API keys. The SDK automatically loads `TD_API_KEY` from your `.env` file:
362
+
363
+ ```bash .env
364
+ TD_API_KEY=your_api_key_here
365
+ ```
366
+
367
+ ```javascript
368
+ // API key is loaded automatically - no need to pass it!
369
+ const testdriver = new TestDriver();
370
+ ```
371
+ </Accordion>
372
+ </AccordionGroup>