testdriverai 7.8.0-test.7 → 7.8.0-test.71

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 (98) hide show
  1. package/agent/index.js +18 -5
  2. package/agent/lib/commands.js +3 -2
  3. package/agent/lib/http.js +162 -0
  4. package/agent/lib/logger.js +15 -0
  5. package/agent/lib/sandbox.js +554 -209
  6. package/agent/lib/sdk.js +5 -22
  7. package/agent/lib/system.js +25 -65
  8. package/ai/skills/testdriver-cache/SKILL.md +221 -0
  9. package/ai/skills/testdriver-errors/SKILL.md +246 -0
  10. package/ai/skills/testdriver-events/SKILL.md +356 -0
  11. package/ai/skills/testdriver-find/SKILL.md +14 -20
  12. package/ai/skills/testdriver-mcp/SKILL.md +7 -0
  13. package/ai/skills/testdriver-provision/SKILL.md +331 -0
  14. package/ai/skills/testdriver-redraw/SKILL.md +214 -0
  15. package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
  16. package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
  17. package/docs/_data/examples-manifest.json +46 -46
  18. package/docs/_scripts/extract-example-urls.js +67 -72
  19. package/docs/changelog.mdx +148 -8
  20. package/docs/docs.json +46 -38
  21. package/docs/images/content/vscode/v7-chat.png +0 -0
  22. package/docs/images/content/vscode/v7-choose-agent.png +0 -0
  23. package/docs/images/content/vscode/v7-full.png +0 -0
  24. package/docs/images/content/vscode/v7-onboarding.png +0 -0
  25. package/docs/v7/cache.mdx +223 -0
  26. package/docs/v7/copilot/auto-healing.mdx +265 -0
  27. package/docs/v7/copilot/creating-tests.mdx +156 -0
  28. package/docs/v7/copilot/github.mdx +143 -0
  29. package/docs/v7/copilot/running-tests.mdx +149 -0
  30. package/docs/v7/copilot/setup.mdx +143 -0
  31. package/docs/v7/enterprise.mdx +3 -110
  32. package/docs/v7/errors.mdx +248 -0
  33. package/docs/v7/events.mdx +358 -0
  34. package/docs/v7/examples/ai.mdx +1 -1
  35. package/docs/v7/examples/assert.mdx +1 -1
  36. package/docs/v7/examples/captcha-api.mdx +1 -1
  37. package/docs/v7/examples/chrome-extension.mdx +1 -1
  38. package/docs/v7/examples/drag-and-drop.mdx +1 -1
  39. package/docs/v7/examples/element-not-found.mdx +1 -1
  40. package/docs/v7/examples/exec-output.mdx +85 -0
  41. package/docs/v7/examples/exec-pwsh.mdx +83 -0
  42. package/docs/v7/examples/focus-window.mdx +62 -0
  43. package/docs/v7/examples/hover-image.mdx +1 -1
  44. package/docs/v7/examples/hover-text.mdx +1 -1
  45. package/docs/v7/examples/installer.mdx +1 -1
  46. package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
  47. package/docs/v7/examples/match-image.mdx +1 -1
  48. package/docs/v7/examples/press-keys.mdx +1 -1
  49. package/docs/v7/examples/scroll-keyboard.mdx +1 -1
  50. package/docs/v7/examples/scroll-until-image.mdx +1 -1
  51. package/docs/v7/examples/scroll-until-text.mdx +1 -1
  52. package/docs/v7/examples/scroll.mdx +1 -1
  53. package/docs/v7/examples/type.mdx +1 -1
  54. package/docs/v7/examples/windows-installer.mdx +1 -1
  55. package/docs/v7/find.mdx +14 -20
  56. package/docs/v7/{cloud.mdx → hosted.mdx} +43 -5
  57. package/docs/v7/mcp.mdx +9 -0
  58. package/docs/v7/provision.mdx +333 -0
  59. package/docs/v7/quickstart.mdx +30 -2
  60. package/docs/v7/redraw.mdx +216 -0
  61. package/docs/v7/running-tests.mdx +1 -1
  62. package/docs/v7/screenshots.mdx +186 -0
  63. package/docs/v7/self-hosted.mdx +127 -44
  64. package/docs/v7/test-results-json.mdx +258 -0
  65. package/examples/scroll-keyboard.test.mjs +1 -1
  66. package/examples/scroll.test.mjs +1 -12
  67. package/interfaces/logger.js +0 -12
  68. package/interfaces/vitest-plugin.mjs +170 -51
  69. package/lib/core/Dashcam.js +30 -23
  70. package/lib/environments.json +22 -0
  71. package/lib/github-comment.mjs +58 -40
  72. package/lib/init-project.js +5 -67
  73. package/lib/resolve-channel.js +42 -12
  74. package/lib/sentry.js +47 -23
  75. package/lib/vitest/hooks.mjs +63 -3
  76. package/{examples → manual}/drag-and-drop.test.mjs +1 -1
  77. package/manual/exec-stream-logs.test.mjs +25 -0
  78. package/mcp-server/dist/server.mjs +28 -8
  79. package/mcp-server/src/server.ts +31 -8
  80. package/package.json +4 -3
  81. package/sdk.d.ts +4 -0
  82. package/sdk.js +45 -15
  83. package/setup/aws/install-dev-runner.sh +79 -0
  84. package/setup/aws/spawn-runner.sh +165 -0
  85. package/test-sentry-span.js +35 -0
  86. package/vitest.config.mjs +22 -34
  87. package/vitest.runner.config.mjs +33 -0
  88. /package/{examples → manual}/flake-diffthreshold-001.test.mjs +0 -0
  89. /package/{examples → manual}/flake-diffthreshold-01.test.mjs +0 -0
  90. /package/{examples → manual}/flake-diffthreshold-05.test.mjs +0 -0
  91. /package/{examples → manual}/flake-noredraw-cache.test.mjs +0 -0
  92. /package/{examples → manual}/flake-noredraw-nocache.test.mjs +0 -0
  93. /package/{examples → manual}/flake-redraw-cache.test.mjs +0 -0
  94. /package/{examples → manual}/flake-redraw-nocache.test.mjs +0 -0
  95. /package/{examples → manual}/flake-rocket-match.test.mjs +0 -0
  96. /package/{examples → manual}/flake-shared.mjs +0 -0
  97. /package/{examples → manual}/no-provision.test.mjs +0 -0
  98. /package/{examples → manual}/scroll-until-text.test.mjs +0 -0
