testdriverai 7.2.3 → 7.2.10

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 (142) hide show
  1. package/.github/workflows/publish.yaml +15 -7
  2. package/.github/workflows/testdriver.yml +163 -0
  3. package/.testdriver/last-sandbox +7 -0
  4. package/agent/events.js +1 -0
  5. package/agent/index.js +99 -163
  6. package/agent/lib/sandbox.js +11 -1
  7. package/agents.md +393 -0
  8. package/bin/testdriverai.js +8 -0
  9. package/debug/01-table-initial.png +0 -0
  10. package/debug/02-after-ai-explore.png +0 -0
  11. package/debug/02-after-scroll.png +0 -0
  12. package/debugger/index.html +37 -0
  13. package/docs/docs.json +93 -125
  14. package/docs/v7/_drafts/architecture.mdx +1 -26
  15. package/docs/v7/_drafts/caching.mdx +2 -2
  16. package/docs/v7/{getting-started → _drafts}/installation.mdx +0 -66
  17. package/docs/v7/{features/coverage.mdx → _drafts/powerful.mdx} +1 -90
  18. package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -1
  19. package/docs/v7/{features → _drafts}/scalable.mdx +126 -4
  20. package/docs/v7/_drafts/screenshot.mdx +155 -0
  21. package/docs/v7/_drafts/test-recording.mdx +0 -6
  22. package/docs/v7/_drafts/writing-tests.mdx +25 -0
  23. package/docs/v7/{api/act.mdx → ai.mdx} +28 -27
  24. package/docs/v7/{api/assert.mdx → assert.mdx} +3 -3
  25. package/docs/v7/aws-setup.mdx +338 -0
  26. package/docs/v7/caching.mdx +128 -0
  27. package/docs/v7/ci-cd.mdx +605 -0
  28. package/docs/v7/{api/click.mdx → click.mdx} +4 -4
  29. package/docs/v7/cloud.mdx +120 -0
  30. package/docs/v7/customizing-devices.mdx +129 -0
  31. package/docs/v7/{api/doubleClick.mdx → double-click.mdx} +5 -5
  32. package/docs/v7/enterprise.mdx +135 -0
  33. package/docs/v7/examples.mdx +5 -0
  34. package/docs/v7/{api/exec.mdx → exec.mdx} +3 -3
  35. package/docs/v7/{api/find.mdx → find.mdx} +17 -21
  36. package/docs/v7/{api/focusApplication.mdx → focus-application.mdx} +3 -3
  37. package/docs/v7/generating-tests.mdx +32 -0
  38. package/docs/v7/{api/hover.mdx → hover.mdx} +3 -3
  39. package/docs/v7/locating-elements.mdx +71 -0
  40. package/docs/v7/making-assertions.mdx +32 -0
  41. package/docs/v7/{api/mouseDown.mdx → mouse-down.mdx} +7 -7
  42. package/docs/v7/{api/mouseUp.mdx → mouse-up.mdx} +8 -8
  43. package/docs/v7/performing-actions.mdx +51 -0
  44. package/docs/v7/{api/pressKeys.mdx → press-keys.mdx} +3 -3
  45. package/docs/v7/quickstart.mdx +162 -0
  46. package/docs/v7/reusable-code.mdx +240 -0
  47. package/docs/v7/{api/rightClick.mdx → right-click.mdx} +5 -5
  48. package/docs/v7/running-tests.mdx +181 -0
  49. package/docs/v7/{api/scroll.mdx → scroll.mdx} +3 -3
  50. package/docs/v7/secrets.mdx +115 -0
  51. package/docs/v7/self-hosted.mdx +66 -0
  52. package/docs/v7/{api/type.mdx → type.mdx} +3 -3
  53. package/docs/v7/variables.mdx +111 -0
  54. package/docs/v7/waiting-for-elements.mdx +66 -0
  55. package/docs/v7/what-is-testdriver.mdx +54 -0
  56. package/interfaces/cli/commands/init.js +33 -19
  57. package/interfaces/cli/lib/base.js +24 -0
  58. package/interfaces/cli.js +8 -1
  59. package/interfaces/logger.js +8 -3
  60. package/interfaces/vitest-plugin.mjs +16 -71
  61. package/lib/sentry.js +343 -0
  62. package/lib/vitest/hooks.mjs +81 -81
  63. package/package.json +4 -3
  64. package/sdk-log-formatter.js +41 -0
  65. package/sdk.d.ts +22 -9
  66. package/sdk.js +344 -100
  67. package/test/manual/reconnect-provision.test.mjs +49 -0
  68. package/test/manual/reconnect-signin.test.mjs +41 -0
  69. package/test/testdriver/act.test.mjs +30 -0
  70. package/test/testdriver/ai.test.mjs +30 -0
  71. package/test/testdriver/assert.test.mjs +1 -1
  72. package/test/testdriver/hover-text.test.mjs +1 -1
  73. package/test/testdriver/setup/testHelpers.mjs +8 -119
  74. package/test/testdriver/windows-installer.test.mjs +61 -0
  75. package/tests/example.test.js +33 -0
  76. package/tests/login.js +28 -0
  77. package/tests/table-sort-enrollments.test.mjs +72 -0
  78. package/tests/table-sort-experiment.test.mjs +42 -0
  79. package/tests/table-sort-setup.test.mjs +59 -0
  80. package/vitest.config.mjs +3 -1
  81. package/agent/lib/cache.js +0 -142
  82. package/docs/v7/api/assertions.mdx +0 -403
  83. package/docs/v7/features/ai-native.mdx +0 -413
  84. package/docs/v7/features/application-logs.mdx +0 -353
  85. package/docs/v7/features/browser-logs.mdx +0 -414
  86. package/docs/v7/features/cache-management.mdx +0 -402
  87. package/docs/v7/features/continuous-testing.mdx +0 -346
  88. package/docs/v7/features/data-driven-testing.mdx +0 -441
  89. package/docs/v7/features/easy-to-write.mdx +0 -280
  90. package/docs/v7/features/enterprise.mdx +0 -656
  91. package/docs/v7/features/fast.mdx +0 -406
  92. package/docs/v7/features/managed-sandboxes.mdx +0 -384
  93. package/docs/v7/features/network-monitoring.mdx +0 -568
  94. package/docs/v7/features/parallel-execution.mdx +0 -381
  95. package/docs/v7/features/powerful.mdx +0 -531
  96. package/docs/v7/features/sandbox-customization.mdx +0 -229
  97. package/docs/v7/features/stable.mdx +0 -473
  98. package/docs/v7/features/system-performance.mdx +0 -616
  99. package/docs/v7/features/test-analytics.mdx +0 -373
  100. package/docs/v7/features/test-cases.mdx +0 -393
  101. package/docs/v7/features/test-replays.mdx +0 -408
  102. package/docs/v7/features/test-reports.mdx +0 -308
  103. package/docs/v7/getting-started/debugging-tests.mdx +0 -382
  104. package/docs/v7/getting-started/quickstart.mdx +0 -90
  105. package/docs/v7/getting-started/running-tests.mdx +0 -173
  106. package/docs/v7/getting-started/setting-up-in-ci.mdx +0 -612
  107. package/docs/v7/getting-started/writing-tests.mdx +0 -534
  108. package/docs/v7/overview/what-is-testdriver.mdx +0 -386
  109. package/docs/v7/presets/chrome-extension.mdx +0 -248
  110. package/docs/v7/presets/chrome.mdx +0 -300
  111. package/docs/v7/presets/electron.mdx +0 -460
  112. package/docs/v7/presets/vscode.mdx +0 -417
  113. package/docs/v7/presets/webapp.mdx +0 -393
  114. /package/docs/v7/{commands → _drafts/commands}/assert.mdx +0 -0
  115. /package/docs/v7/{commands → _drafts/commands}/exec.mdx +0 -0
  116. /package/docs/v7/{commands → _drafts/commands}/focus-application.mdx +0 -0
  117. /package/docs/v7/{commands → _drafts/commands}/hover-image.mdx +0 -0
  118. /package/docs/v7/{commands → _drafts/commands}/hover-text.mdx +0 -0
  119. /package/docs/v7/{commands → _drafts/commands}/if.mdx +0 -0
  120. /package/docs/v7/{commands → _drafts/commands}/match-image.mdx +0 -0
  121. /package/docs/v7/{commands → _drafts/commands}/press-keys.mdx +0 -0
  122. /package/docs/v7/{commands → _drafts/commands}/remember.mdx +0 -0
  123. /package/docs/v7/{commands → _drafts/commands}/run.mdx +0 -0
  124. /package/docs/v7/{commands → _drafts/commands}/scroll-until-image.mdx +0 -0
  125. /package/docs/v7/{commands → _drafts/commands}/scroll-until-text.mdx +0 -0
  126. /package/docs/v7/{commands → _drafts/commands}/scroll.mdx +0 -0
  127. /package/docs/v7/{commands → _drafts/commands}/type.mdx +0 -0
  128. /package/docs/v7/{commands → _drafts/commands}/wait-for-image.mdx +0 -0
  129. /package/docs/v7/{commands → _drafts/commands}/wait-for-text.mdx +0 -0
  130. /package/docs/v7/{commands → _drafts/commands}/wait.mdx +0 -0
  131. /package/docs/v7/{getting-started → _drafts}/configuration.mdx +0 -0
  132. /package/docs/v7/{features → _drafts}/observable.mdx +0 -0
  133. /package/docs/v7/{platforms → _drafts/platforms}/linux.mdx +0 -0
  134. /package/docs/v7/{platforms → _drafts/platforms}/macos.mdx +0 -0
  135. /package/docs/v7/{platforms → _drafts/platforms}/windows.mdx +0 -0
  136. /package/docs/v7/{playwright.mdx → _drafts/playwright.mdx} +0 -0
  137. /package/docs/v7/{overview → _drafts}/readme.mdx +0 -0
  138. /package/docs/v7/{features → _drafts}/reports.mdx +0 -0
  139. /package/docs/v7/{api/client.mdx → client.mdx} +0 -0
  140. /package/docs/v7/{api/dashcam.mdx → dashcam.mdx} +0 -0
  141. /package/docs/v7/{api/elements.mdx → elements.mdx} +0 -0
  142. /package/docs/v7/{api/sandbox.mdx → sandbox.mdx} +0 -0
