testdriverai 7.9.9-test → 7.9.11-test

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 (56) hide show
  1. package/agent/lib/sandbox.js +6 -6
  2. package/ai/agents/testdriver.md +3 -7
  3. package/ai/skills/testdriver-find/SKILL.md +11 -11
  4. package/ai/skills/testdriver-performing-actions/SKILL.md +0 -1
  5. package/ai/skills/testdriver-screenshot/SKILL.md +1 -1
  6. package/ai/skills/testdriver-scroll/SKILL.md +20 -150
  7. package/ai/skills/testdriver-test-writer/SKILL.md +0 -2
  8. package/ai/skills/testdriver-testdriver/SKILL.md +3 -7
  9. package/docs/_data/examples-manifest.json +42 -42
  10. package/docs/snippets/tests/scroll-yaml.mdx +2 -2
  11. package/docs/v6/commands/scroll-until-image.mdx +1 -1
  12. package/docs/v6/commands/scroll-until-text.mdx +2 -2
  13. package/docs/v6/commands/scroll.mdx +2 -2
  14. package/docs/v7/_drafts/agents.mdx +0 -4
  15. package/docs/v7/_drafts/commands/scroll-until-image.mdx +1 -1
  16. package/docs/v7/_drafts/commands/scroll-until-text.mdx +2 -2
  17. package/docs/v7/_drafts/commands/scroll.mdx +1 -1
  18. package/docs/v7/_drafts/readme.mdx +0 -1
  19. package/docs/v7/aws-setup.mdx +1 -1
  20. package/docs/v7/ci-cd.mdx +1 -1
  21. package/docs/v7/client.mdx +5 -5
  22. package/docs/v7/customizing-devices.mdx +1 -1
  23. package/docs/v7/device-config.mdx +5 -5
  24. package/docs/v7/examples/ai.mdx +1 -1
  25. package/docs/v7/examples/assert.mdx +1 -1
  26. package/docs/v7/examples/chrome-extension.mdx +1 -1
  27. package/docs/v7/examples/element-not-found.mdx +1 -1
  28. package/docs/v7/examples/exec-output.mdx +1 -1
  29. package/docs/v7/examples/exec-pwsh.mdx +1 -1
  30. package/docs/v7/examples/findall-coffee-icons.mdx +1 -1
  31. package/docs/v7/examples/focus-window.mdx +1 -1
  32. package/docs/v7/examples/hover-image.mdx +1 -1
  33. package/docs/v7/examples/hover-text-with-description.mdx +1 -1
  34. package/docs/v7/examples/hover-text.mdx +1 -1
  35. package/docs/v7/examples/installer.mdx +1 -1
  36. package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
  37. package/docs/v7/examples/parse.mdx +1 -1
  38. package/docs/v7/examples/press-keys.mdx +1 -1
  39. package/docs/v7/examples/prompt.mdx +1 -1
  40. package/docs/v7/examples/scroll-keyboard.mdx +3 -3
  41. package/docs/v7/examples/scroll-until-image.mdx +3 -3
  42. package/docs/v7/examples/scroll.mdx +2 -2
  43. package/docs/v7/examples/type.mdx +1 -1
  44. package/docs/v7/examples/windows-installer.mdx +1 -1
  45. package/docs/v7/find.mdx +11 -11
  46. package/docs/v7/hosted.mdx +1 -1
  47. package/docs/v7/parse.mdx +1 -1
  48. package/docs/v7/performing-actions.mdx +0 -1
  49. package/docs/v7/reusable-code.mdx +3 -3
  50. package/docs/v7/running-tests.mdx +1 -1
  51. package/docs/v7/screenshot.mdx +5 -5
  52. package/docs/v7/scroll.mdx +30 -160
  53. package/lib/github-comment.mjs +11 -5
  54. package/package.json +1 -1
  55. package/sdk.d.ts +2 -2
  56. package/sdk.js +7 -3
@@ -27,21 +27,21 @@ Scroll the page or active element in any direction using mouse wheel or keyboard
27
27
  ## Syntax
28
28
 
