testdriverai 7.8.0-test.3 → 7.8.0-test.30

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 (65) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/agent/index.js +6 -5
  3. package/agent/lib/commands.js +3 -2
  4. package/agent/lib/http.js +144 -0
  5. package/agent/lib/sandbox.js +117 -102
  6. package/agent/lib/sdk.js +4 -2
  7. package/agent/lib/system.js +25 -65
  8. package/ai/skills/testdriver-cache/SKILL.md +221 -0
  9. package/ai/skills/testdriver-captcha/SKILL.md +0 -1
  10. package/ai/skills/testdriver-errors/SKILL.md +246 -0
  11. package/ai/skills/testdriver-events/SKILL.md +356 -0
  12. package/ai/skills/testdriver-exec/SKILL.md +13 -24
  13. package/ai/skills/testdriver-mcp/SKILL.md +7 -0
  14. package/ai/skills/testdriver-provision/SKILL.md +331 -0
  15. package/ai/skills/testdriver-quickstart/SKILL.md +1 -1
  16. package/ai/skills/testdriver-redraw/SKILL.md +214 -0
  17. package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
  18. package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
  19. package/docs/changelog.mdx +155 -3
  20. package/docs/docs.json +44 -37
  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/captcha.mdx +0 -1
  27. package/docs/v7/copilot/auto-healing.mdx +265 -0
  28. package/docs/v7/copilot/creating-tests.mdx +156 -0
  29. package/docs/v7/copilot/github.mdx +143 -0
  30. package/docs/v7/copilot/running-tests.mdx +149 -0
  31. package/docs/v7/copilot/setup.mdx +143 -0
  32. package/docs/v7/enterprise.mdx +3 -110
  33. package/docs/v7/errors.mdx +248 -0
  34. package/docs/v7/events.mdx +358 -0
  35. package/docs/v7/examples/exec-output.mdx +85 -0
  36. package/docs/v7/examples/exec-pwsh.mdx +83 -0
  37. package/docs/v7/examples/focus-window.mdx +62 -0
  38. package/docs/v7/{cloud.mdx → hosted.mdx} +43 -5
  39. package/docs/v7/mcp.mdx +9 -0
  40. package/docs/v7/provision.mdx +333 -0
  41. package/docs/v7/quickstart.mdx +30 -2
  42. package/docs/v7/redraw.mdx +216 -0
  43. package/docs/v7/running-tests.mdx +1 -1
  44. package/docs/v7/screenshots.mdx +186 -0
  45. package/docs/v7/self-hosted.mdx +127 -44
  46. package/interfaces/logger.js +0 -12
  47. package/interfaces/vitest-plugin.mjs +3 -0
  48. package/lib/core/Dashcam.js +13 -16
  49. package/lib/environments.json +18 -0
  50. package/lib/resolve-channel.js +4 -3
  51. package/{examples → manual}/drag-and-drop.test.mjs +1 -1
  52. package/package.json +3 -3
  53. package/sdk.js +3 -3
  54. package/vitest.config.mjs +20 -32
  55. /package/{examples → manual}/flake-diffthreshold-001.test.mjs +0 -0
  56. /package/{examples → manual}/flake-diffthreshold-01.test.mjs +0 -0
  57. /package/{examples → manual}/flake-diffthreshold-05.test.mjs +0 -0
  58. /package/{examples → manual}/flake-noredraw-cache.test.mjs +0 -0
  59. /package/{examples → manual}/flake-noredraw-nocache.test.mjs +0 -0
  60. /package/{examples → manual}/flake-redraw-cache.test.mjs +0 -0
  61. /package/{examples → manual}/flake-redraw-nocache.test.mjs +0 -0
  62. /package/{examples → manual}/flake-rocket-match.test.mjs +0 -0
  63. /package/{examples → manual}/flake-shared.mjs +0 -0
  64. /package/{examples → manual}/no-provision.test.mjs +0 -0
  65. /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
+ ```
@@ -198,7 +198,7 @@ await testdriver.exec('pwsh', '.\\setup.ps1', 60000, true);
198
198
 
199
199
  ```javascript
200
200
  // Quick operations: 5000ms
201
- await testdriver.exec('js', 'document.title', 5000);
201
+ await testdriver.exec('sh', 'ls -la', 5000);
202
202
 
203
203
  // Installations: 30000-60000ms
204
204
  await testdriver.exec('pwsh', 'npm install -g package', 30000);
@@ -271,27 +271,20 @@ describe('Code Execution', () => {
271
271
  await testdriver.disconnect();
272
272
  });
273
273
 
274
- it('should execute JavaScript in browser', async () => {
275
- await testdriver.focusApplication('Google Chrome');
276
-
277
- // Get page info via JavaScript
278
- const title = await testdriver.exec('js', 'document.title', 5000);
279
- console.log('Page title:', title);
280
-
281
- // Manipulate DOM
282
- await testdriver.exec('js', `
283
- document.querySelector('#username').value = 'testuser';
284
- `, 5000);
274
+ it('should execute shell commands on Linux', async () => {
275
+ // List directory
276
+ const files = await testdriver.exec('sh', 'ls -la', 5000);
277
+ console.log('Files:', files);
285
278
 
286
- // Verify
287
- const value = await testdriver.exec('js', `
288
- document.querySelector('#username').value
289
- `, 5000);
279
+ // Create a file
280
+ await testdriver.exec('sh', 'echo "Hello World" > test.txt', 5000);
290
281
 
291
- expect(value).toBe('testuser');
282
+ // Read the file
283
+ const content = await testdriver.exec('sh', 'cat test.txt', 5000);
284
+ expect(content).toContain('Hello World');
292
285
  });
293
286
 
294
- it('should install and use tools', async () => {
287
+ it('should install and use tools on Windows', async () => {
295
288
  // Install tool
296
289
  await testdriver.exec('pwsh', 'npm install -g http-server', 30000, true);
297
290
 
@@ -313,10 +306,6 @@ describe('Code Execution', () => {
313
306
  `, 5000);
314
307
 
315
308
  await testdriver.focusApplication('Google Chrome');
316
-
317
- // Verify page loaded
318
- const content = await testdriver.exec('js', 'document.body.textContent', 5000);
319
- expect(content).toContain('Test Page');
320
309
  });
321
310
  });
322
311
  ```
@@ -324,5 +313,5 @@ describe('Code Execution', () => {
324
313
  ## Related Methods
325
314
 
326
315
  - [`focusApplication()`](/v7/focus-application) - Focus apps before exec
327
- - [`find()`](/v7/find) - Locate elements (alternative to DOM manipulation)
328
- - [`type()`](/v7/type) - Type text (alternative to JS form filling)
316
+ - [`find()`](/v7/find) - Locate elements visually
317
+ - [`type()`](/v7/type) - Type text into inputs
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: testdriver:mcp
3
+ description: mcp
4
+ ---
5
+ <!-- Generated from mcp.mdx. DO NOT EDIT. -->
6
+
7
+