package/agents.md ADDED
@@ -0,0 +1,393 @@
1
+ # TestDriver Agent Guide
2
+
3
+ This guide is designed for AI agents working with TestDriver. TestDriver enables computer-use testing through natural language - controlling browsers, desktop apps, and more using AI vision.
4
+
5
+ ## Quick Reference
6
+
7
+ | Resource | Location |
8
+ |----------|----------|
9
+ | Code samples | `node_modules/testdriverai/test` |
10
+ | TypeScript types | `node_modules/testdriverai/sdk.d.ts` |
11
+ | Documentation | `node_modules/testdriverai/docs` |
12
+ | API Key | [console.testdriver.ai/team](https://console.testdriver.ai/team) |
13
+
14
+ ## Prerequisites
15
+
16
+ ### API Key Setup
17
+
18
+ The user **must** have a TestDriver API key set in their environment:
19
+
20
+ ```bash
21
+ # .env file
22
+ TD_API_KEY=your_api_key_here
23
+ ```
24
+
25
+ Get your API key at: **https://console.testdriver.ai/team**
26
+
27
+ ### Test Runner
28
+
29
+ TestDriver **only works with Vitest**. Tests must use the `.test.mjs` extension and import from vitest:
30
+
31
+ ```javascript
32
+ import { describe, expect, it } from "vitest";
33
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
34
+ ```
35
+
36
+ ## Basic Test Structure
37
+
38
+ ```javascript
39
+ import { describe, expect, it } from "vitest";
40
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
41
+
42
+ describe("My Test Suite", () => {
43
+ it("should do something", async (context) => {
44
+ // Initialize TestDriver with options
45
+ const testdriver = TestDriver(context, { newSandbox: true, headless: false });
46
+
47
+ // Start with provision - this launches the sandbox and browser
48
+ await testdriver.provision.chrome({
49
+ url: 'https://example.com',
50
+ });
51
+
52
+ // Find elements and interact
53
+ const button = await testdriver.find("Sign In button");
54
+ await button.click();
55
+
56
+ // Assert using natural language
57
+ const result = await testdriver.assert("the dashboard is visible");
58
+ expect(result).toBeTruthy();
59
+ });
60
+ });
61
+ ```
62
+
63
+ ## Provisioning Options
64
+
65
+ Most tests start with `testdriver.provision`. Choose the right one:
66
+
67
+ ### `provision.chrome` - Web Testing (Most Common)
68
+ ```javascript
69
+ await testdriver.provision.chrome({
70
+ url: 'https://your-app.com',
71
+ });
72
+ ```
73
+
74
+ ### `provision.installer` - Desktop App Testing
75
+ ```javascript
76
+ // Download and install an application
77
+ const filePath = await testdriver.provision.installer({
78
+ url: 'https://example.com/app.deb', // or .msi, .exe, .sh
79
+ launch: true, // auto-launch after install
80
+ });
81
+ ```
82
+
83
+ ## Key SDK Methods
84
+
85
+ The SDK has TypeScript types in `sdk.d.ts`. Key methods:
86
+
87
+ | Method | Purpose |
88
+ |--------|---------|
89
+ | `find(description)` | Find element by natural language |
90
+ | `findAll(description)` | Find all matching elements |
91
+ | `assert(assertion)` | AI-powered assertion |
92
+ | `type(text)` | Type text |
93
+ | `pressKeys([keys])` | Press keyboard keys |
94
+ | `scroll(direction)` | Scroll the page |
95
+ | `exec(language, code)` | Execute code in sandbox |
96
+ | `ai(task)` | AI exploratory loop (see note below) |
97
+
98
+ ### About `ai()` - Use for Exploration, Not Final Tests
99
+
100
+ The `ai(task)` method lets the AI figure out how to accomplish a task autonomously. It's useful for:
101
+ - **Exploring** how to accomplish something when you're unsure of the steps
102
+ - **Discovering** element descriptions and UI flow
103
+ - **Last resort** when explicit methods fail repeatedly
104
+
105
+ However, **prefer explicit methods** (`find`, `click`, `type`) in final tests because:
106
+ - They're more predictable and repeatable
107
+ - They're faster (no AI reasoning loop)
108
+ - They're easier to debug when they fail
109
+
110
+ ```javascript
111
+ // ✅ GOOD: Explicit steps (preferred for final tests)
112
+ const emailInput = await testdriver.find("email input field");
113
+ await emailInput.click();
114
+ await testdriver.type("user@example.com");
115
+
116
+ // ⚠️ OK for exploration, but convert to explicit steps later
117
+ await testdriver.ai("fill in the email field with user@example.com");
118
+ ```
119
+
120
+ ### Element Properties (for debugging)
121
+
122
+ Elements returned by `find()` have properties you can inspect:
123
+
124
+ ```javascript
125
+ const element = await testdriver.find("Sign In button");
126
+
127
+ // Debugging properties
128
+ console.log(element.x, element.y); // coordinates
129
+ console.log(element.centerX, element.centerY); // center coordinates
130
+ console.log(element.width, element.height); // dimensions
131
+ console.log(element.confidence); // AI confidence score
132
+ console.log(element.text); // detected text
133
+ console.log(element.boundingBox); // full bounding box
134
+ ```
135
+
136
+ ### Element Methods
137
+
138
+ ```javascript
139
+ const element = await testdriver.find("button");
140
+ await element.click(); // click
141
+ await element.hover(); // hover
142
+ await element.doubleClick(); // double-click
143
+ await element.rightClick(); // right-click
144
+ await element.mouseDown(); // press mouse down
145
+ await element.mouseUp(); // release mouse
146
+ element.found(); // check if found (boolean)
147
+ ```
148
+
149
+ ## Best Workflow: Two-File Pattern
150
+
151
+ **The most efficient workflow for building tests uses two files.** This prevents having to restart from scratch when experimenting with new steps.
152
+
153
+ ### IMPORTANT: When to Use This Pattern
154
+
155
+ - **If a working test already exists**: Only create an `experiment.test.mjs` file to add new steps. Do NOT recreate the stable file.
156
+ - **If starting from scratch**: Start with a MINIMAL setup file, run it, verify it passes, THEN create the experiment file.
157
+
158
+ ### Step 1: Create a Minimal Setup File
159
+
160
+ Start with the bare minimum - just provision and one assertion. **Do NOT call it "stable" yet** - name it `setup.test.mjs` until it's proven to work:
161
+
162
+ ```javascript
163
+ /**
164
+ * Setup file - MINIMAL steps to get to starting state
165
+ * Only add more steps AFTER this passes!
166
+ */
167
+ import { afterAll, describe, expect, it } from "vitest";
168
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
169
+
170
+ describe("Setup State", () => {
171
+
172
+ afterAll(async () => {
173
+ // DO NOT disconnect - keep sandbox alive for reconnect
174
+ console.log("Sandbox staying alive for 30 seconds (keepAlive)");
175
+ });
176
+
177
+ it("should set up the application state", async (context) => {
178
+ const testdriver = TestDriver(context, {
179
+ newSandbox: true,
180
+ headless: false
181
+ });
182
+
183
+ await testdriver.provision.chrome({
184
+ url: 'https://your-app.com/login',
185
+ });
186
+
187
+ // Start with just ONE assertion to verify we're on the right page
188
+ const result = await testdriver.assert("I can see the login page");
189
+ expect(result).toBeTruthy();
190
+
191
+ console.log("✅ Setup ready - run experiment.test.mjs now");
192
+ });
193
+ });
194
+ ```
195
+
196
+ ### Step 2: Run Setup File and Verify It Passes
197
+
198
+ ```bash
199
+ vitest run tests/setup.test.mjs
200
+ ```
201
+
202
+ **Only proceed to Step 3 if this passes!** If it fails, fix it first.
203
+
204
+ ### Step 3: Create Experiment File
205
+
206
+ Only AFTER the setup file passes, create the experiment file.
207
+
208
+ **CRITICAL: The experiment file must NOT call `provision`!** It reconnects to the existing sandbox where provision already ran:
209
+
210
+ ```javascript
211
+ /**
212
+ * Experiment file - reconnects to existing sandbox
213
+ * Run AFTER setup.test.mjs passes (within 2 minutes)
214
+ */
215
+ import { describe, expect, it } from "vitest";
216
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
217
+
218
+ describe("Experiment", () => {
219
+
220
+ it("should continue from existing state", async (context) => {
221
+ const testdriver = TestDriver(context, {
222
+ newSandbox: true,
223
+ headless: false,
224
+ reconnect: true // ← Key: reconnects to last sandbox
225
+ });
226
+
227
+ // NO provision here! The sandbox is already running from setup.test.mjs
228
+
229
+ // Experiment with new steps here - try ONE thing at a time
230
+ const element = await testdriver.find("email input");
231
+ console.log("Found element:", element.found(), element.getCoordinates());
232
+
233
+ await element.click();
234
+ await testdriver.type("user@example.com");
235
+
236
+ // Assert after each major step
237
+ const result = await testdriver.assert("email is filled in");
238
+ console.log("Assertion result:", result);
239
+ expect(result).toBeTruthy();
240
+ });
241
+ });
242
+ ```
243
+
244
+ ### Step 4: Iterate in Experiment File
245
+
246
+ - Run experiment, see output, fix issues
247
+ - Once steps work, move them to the setup file
248
+ - Re-run setup file to verify it still passes
249
+ - Repeat until complete
250
+
251
+ ### Running the Two-File Pattern
252
+
253
+ ```bash
254
+ # Step 1: Run setup file (must pass first!)
255
+ vitest run tests/setup.test.mjs
256
+
257
+ # Step 2: Within 2 minutes, run experiment file
258
+ vitest run tests/experiment.test.mjs
259
+ ```
260
+
261
+ ### After Experimentation: Combine and Rename
262
+
263
+ **IMPORTANT:** Once the test is working, combine both files into a single, properly-named test file:
264
+
265
+ 1. **Merge the code** - Copy the working steps from `experiment.test.mjs` into `setup.test.mjs`
266
+ 2. **Remove reconnect options** - Delete `reconnect: true` since the final test runs standalone
267
+ 3. **Rename the file** - Give it a meaningful name like `login-flow.test.mjs` or `checkout-process.test.mjs`
268
+ 4. **Delete the experiment file** - Clean up `experiment.test.mjs`
269
+
270
+ ```javascript
271
+ // Final combined test: login-flow.test.mjs
272
+ import { describe, expect, it } from "vitest";
273
+ import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
274
+
275
+ describe("Login Flow", () => {
276
+ it("should log in and open settings", async (context) => {
277
+ const testdriver = TestDriver(context, { newSandbox: true, headless: false });
278
+
279
+ await testdriver.provision.chrome({ url: 'https://your-app.com/login' });
280
+
281
+ // Steps from stable file
282
+ await testdriver.find("email input").click();
283
+ await testdriver.type("user@example.com");
284
+ await testdriver.find("password input").click();
285
+ await testdriver.type("password123");
286
+ await testdriver.find("Login button").click();
287
+
288
+ // Steps from experiment file
289
+ const settingsBtn = await testdriver.find("Settings button");
290
+ await settingsBtn.click();
291
+
292
+ const result = await testdriver.assert("Settings panel is open");
293
+ expect(result).toBeTruthy();
294
+ });
295
+ });
296
+ ```
297
+
298
+ ## Recommended Development Workflow
299
+
300
+ 1. **Write a few steps** - Don't write the entire test at once
301
+ 2. **Run the test** - See what happens on the sandbox
302
+ 3. **Inspect outputs** - Use element properties to debug
303
+ 4. **Assert/expect** - Verify the step worked
304
+ 5. **Iterate** - Add more steps incrementally
305
+
306
+ ```javascript
307
+ // Development workflow example
308
+ it("should incrementally build test", async (context) => {
309
+ const testdriver = TestDriver(context, { newSandbox: true });
310
+ await testdriver.provision.chrome({ url: 'https://example.com' });
311
+
312
+ // Step 1: Find and inspect
313
+ const element = await testdriver.find("Some button");
314
+ console.log("Element found:", element.found());
315
+ console.log("Coordinates:", element.x, element.y);
316
+ console.log("Confidence:", element.confidence);
317
+
318
+ // Step 2: Interact
319
+ await element.click();
320
+
321
+ // Step 3: Assert and log
322
+ const result = await testdriver.assert("Something happened");
323
+ console.log("Assertion result:", result);
324
+ expect(result).toBeTruthy();
325
+
326
+ // Then add more steps...
327
+ });
328
+ ```
329
+
330
+ ## TestDriver Options Reference
331
+
332
+ ```javascript
333
+ const testdriver = TestDriver(context, {
334
+ newSandbox: true, // Create new sandbox (default: true)
335
+ headless: false, // Run in headless mode (default: false)
336
+ reconnect: false, // Reconnect to last sandbox (default: false)
337
+ keepAlive: 30000, // Keep sandbox alive after test (default: 30000ms / 30 seconds)
338
+ os: 'linux', // 'linux' | 'windows' (default: 'linux')
339
+ resolution: '1366x768', // Sandbox resolution
340
+ cache: true, // Enable element caching (default: true)
341
+ cacheKey: 'my-test', // Cache key for element finding
342
+ });
343
+ ```
344
+
345
+ ## Common Patterns
346
+
347
+ ### Typing in Fields
348
+ ```javascript
349
+ await testdriver.find("Email input").click();
350
+ await testdriver.type("user@example.com");
351
+ ```
352
+
353
+ ### Keyboard Shortcuts
354
+ ```javascript
355
+ await testdriver.pressKeys(["ctrl", "a"]); // Select all
356
+ await testdriver.pressKeys(["ctrl", "c"]); // Copy
357
+ await testdriver.pressKeys(["enter"]); // Submit
358
+ ```
359
+
360
+ ### Waiting and Polling
361
+ ```javascript
362
+ // Use timeout option to poll until element is found (retries every 5 seconds)
363
+ const element = await testdriver.find("Loading complete indicator", { timeout: 30000 });
364
+ await element.click();
365
+ ```
366
+
367
+ ### Scrolling
368
+ ```javascript
369
+ await testdriver.scroll("down");
370
+ await testdriver.scrollUntilText("Footer text");
371
+ await testdriver.scrollUntilImage("Product image at bottom");
372
+ ```
373
+
374
+ ### Executing Code in Sandbox
375
+ ```javascript
376
+ // JavaScript
377
+ const result = await testdriver.exec("js", "return document.title", 5000);
378
+
379
+ // Shell (Linux)
380
+ const output = await testdriver.exec("sh", "ls -la", 5000);
381
+
382
+ // PowerShell (Windows)
383
+ const date = await testdriver.exec("pwsh", "Get-Date", 5000);
384
+ ```
385
+
386
+ ## Tips for Agents
387
+
388
+ 1. **Always check `sdk.d.ts`** for method signatures and types
389
+ 2. **Look at test samples** in `node_modules/testdriverai/test` for working examples
390
+ 3. **Use reconnect pattern** when iterating on test steps
391
+ 4. **Log element properties** to understand what the AI sees
392
+ 5. **Use `assert()` with specific, descriptive natural language**
393
+ 6. **Start simple** - get one step working before adding more
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Initialize Sentry first, before any other modules
4
+ const sentry = require("../lib/sentry");
5
+
3
6
  // Set process priority if possible
4
7
  const os = require("os");
5
8
  try {
@@ -10,5 +13,10 @@ try {
10
13
  // Ignore if not permitted
11
14
  }
12
15
 
16
+ // Ensure Sentry flushes on exit
17
+ process.on("beforeExit", async () => {
18
+ await sentry.flush();
19
+ });
20
+
13
21
  // Run the CLI
14
22
  require("../interfaces/cli.js");
Binary file
Binary file
Binary file
@@ -307,9 +307,46 @@
307
307
  text-align: center;
308
308
  user-select: none;
309
309
  }
310
+
311
+ .close-button {
312
+ position: fixed;
313
+ top: 12px;
314
+ right: 12px;
315
+ z-index: 100;
316
+ background: rgba(0, 0, 0, 0.8);
317
+ border: 1px solid #444;
318
+ color: #fff;
319
+ padding: 8px 16px;
320
+ border-radius: 6px;
321
+ cursor: pointer;
322
+ font-size: 13px;
323
+ font-weight: 500;
324
+ pointer-events: auto;
325
+ transition: all 0.2s ease;
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 6px;
329
+ }
330
+
331
+ .close-button:hover {
332
+ background: rgba(220, 53, 69, 0.9);
333
+ border-color: #dc3545;
334
+ }
335
+
336
+ .close-button svg {
337
+ width: 14px;
338
+ height: 14px;
339
+ fill: currentColor;
340
+ }
310
341
  </style>
311
342
  </head>
312
343
  <body>
344
+ <!-- Close window button -->
345
+ <button class="close-button" onclick="window.close()" title="Close this window">
346
+ <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
347
+ Close
348
+ </button>
349
+
313
350
  <!-- Loading screen -->
314
351
  <div class="loading-screen" id="loading-screen">
315
352
  <div class="testdriver-logo">