29
29
  ```javascript
30
- await testdriver.scroll(direction, amount, method)
30
+ await testdriver.scroll(direction, options)
31
31
  ```
32
32
 
33
33
  ## Parameters
34
34
 
35
35
  <ParamField path="direction" type="string" default="down">
36
- Direction to scroll: `'up'`, `'down'`, `'left'`, `'right'`
36
+ Direction to scroll: `'up'`, `'down'`
37
37
  </ParamField>
38
38
 
39
- <ParamField path="amount" type="number" default="300">
40
- Amount to scroll in pixels
41
- </ParamField>
42
-
43
- <ParamField path="method" type="string" default="mouse">
44
- Scroll method: `'mouse'` or `'keyboard'`
39
+ <ParamField path="options" type="object">
40
+ <Expandable title="properties">
41
+ <ParamField path="amount" type="number" default="300">
42
+ Amount to scroll in pixels
43
+ </ParamField>
44
+ </Expandable>
45
45
  </ParamField>
46
46
 
47
47
  ## Returns
@@ -56,95 +56,34 @@ await testdriver.scroll(direction, amount, method)
56
56
  // Scroll down (default)
57
57
  await testdriver.scroll();
58
58
 
59
- // Scroll down 500 pixels
60
- await testdriver.scroll('down', 500);
59
+ // Scroll down 5 clicks
60
+ await testdriver.scroll('down', { amount: 5 });
61
61
 
62
62
  // Scroll up
63
63
  await testdriver.scroll('up');
64
64
 
65
- // Scroll up 200 pixels
66
- await testdriver.scroll('up', 200);
65
+ // Scroll up 2 clicks
66
+ await testdriver.scroll('up', { amount: 2 });
67
67
  ```
68
68
 
69
69
  ### Horizontal Scrolling
70
70
 
71
71
  ```javascript
72
72
  // Scroll right
73
- await testdriver.scroll('right', 300);
73
+ await testdriver.scroll('right', { amount: 3 });
74
74
 
75
75
  // Scroll left
76
- await testdriver.scroll('left', 300);
76
+ await testdriver.scroll('left', { amount: 3 });
77
77
  ```
78
78
 
79
79
  ### Scroll Methods
80
80
 
81
81
  ```javascript
82
- // Mouse wheel scroll (smooth, pixel-precise)
83
- await testdriver.scroll('down', 300, 'mouse');
84
-
85
- // Keyboard scroll (uses Page Down/Up, more compatible)
86
- await testdriver.scroll('down', 300, 'keyboard');
87
- ```
88
-
89
- ## Scroll Until Found
90
-
91
- ### scrollUntilText()
92
-
93
- Scroll until specific text appears on screen.
94
-
95
- ```javascript
96
- await testdriver.scrollUntilText(text, direction, maxDistance, textMatchMethod, method, invert)
97
- ```
98
-
99
- **Parameters:**
100
- - `text` (string) - Text to find
101
- - `direction` (string) - Scroll direction (default: `'down'`)
102
- - `maxDistance` (number) - Max pixels to scroll (default: 10000)
103
- - `textMatchMethod` (string) - `'turbo'` or `'ai'` (default: `'turbo'`)
104
- - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
105
- - `invert` (boolean) - Scroll until text disappears (default: false)
106
-
107
- **Examples:**
108
- ```javascript
109
- // Scroll down until "Contact Us" appears
110
- await testdriver.scrollUntilText('Contact Us');
111
-
112
- // Scroll up to find text
113
- await testdriver.scrollUntilText('Header', 'up');
114
-
115
- // Scroll until text disappears
116
- await testdriver.scrollUntilText('Loading...', 'down', 5000, 'turbo', 'keyboard', true);
82
+ // Mouse wheel scroll (default)
83
+ await testdriver.scroll('down', { amount: 3 });
117
84
 