@@ -0,0 +1,356 @@
1
+ ---
2
+ name: testdriver:events
3
+ description: Listen to SDK lifecycle events with wildcard support
4
+ ---
5
+ <!-- Generated from events.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ TestDriver uses [EventEmitter2](https://github.com/EventEmitter2/EventEmitter2) for its event system. Events use a colon-delimited namespace pattern and support wildcard listeners.
10
+
11
+ Access the emitter through `testdriver.emitter`:
12
+
13
+ ```javascript
14
+ testdriver.emitter.on('command:start', (data) => {
15
+ console.log(`Running: ${data.command}`);
16
+ });
17
+ ```
18
+
19
+ ### Configuration
20
+
21
+ The internal emitter is created with:
22
+
23
+ ```javascript
24
+ new EventEmitter2({
25
+ wildcard: true,
26
+ delimiter: ':',
27
+ maxListeners: 20,
28
+ verboseMemoryLeak: false,
29
+ ignoreErrors: false,
30
+ });
31
+ ```
32
+
33
+ ### Wildcard Listeners
34
+
35
+ Use `*` to match a single level or `**` to match multiple levels:
36
+
37
+ ```javascript
38
+ // Match all log events
39
+ testdriver.emitter.on('log:*', (message) => {
40
+ console.log(message);
41
+ });
42
+
43
+ // Match all events in any namespace
44
+ testdriver.emitter.on('**', (...args) => {
45
+ console.log('Event:', this.event, args);
46
+ });
47
+ ```
48
+
49
+ ## Event Reference
50
+
51
+ ### Command Events
52
+
53
+ Emitted during the execution of SDK commands (`click`, `type`, `find`, etc.).
54
+
55
+ | Event | Payload |
56
+ |---|---|
57
+ | `command:start` | `{ command, depth, data, timestamp, sourcePosition }` |
58
+ | `command:success` | `{ command, depth, data, duration, response, timestamp, sourcePosition }` |
59
+ | `command:error` | `{ command, depth, data, error, duration, timestamp, sourcePosition }` |
60
+ | `command:status` | `{ command, status: "executing", data, depth, timestamp }` |
61
+ | `command:progress` | `{ command, status: "completed", timing, data, depth, timestamp }` |
62
+
63
+ ```javascript
64
+ testdriver.emitter.on('command:start', ({ command, data }) => {
65
+ console.log(`Starting ${command}`, data);
66
+ });
67
+
68
+ testdriver.emitter.on('command:error', ({ command, error, duration }) => {
69
+ console.error(`${command} failed after ${duration}ms: ${error}`);
70
+ });
71
+ ```
72
+
73
+ ### Step Events
74
+
75
+ Emitted for each AI reasoning step within a command.
76
+
77
+ | Event | Payload |
78
+ |---|---|
79
+ | `step:start` | `{ stepIndex, prompt, commandCount, timestamp, sourcePosition }` |
80
+ | `step:success` | `{ stepIndex, prompt, commandCount, duration, timestamp, sourcePosition }` |
81
+ | `step:error` | `{ stepIndex, prompt, error, duration?, timestamp, sourcePosition? }` |
82
+
83
+ ```javascript
84
+ testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
85
+ console.log(`Step ${stepIndex}: ${prompt}`);
86
+ });
87
+ ```
88
+
89
+ ### Test Events
90
+
91
+ Emitted when a test file execution starts.
92
+
93
+ | Event | Payload |
94
+ |---|---|
95
+ | `test:start` | `{ filePath, timestamp }` |
96
+ | `test:success` | *Emitted on test completion* |
97
+ | `test:error` | *Emitted on test failure* |
98
+
99
+ ### Log Events
100
+
101
+ Emitted for all log output from the SDK.
102
+
103
+ | Event | Payload |
104
+ |---|---|
105
+ | `log:log` | `(message: string)` — general log message |
106
+ | `log:warn` | `(message: string)` — warning message |
107
+ | `log:debug` | `(message: string)` — debug output (only when `VERBOSE`/`DEBUG`/`TD_DEBUG` env set) |
108
+ | `log:info` | `(message: string)` — informational message |
109
+ | `log:error` | `(message: string)` — error message |
110
+ | `log:narration` | `(message: string, overwrite?: boolean)` — in-place status line |
111
+ | `log:markdown` | `(markdown: string)` — full static markdown content |
112
+ | `log:markdown:start` | `(streamId: string)` — begin streaming markdown |
113
+ | `log:markdown:chunk` | `(streamId: string, chunk: string)` — incremental chunk |
114
+ | `log:markdown:end` | `(streamId: string)` — end streaming markdown |
115
+
116
+ ```javascript
117
+ // Capture all logs
118
+ testdriver.emitter.on('log:*', function (message) {
119
+ console.log(`[${this.event}]`, message);
120
+ });
121
+ ```
122
+
123
+ ### Screen Capture Events
124
+
125
+ Emitted during screenshot capture.
126
+
127
+ | Event | Payload |
128
+ |---|---|
129
+ | `screen-capture:start` | `{ scale, silent, display }` |
130
+ | `screen-capture:end` | `{ scale, silent, display }` |
131
+ | `screen-capture:error` | `{ error, scale, silent, display }` |
132
+
133
+ ### Sandbox Events
134
+
135
+ Emitted for sandbox WebSocket lifecycle and communication.
136
+
137
+ | Event | Payload |
138
+ |---|---|
139
+ | `sandbox:connected` | *No payload* — WebSocket connection established |
140
+ | `sandbox:authenticated` | `{ traceId }` — authentication successful |
141
+ | `sandbox:error` | `(err: Error \| string)` — connection or sandbox error |
142
+ | `sandbox:sent` | `(message: object)` — WebSocket message sent |
143
+ | `sandbox:received` | *No payload* — successful message reply received |
144
+ | `sandbox:progress` | `{ step, message }` — sandbox setup progress |
145
+
146
+ ```javascript
147
+ testdriver.emitter.on('sandbox:connected', () => {
148
+ console.log('Connected to sandbox');
149
+ });
150
+
151
+ testdriver.emitter.on('sandbox:progress', ({ step, message }) => {
152
+ console.log(`Sandbox: [${step}] ${message}`);
153
+ });
154
+ ```
155
+
156
+ ### Redraw Events
157
+
158
+ Emitted during screen stability detection. See [Redraw](/v7/redraw) for more details.
159
+
160
+ | Event | Payload |
161
+ |---|---|
162
+ | `redraw:status` | `{ redraw: { enabled, settled, hasChangedFromInitial, consecutiveFramesStable, diffFromInitial, diffFromLast, text }, network: { enabled, settled, rxBytes, txBytes, text }, timeout: { isTimeout, elapsed, max, text } }` |
163
+ | `redraw:complete` | `{ screenSettled, hasChangedFromInitial, consecutiveFramesStable, networkSettled, isTimeout, timeElapsed }` |
164
+
165
+ ```javascript
166
+ testdriver.emitter.on('redraw:complete', (result) => {
167
+ if (result.isTimeout) {
168
+ console.warn('Redraw timed out after', result.timeElapsed, 'ms');
169
+ }
170
+ });
171
+ ```
172
+
173
+ ### File Events
174
+
175
+ Emitted during file load/save operations in the agent.
176
+
177
+ | Event | Payload |
178
+ |---|---|
179
+ | `file:start` | `{ operation: "load" \| "save" \| "run", filePath, timestamp }` |
180
+ | `file:stop` | `{ operation, filePath, duration, success, sourceMap?, reason?, timestamp }` |
181
+ | `file:load` | `{ filePath, size, timestamp }` |
182
+ | `file:save` | `{ filePath, size, timestamp }` |
183
+ | `file:diff` | `{ filePath, diff: { patches, sourceMaps, summary: { additions, deletions, modifications } }, timestamp }` |
184
+ | `file:error` | `{ operation, filePath, error, duration?, timestamp }` |
185
+
186
+ ### Error Events
187
+
188
+ Emitted for errors at various severity levels.
189
+
190
+ | Event | Payload |
191
+ |---|---|
192
+ | `error:fatal` | `(error: string \| Error)` — terminates the process |
193
+ | `error:general` | `(message: string)` — non-fatal error |
194
+ | `error:sandbox` | `(err: Error \| string)` — sandbox/WebSocket error |
195
+
196
+ ```javascript
197
+ testdriver.emitter.on('error:*', function (err) {
198
+ console.error(`[${this.event}]`, err);
199
+ });
200
+ ```
201
+
202
+ ### SDK Events
203
+
204
+ Emitted for API request lifecycle.
205
+
206
+ | Event | Payload |
207
+ |---|---|
208
+ | `sdk:request` | `{ path }` — outgoing API request |
209
+ | `sdk:response` | `{ path }` — API response received |
210
+ | `sdk:retry` | `{ path, attempt, error, delayMs }` — request retry |
211
+
212
+ ### Other Events
213
+
214
+ | Event | Payload |
215
+ |---|---|
216
+ | `exit` | `(exitCode: number)` — `0` for success, `1` for failure |
217
+ | `status` | `(message: string)` — general status updates |
218
+ | `mouse-click` | `{ x, y, button, click, double }` — mouse click performed |
219
+ | `terminal:stdout` | Terminal stdout output |
220
+ | `terminal:stderr` | Terminal stderr output |
221
+
222
+ ## Practical Examples
223
+
224
+ ### Custom Test Reporter
225
+
226
+ ```javascript
227
+ const results = [];
228
+
229
+ testdriver.emitter.on('command:success', ({ command, duration }) => {
230
+ results.push({ command, duration, status: 'pass' });
231
+ });
232
+
233
+ testdriver.emitter.on('command:error', ({ command, duration, error }) => {
234
+ results.push({ command, duration, status: 'fail', error });
235
+ });
236
+
237
+ // After test completes
238
+ afterAll(() => {
239
+ console.table(results);
240
+ });
241
+ ```
242
+
243
+ ### Progress Monitoring
244
+
245
+ ```javascript
246
+ testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
247
+ process.stdout.write(`\r Step ${stepIndex}: ${prompt}`);
248
+ });
249
+
250
+ testdriver.emitter.on('command:progress', ({ command, timing }) => {
251
+ process.stdout.write(`\r ${command} completed in ${timing}ms`);
252
+ });
253
+ ```
254
+
255
+ ### Debug Logging
256
+
257
+ ```javascript
258
+ // Log every event (verbose)
259
+ testdriver.emitter.on('**', function (...args) {
260
+ console.debug(`[EVENT] ${this.event}`, ...args);
261
+ });
262
+ ```
263
+
264
+ ## Types
265
+
266
+ ```typescript
267
+ interface CommandStartEvent {
268
+ command: string;
269
+ depth: number;
270
+ data: Record<string, any>;
271
+ timestamp: number;
272
+ sourcePosition: SourcePosition;
273
+ }
274
+
275
+ interface CommandSuccessEvent {
276
+ command: string;
277
+ depth: number;
278
+ data: Record<string, any>;
279
+ duration: number;
280
+ response: any;
281
+ timestamp: number;
282
+ sourcePosition: SourcePosition;
283
+ }
284
+
285
+ interface CommandErrorEvent {
286
+ command: string;
287
+ depth: number;
288
+ data: Record<string, any>;
289
+ error: string;
290
+ duration: number;
291
+ timestamp: number;
292
+ sourcePosition: SourcePosition;
293
+ }
294
+
295
+ interface StepStartEvent {
296
+ stepIndex: number;
297
+ prompt: string;
298
+ commandCount: number;
299
+ timestamp: number;
300
+ sourcePosition: SourcePosition;
301
+ }
302
+
303
+ interface StepSuccessEvent {
304
+ stepIndex: number;
305
+ prompt: string;
306
+ commandCount: number;
307
+ duration: number;
308
+ timestamp: number;
309
+ sourcePosition: SourcePosition;
310
+ }
311
+
312
+ interface RedrawStatusEvent {
313
+ redraw: {
314
+ enabled: boolean;
315
+ settled: boolean;
316
+ hasChangedFromInitial: boolean;
317
+ consecutiveFramesStable: number;
318
+ diffFromInitial: number;
319
+ diffFromLast: number;
320
+ text: string;
321
+ };
322
+ network: {
323
+ enabled: boolean;
324
+ settled: boolean;
325
+ rxBytes: number;
326
+ txBytes: number;
327
+ text: string;
328
+ };
329
+ timeout: {
330
+ isTimeout: boolean;
331
+ elapsed: number;
332
+ max: number;
333
+ text: string;
334
+ };
335
+ }
336
+
337
+ interface RedrawCompleteEvent {
338
+ screenSettled: boolean;
339
+ hasChangedFromInitial: boolean;
340
+ consecutiveFramesStable: number;
341
+ networkSettled: boolean;
342
+ isTimeout: boolean;
343
+ timeElapsed: number;
344
+ }
345
+
346
+ interface SandboxProgressEvent {
347
+ step: string;
348
+ message: string;
349
+ }
350
+
351
+ interface SourcePosition {
352
+ file: string;
353
+ line: number;
354
+ column: number;
355
+ }
356
+ ```
@@ -49,8 +49,8 @@ const element = await testdriver.find(description, options)
49
49
  - `"any"` — No wrapping, uses the description as-is (default behavior)
50
50
  </ParamField>
51
51
 
52
- <ParamField path="zoom" type="boolean" default={false}>
53
- Enable two-phase zoom mode for better precision in crowded UIs with many similar elements.
52
+ <ParamField path="zoom" type="boolean" default={true}>
53
+ Two-phase zoom mode for better precision in crowded UIs with many similar elements. Enabled by default.
54
54
  </ParamField>
55
55
 
56
56
  <ParamField path="ai" type="object">
@@ -332,14 +332,19 @@ The `timeout` option:
332
332
  - Returns the element (check `element.found()` if not throwing on failure)
333
333
  - Set to `0` to disable polling and make a single attempt
334
334
 
335
- ## Zoom Mode for Crowded UIs
335
+ ## Zoom Mode
336
336
 
337
- When dealing with many similar icons or elements clustered together (like browser toolbars), enable `zoom` mode for better precision:
337
+ Zoom mode is **enabled by default**. It uses a two-phase approach for better precision when locating elements, especially in crowded UIs with many similar elements.
338
+
339
+ To disable zoom for a specific find call, pass `zoom: false`:
338
340
 
339
341
  ```javascript
340
- // Enable zoom for better precision in crowded UIs
341
- const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar', { zoom: true });
342
+ // Zoom is on by default no option needed
343
+ const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar');
342
344
  await extensionsBtn.click();
345
+
346
+ // Disable zoom for a specific call if needed
347
+ const largeButton = await testdriver.find('big hero button', { zoom: false });
343
348
  ```
344
349
 
345
350
  ### How Zoom Mode Works
@@ -352,22 +357,11 @@ await extensionsBtn.click();
352
357
  This two-phase approach gives the AI a higher-resolution view of the target area, improving accuracy when multiple similar elements are close together.
353
358
 
354
359
  <Tip>
355
- Use `zoom: true` when:
356
- - Clicking small icons in toolbars
357
- - Selecting from a grid of similar items
358
- - Targeting elements in dense UI areas
359
- - The default locate is clicking the wrong similar element
360
- - You get an AI verification rejection like "The crosshair is located in the empty space of the browser's tab bar/title bar area" — this means the initial locate was imprecise and zoom will help the AI pinpoint the correct element
360
+ You may want to disable zoom with `zoom: false` when:
361
+ - Targeting large, isolated elements where the extra precision isn't needed
362
+ - You want to speed up find calls in simple UIs
361
363
  </Tip>
362
364
 
363
- ```javascript
364
- // Without zoom - may click wrong icon in toolbar
365
- const icon = await testdriver.find('settings icon');
366
-
367
- // With zoom - better precision for crowded areas
368
- const icon = await testdriver.find('settings icon', { zoom: true });
369
- ```
370
-
371
365
  ## Cache Options
372
366
 
373
367
  Control caching behavior to optimize performance, especially when using dynamic variables in prompts.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: testdriver:mcp
3
+ description: mcp
4
+ ---
5
+ <!-- Generated from mcp.mdx. DO NOT EDIT. -->
6
+
7
+