118
- // Use AI matching for fuzzy text
119
- await testdriver.scrollUntilText('footer content', 'down', 10000, 'ai');
120
- ```
121
-
122
- ### scrollUntilImage()
123
-
124
- Scroll until a visual element appears.
125
-
126
- ```javascript
127
- await testdriver.scrollUntilImage(description, direction, maxDistance, method, path, invert)
128
- ```
129
-
130
- **Parameters:**
131
- - `description` (string) - Description of the image/element
132
- - `direction` (string) - Scroll direction (default: `'down'`)
133
- - `maxDistance` (number) - Max pixels to scroll (default: 10000)
134
- - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
135
- - `path` (string | null) - Path to image template (optional)
136
- - `invert` (boolean) - Scroll until image disappears (default: false)
137
-
138
- **Examples:**
139
- ```javascript
140
- // Scroll until visual element appears
141
- await testdriver.scrollUntilImage('red subscribe button');
142
-
143
- // Scroll using image template
144
- await testdriver.scrollUntilImage('', 'down', 10000, 'keyboard', './footer-logo.png');
145
-
146
- // Scroll until image disappears
147
- await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', null, true);
85
+ // For keyboard-based scrolling, use pressKeys instead
86
+ await testdriver.pressKeys(['pagedown']);
148
87
  ```
149
88
 
150
89
  ## Best Practices
@@ -163,7 +102,7 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
163
102
  // await testdriver.find('page background').click();
164
103
 
165
104
  // Now scroll will work properly
166
- await testdriver.scroll('down', 300);
105
+ await testdriver.scroll('down');
167
106
 
168
107
  // If scroll still doesn't work, use Page Down directly
169
108
  // await testdriver.pressKeys(['pagedown']);
@@ -171,84 +110,31 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
171
110
  </Check>
172
111
 
173
112
  <Check>
174
- **Choose the right scroll method**
175
-
176
- ```javascript
177
- // For web pages, mouse scroll is usually smoother
178
- await testdriver.scroll('down', 300, 'mouse');
179
-
180
- // For desktop apps or when mouse doesn't work
181
- await testdriver.scroll('down', 300, 'keyboard');
182
- ```
183
- </Check>
184
-
185
- <Check>
186
- **Use scrollUntil for dynamic content**
113
+ **Control scroll distance with the options object**
187
114
 
188
115
  ```javascript
189
- // Instead of guessing scroll amount
190
- await testdriver.scrollUntilText('Load More button');
116
+ // For web pages, mouse scroll works well
117
+ await testdriver.scroll('down', { amount: 3 });
191
118
 
192
- const loadMoreBtn = await testdriver.find('Load More button');
193
- await loadMoreBtn.click();
194
- ```
195
- </Check>
196
-
197
- <Check>
198
- **Set reasonable max distance**
199
-
200
- ```javascript
201
- // Avoid infinite scrolling
202
- await testdriver.scrollUntilText('Footer', 'down', 5000); // Max 5000px
119
+ // For desktop apps or when mouse doesn't work, use keyboard
120
+ await testdriver.pressKeys(['pagedown']);
203
121
  ```
204
122
  </Check>
205
123
 
206
124
  <Warning>
207
125
  **Keyboard scroll uses Page Down/Up**
208
126
 
209
- Keyboard scrolling typically moves by one "page" at a time, which may be more than the specified pixel amount. It's more compatible but less precise than mouse scrolling.
127
+ Keyboard scrolling typically moves by one "page" at a time, which may be more than the specified click amount. It's more compatible but less precise than mouse scrolling.
210
128
  </Warning>
211
129
 
212
130
  ## Use Cases
213
131
 
214
132
  <AccordionGroup>
215
- <Accordion title="Navigate to Footer">
216
- ```javascript
217
- // Scroll to bottom of page
218
- await testdriver.scrollUntilText('Contact Us');
219
-
220
- const contactLink = await testdriver.find('Contact Us link');
221
- await contactLink.click();
222
- ```
223
- </Accordion>
224
-
225
- <Accordion title="Load More Results">
226
- ```javascript
227
- // Scroll to load more button
228
- await testdriver.scrollUntilText('Load More');
229
-
230
- const loadBtn = await testdriver.find('Load More button');
231
- await loadBtn.click();
232
-
233
- await new Promise(r => setTimeout(r, 2000));
234
- ```
235
- </Accordion>
236
-
237
- <Accordion title="Find Element in Long List">
238
- ```javascript
239
- // Scroll through list to find item
240
- await testdriver.scrollUntilText('Product #42');
241
-
242
- const product = await testdriver.find('Product #42');
243
- await product.click();
244
- ```
245
- </Accordion>
246
-
247
133
  <Accordion title="Infinite Scroll">
248
134
  ```javascript
249
135
  // Scroll multiple times for infinite scroll
250
136
  for (let i = 0; i < 5; i++) {
251
- await testdriver.scroll('down', 500);
137
+ await testdriver.scroll('down', { amount: 5 });
252
138
  await new Promise(r => setTimeout(r, 1000)); // Wait for load
253
139
  }
254
140
  ```
@@ -257,7 +143,7 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
257
143
  <Accordion title="Horizontal Gallery">
258
144
  ```javascript
259
145
  // Navigate horizontal carousel
260
- await testdriver.scroll('right', 300);
146
+ await testdriver.scroll('right', { amount: 3 });
261
147
  await new Promise(r => setTimeout(r, 500));
262
148
 
263
149
  const nextImage = await testdriver.find('next image in carousel');
@@ -288,8 +174,8 @@ describe('Scrolling', () => {
288
174
  it('should scroll to find elements', async () => {
289
175
  await testdriver.focusApplication('Google Chrome');
290
176
 
291
- // Scroll to footer
292
- await testdriver.scrollUntilText('Contact Information');
177
+ // Scroll down the page
178
+ await testdriver.scroll('down', { amount: 5 });
293
179
 
294
180
  // Click footer link
295
181
  const privacyLink = await testdriver.find('Privacy Policy link');
@@ -303,29 +189,13 @@ describe('Scrolling', () => {
303
189
 
304
190
  // Scroll multiple times to load content
305
191
  for (let i = 0; i < 3; i++) {
306
- await testdriver.scroll('down', 500);
192
+ await testdriver.scroll('down', { amount: 5 });
307
193
  await new Promise(r => setTimeout(r, 1500)); // Wait for load
308
194
  }
309
195
 
310
196
  // Verify content loaded
311
197
  await testdriver.assert('more than 10 items are visible');
312
198
  });
313
-
314
- it('should scroll until loading completes', async () => {
315
- // Scroll until loading spinner disappears
316
- await testdriver.scrollUntilImage(
317
- 'loading spinner',
318
- 'down',
319
- 5000,
320
- 'keyboard',
321
- null,
322
- true // invert - wait for it to disappear
323
- );
324
-
325
- // Now interact with loaded content
326
- const firstResult = await testdriver.find('first search result');
327
- await firstResult.click();
328
- });
329
199
  });
330
200
  ```
331
201
 
@@ -8,7 +8,13 @@
8
8
  * - Links to test runs
9
9
  */
10
10
 
11
- import { Octokit } from '@octokit/rest';
11
+ /**
12
+ * Lazily load Octokit to avoid hard failure when @octokit/rest is not installed
13
+ */
14
+ async function getOctokit(token) {
15
+ const { Octokit } = await import('@octokit/rest');
16
+ return new Octokit({ auth: token });
17
+ }
12
18
 
13
19
  /**
14
20
  * Format test duration in human-readable format
@@ -334,7 +340,7 @@ export async function postGitHubComment(options) {
334
340
  throw new Error('Either prNumber or commitSha must be provided');
335
341
  }
336
342
 
337
- const octokit = new Octokit({ auth: token });
343
+ const octokit = await getOctokit(token);
338
344
 
339
345
  if (prNumber) {
340
346
  // Comment on PR
@@ -374,7 +380,7 @@ export async function updateGitHubComment(options) {
374
380
  throw new Error('Token, owner, repo, and commentId are required');
375
381
  }
376
382
 
377
- const octokit = new Octokit({ auth: token });
383
+ const octokit = await getOctokit(token);
378
384
 
379
385
  const response = await octokit.rest.issues.updateComment({
380
386
  owner,
@@ -402,7 +408,7 @@ export async function findExistingComment(options) {
402
408
  return null;
403
409
  }
404
410
 
405
- const octokit = new Octokit({ auth: token });
411
+ const octokit = await getOctokit(token);
406
412
 
407
413
  const comments = await octokit.rest.issues.listComments({
408
414
  owner,
@@ -435,7 +441,7 @@ export async function postOrUpdateTestResults(testRunData, testCases, githubOpti
435
441
 
436
442
  if (existingComment) {
437
443
  // Delete the old comment
438
- const octokit = new Octokit({ auth: githubOptions.token });
444
+ const octokit = await getOctokit(githubOptions.token);
439
445
  await octokit.rest.issues.deleteComment({
440
446
  owner: githubOptions.owner,
441
447
  repo: githubOptions.repo,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.9.9-test",
3
+ "version": "7.9.11-test",
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
@@ -282,7 +282,7 @@ export interface TestDriverOptions {
282
282
  /** Enable/disable Dashcam video recording (default: true) */
283
283
  dashcam?: boolean;
284
284
  /**
285
- * Enable automatic screenshots before and after each command (default: true)
285
+ * Enable automatic screenshots before and after each command (default: false)
286
286
  * Screenshots are saved to .testdriver/screenshots/<test>/ with descriptive filenames
287
287
  * Format: <seq>-<action>-<phase>-L<line>-<description>.png
288
288
  * Example: 001-click-before-L42-submit-button.png
@@ -1086,7 +1086,7 @@ export default class TestDriverSDK {
1086
1086
  find(description: string, cacheThreshold?: number): ChainableElementPromise;
1087
1087
  find(
1088
1088
  description: string,
1089
- options?: { cacheThreshold?: number; cacheKey?: string; timeout?: number; confidence?: number; type?: "text" | "image" | "ui" | "any"; ai?: AIConfig; cache?: { thresholds?: { screen?: number; element?: number } } },
1089
+ options?: { cacheThreshold?: number; cacheKey?: string; timeout?: number; confidence?: number; type?: "text" | "image" | "ui" | "any"; zoom?: boolean | number; verify?: boolean; ai?: AIConfig; cache?: { thresholds?: { screen?: number; element?: number } } },
1090
1090
  ): ChainableElementPromise;
1091
1091
 
1092
1092
  /**
package/sdk.js CHANGED
@@ -481,7 +481,8 @@ class Element {
481
481
  let cacheKey = null;
482
482
  let cacheThreshold = null;
483
483
  let perCommandThresholds = null; // Per-command { screen, element } override
484
- let zoom = true; // Default to enabled
484
+ let zoom = false; // Default to disabled
485
+ let verify = false; // Default to disabled (skip AI verification)
485
486
  let perCommandAi = null; // Per-command AI config override
486
487
 
487
488
  let minConfidence = null; // Minimum confidence threshold
@@ -494,8 +495,10 @@ class Element {
494
495
  // New: options is an object with cacheKey and/or cacheThreshold
495
496
  cacheKey = options.cacheKey || null;
496
497
  cacheThreshold = options.cacheThreshold ?? null;
497
- // zoom defaults to true unless explicitly set to false
498
- zoom = options.zoom !== false;
498
+ // zoom defaults to false unless explicitly set to true
499
+ zoom = options.zoom === true;
500
+ // verify defaults to false unless explicitly set to true
501
+ verify = options.verify === true;
499
502
  // Minimum confidence threshold: fail find if AI confidence is below this value
500
503
  minConfidence = options.confidence ?? null;
501
504
  // Element type hint for prompt wrapping
@@ -569,6 +572,7 @@ class Element {
569
572
  os: this.sdk.os,
570
573
  resolution: this.sdk.resolution,
571
574
  zoom: zoom === true ? 1 : zoom === false ? 0 : zoom,
575
+ skipVerify: !verify,
572
576
  confidence: minConfidence,
573
577
  type: elementType,
574
578
  ai: {