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
@@ -1283,12 +1283,12 @@ const createSandbox = function (emitter, analytics, sessionInstance) {
1283
1283
  var rate = (this._publishCount / windowElapsed) * 1000;
1284
1284
  var rateStr = rate.toFixed(1);
1285
1285
 
1286
- // Log rate - warning if approaching limit, debug otherwise
1287
- if (rate > 45) {
1288
- logger.warn("Ably publish rate: " + rateStr + " msg/sec (approaching 50/sec limit)");
1289
- } else if (process.env.VERBOSE || process.env.TD_DEBUG) {
1290
- logger.log("Ably publish rate: " + rateStr + " msg/sec");
1291
- }
1286
+ // // Log rate - warning if approaching limit, debug otherwise
1287
+ // if (rate > 45) {
1288
+ // logger.warn("Ably publish rate: " + rateStr + " msg/sec (approaching 50/sec limit)");
1289
+ // } else if (process.env.VERBOSE || process.env.TD_DEBUG) {
1290
+ // logger.log("Ably publish rate: " + rateStr + " msg/sec");
1291
+ // }
1292
1292
 
1293
1293
  // Reset window
1294
1294
  this._publishCount = 0;
@@ -44,7 +44,7 @@ Use this agent when the user asks to:
44
44
  4. **⚠️ WRITE CODE IMMEDIATELY**: After EVERY successful action, append the generated code to the test file RIGHT AWAY. Do NOT wait until the end.
45
45
  5. **Verify Actions**: Use `check` after actions to verify they succeeded (for YOUR understanding only).
46
46
  6. **Add Assertions**: Use `assert` for test conditions that should be in the final test file.
47
- 7. **⚠️ RUN THE TEST YOURSELF**: Use `vitest run <testFile> --reporter=dot` to run the test - do NOT tell the user to run it. Iterate until it passes. **NEVER use `npx vitest`** - always use `vitest` directly.
47
+ 7. **⚠️ RUN THE TEST YOURSELF**: Use `vitest run <testFile>` to run the test - do NOT tell the user to run it. Iterate until it passes. **NEVER use `npx vitest`** - always use `vitest` directly.
48
48
  8. **⚠️ SHARE THE TEST REPORT**: After EVERY test run, find the `TESTDRIVER_RUN_URL` in the output (e.g., `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...`) and share it with the user so they can view the recording and results.
49
49
 
50
50
  ## Prerequisites
@@ -315,11 +315,9 @@ assert({ assertion: "the dashboard is visible" })
315
315
  **⚠️ YOU must run the test - do NOT tell the user to run it. NEVER use `npx vitest` - always use `vitest` directly:**
316
316
 
317
317
  ```bash
318
- vitest run tests/login.test.mjs --reporter=dot
318
+ vitest run tests/login.test.mjs
319
319
  ```
320
320
 
321
- **Always use `--reporter=dot`** for cleaner, more concise output that's easier to parse.
322
-
323
321
  Analyze the output, fix any issues, and iterate until the test passes.
324
322
 
325
323
  **⚠️ ALWAYS share the test report link with the user.** After each test run, look for `TESTDRIVER_RUN_URL` in the test output (e.g., `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...`) and share it with the user so they can view the recording and results. This is CRITICAL - users need to see the visual recording to understand test behavior.
@@ -568,8 +566,6 @@ await testdriver.pressKeys(["escape"]);
568
566
 
569
567
  // Now scroll
570
568
  await testdriver.scroll("down");
571
- await testdriver.scrollUntilText("Footer text");
572
- await testdriver.scrollUntilImage("Product image at bottom");
573
569
 
574
570
  // If scroll is not working, try using Page Down key directly
575
571
  await testdriver.pressKeys(["pagedown"]);
@@ -614,7 +610,7 @@ await testdriver.screenshot(1, false, true);
614
610
  ## Tips for Agents
615
611
 
616
612
  1. **⚠️ WRITE CODE IMMEDIATELY** - After EVERY successful MCP action, append the generated code to the test file RIGHT AWAY. Do NOT wait until the session ends.
617
- 2. **⚠️ RUN TESTS YOURSELF** - Do NOT tell the user to run tests. YOU must run the tests using `vitest run <testFile> --reporter=dot` (NEVER use `npx vitest` - it breaks the reporter). Always use `--reporter=dot` for cleaner output. Analyze the output and iterate until the test passes.
613
+ 2. **⚠️ RUN TESTS YOURSELF** - Do NOT tell the user to run tests. YOU must run the tests using `vitest run <testFile>` (NEVER use `npx vitest`). Analyze the output and iterate until the test passes.
618
614
  3. **⚠️ SHARE THE TEST REPORT URL** - After EVERY test run, find `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...` in the output and share it with the user. This is CRITICAL - users need to view the recording to understand what happened.
619
615
  3. **Screenshots are automatic** - TestDriver captures screenshots before/after every command by default. Each screenshot filename includes the line number (e.g., `001-click-before-L42-submit-button.png`) making it easy to trace issues.
620
616
  4. **⚠️ USE SCREENSHOT VIEWING FOR DEBUGGING** - When tests fail, use `list_local_screenshots` and `view_local_screenshot` MCP commands to see exactly what the UI looked like. The filenames tell you which line of code triggered each screenshot.
@@ -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={true}>
53
- Two-phase zoom mode for better precision in crowded UIs with many similar elements. Enabled by default.
52
+ <ParamField path="zoom" type="boolean" default={false}>
53
+ Two-phase zoom mode for better precision in crowded UIs with many similar elements. Disabled by default.
54
54
  </ParamField>
55
55
 
56
56
  <ParamField path="ai" type="object">
@@ -334,17 +334,17 @@ The `timeout` option:
334
334
 
335
335
  ## Zoom Mode
336
336
 
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.
337
+ Zoom mode is **disabled by default**. It uses a two-phase approach for better precision when locating elements, especially in crowded UIs with many similar elements.
338
338
 
339
- To disable zoom for a specific find call, pass `zoom: false`:
339
+ To enable zoom for a specific find call, pass `zoom: true`:
340
340
 
341
341
  ```javascript
342
- // Zoom is on by default no option needed
343
- const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar');
342
+ // Enable zoom for better precision in crowded UIs
343
+ const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar', { zoom: true });
344
344
  await extensionsBtn.click();
345
345
 
346
- // Disable zoom for a specific call if needed
347
- const largeButton = await testdriver.find('big hero button', { zoom: false });
346
+ // Without zoom (default)
347
+ const largeButton = await testdriver.find('big hero button');
348
348
  ```
349
349
 
350
350
  ### How Zoom Mode Works
@@ -357,9 +357,9 @@ const largeButton = await testdriver.find('big hero button', { zoom: false });
357
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.
358
358
 
359
359
  <Tip>
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
360
+ You may want to enable zoom with `zoom: true` when:
361
+ - Targeting small elements in crowded UIs with many similar elements
362
+ - You need extra precision for closely spaced UI elements
363
363
  </Tip>
364
364
 
365
365
  ## Cache Options
@@ -27,7 +27,6 @@ await testdriver.find('dropdown menu').hover();
27
27
 
28
28
  // Scrolling
29
29
  await testdriver.scroll('down', 500);
30
- await testdriver.scrollUntilText('Footer content');
31
30
 
32
31
  // Waiting
33
32
  await testdriver.wait(2000); // Wait 2 seconds for animation/state change
@@ -153,7 +153,7 @@ Automatic screenshots are taken around these commands:
153
153
  - `find()` / `findAll()`
154
154
  - `click()` / `hover()` / `doubleClick()` / `rightClick()`
155
155
  - `type()` / `pressKeys()`
156
- - `scroll()` / `scrollUntilText()` / `scrollUntilImage()`
156
+ - `scroll()`
157
157
  - `waitForText()` / `waitForImage()`
158
158
  - `focusApplication()`
159
159
  - `assert()` / `extract()` / `exec()`
@@ -35,8 +35,8 @@ await testdriver.scroll(direction, amount, method)
35
35
  Direction to scroll: `'up'`, `'down'`, `'left'`, `'right'`
36
36
  </ParamField>
37
37
 
38
- <ParamField path="amount" type="number" default="300">
39
- Amount to scroll in pixels
38
+ <ParamField path="amount" type="number" default="3">
39
+ Amount to scroll in clicks (scroll wheel units). Each click is roughly 100px in a browser.
40
40
  </ParamField>
41
41
 
42
42
  <ParamField path="method" type="string" default="mouse">
@@ -55,95 +55,34 @@ await testdriver.scroll(direction, amount, method)
55
55
  // Scroll down (default)
56
56
  await testdriver.scroll();
57
57
 
58
- // Scroll down 500 pixels
59
- await testdriver.scroll('down', 500);
58
+ // Scroll down 5 clicks
59
+ await testdriver.scroll('down', 5);
60
60
 
61
61
  // Scroll up
62
62
  await testdriver.scroll('up');
63
63
 
64
- // Scroll up 200 pixels
65
- await testdriver.scroll('up', 200);
64
+ // Scroll up 2 clicks
65
+ await testdriver.scroll('up', 2);
66
66
  ```
67
67
 
68
68
  ### Horizontal Scrolling
69
69
 
70
70
  ```javascript
71
71
  // Scroll right
72
- await testdriver.scroll('right', 300);
72
+ await testdriver.scroll('right', 3);
73
73
 
74
74
  // Scroll left
75
- await testdriver.scroll('left', 300);
75
+ await testdriver.scroll('left', 3);
76
76
  ```
77
77
 
78
78
  ### Scroll Methods
79
79
 
80
80
  ```javascript
81
- // Mouse wheel scroll (smooth, pixel-precise)
82
- await testdriver.scroll('down', 300, 'mouse');
81
+ // Mouse wheel scroll (smooth)
82
+ await testdriver.scroll('down', 3, 'mouse');
83
83
 
84
84
  // Keyboard scroll (uses Page Down/Up, more compatible)
85
- await testdriver.scroll('down', 300, 'keyboard');
86
- ```
87
-
88
- ## Scroll Until Found
89
-
90
- ### scrollUntilText()
91
-
92
- Scroll until specific text appears on screen.
93
-
94
- ```javascript
95
- await testdriver.scrollUntilText(text, direction, maxDistance, textMatchMethod, method, invert)
96
- ```
97
-
98
- **Parameters:**
99
- - `text` (string) - Text to find
100
- - `direction` (string) - Scroll direction (default: `'down'`)
101
- - `maxDistance` (number) - Max pixels to scroll (default: 10000)
102
- - `textMatchMethod` (string) - `'turbo'` or `'ai'` (default: `'turbo'`)
103
- - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
104
- - `invert` (boolean) - Scroll until text disappears (default: false)
105
-
106
- **Examples:**
107
- ```javascript
108
- // Scroll down until "Contact Us" appears
109
- await testdriver.scrollUntilText('Contact Us');
110
-
111
- // Scroll up to find text
112
- await testdriver.scrollUntilText('Header', 'up');
113
-
114
- // Scroll until text disappears
115
- await testdriver.scrollUntilText('Loading...', 'down', 5000, 'turbo', 'keyboard', true);
116
-
117
- // Use AI matching for fuzzy text
118
- await testdriver.scrollUntilText('footer content', 'down', 10000, 'ai');
119
- ```
120
-
121
- ### scrollUntilImage()
122
-
123
- Scroll until a visual element appears.
124
-
125
- ```javascript
126
- await testdriver.scrollUntilImage(description, direction, maxDistance, method, path, invert)
127
- ```
128
-
129
- **Parameters:**
130
- - `description` (string) - Description of the image/element
131
- - `direction` (string) - Scroll direction (default: `'down'`)
132
- - `maxDistance` (number) - Max pixels to scroll (default: 10000)
133
- - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
134
- - `path` (string | null) - Path to image template (optional)
135
- - `invert` (boolean) - Scroll until image disappears (default: false)
136
-
137
- **Examples:**
138
- ```javascript
139
- // Scroll until visual element appears
140
- await testdriver.scrollUntilImage('red subscribe button');
141
-
142
- // Scroll using image template
143
- await testdriver.scrollUntilImage('', 'down', 10000, 'keyboard', './footer-logo.png');
144
-
145
- // Scroll until image disappears
146
- await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', null, true);
85
+ await testdriver.scroll('down', 3, 'keyboard');
147
86
  ```
148
87
 
149
88
  ## Best Practices
@@ -162,7 +101,7 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
162
101
  // await testdriver.find('page background').click();
163
102
 
164
103
  // Now scroll will work properly
165
- await testdriver.scroll('down', 300);
104
+ await testdriver.scroll('down', 3);
166
105
 
167
106
  // If scroll still doesn't work, use Page Down directly
168
107
  // await testdriver.pressKeys(['pagedown']);
@@ -174,80 +113,27 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
174
113
 
175
114
  ```javascript
176
115
  // For web pages, mouse scroll is usually smoother
177
- await testdriver.scroll('down', 300, 'mouse');
116
+ await testdriver.scroll('down', 3, 'mouse');
178
117
 
179
118
  // For desktop apps or when mouse doesn't work
180
- await testdriver.scroll('down', 300, 'keyboard');
181
- ```
182
- </Check>
183
-
184
- <Check>
185
- **Use scrollUntil for dynamic content**
186
-
187
- ```javascript
188
- // Instead of guessing scroll amount
189
- await testdriver.scrollUntilText('Load More button');
190
-
191
- const loadMoreBtn = await testdriver.find('Load More button');
192
- await loadMoreBtn.click();
193
- ```
194
- </Check>
195
-
196
- <Check>
197
- **Set reasonable max distance**
198
-
199
- ```javascript
200
- // Avoid infinite scrolling
201
- await testdriver.scrollUntilText('Footer', 'down', 5000); // Max 5000px
119
+ await testdriver.scroll('down', 3, 'keyboard');
202
120
  ```
203
121
  </Check>
204
122
 
205
123
  <Warning>
206
124
  **Keyboard scroll uses Page Down/Up**
207
125
 
208
- 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.
126
+ 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.
209
127
  </Warning>
210
128
 
211
129
  ## Use Cases
212
130
 
213
131
  <AccordionGroup>
214
- <Accordion title="Navigate to Footer">
215
- ```javascript
216
- // Scroll to bottom of page
217
- await testdriver.scrollUntilText('Contact Us');
218
-
219
- const contactLink = await testdriver.find('Contact Us link');
220
- await contactLink.click();
221
- ```
222
- </Accordion>
223
-
224
- <Accordion title="Load More Results">
225
- ```javascript
226
- // Scroll to load more button
227
- await testdriver.scrollUntilText('Load More');
228
-
229
- const loadBtn = await testdriver.find('Load More button');
230
- await loadBtn.click();
231
-
232
- await new Promise(r => setTimeout(r, 2000));
233
- ```
234
- </Accordion>
235
-
236
- <Accordion title="Find Element in Long List">
237
- ```javascript
238
- // Scroll through list to find item
239
- await testdriver.scrollUntilText('Product #42');
240
-
241
- const product = await testdriver.find('Product #42');
242
- await product.click();
243
- ```
244
- </Accordion>
245
-
246
132
  <Accordion title="Infinite Scroll">
247
133
  ```javascript
248
134
  // Scroll multiple times for infinite scroll
249
135
  for (let i = 0; i < 5; i++) {
250
- await testdriver.scroll('down', 500);
136
+ await testdriver.scroll('down', 5);
251
137
  await new Promise(r => setTimeout(r, 1000)); // Wait for load
252
138
  }
253
139
  ```
@@ -256,7 +142,7 @@ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', n
256
142
  <Accordion title="Horizontal Gallery">
257
143
  ```javascript
258
144
  // Navigate horizontal carousel
259
- await testdriver.scroll('right', 300);
145
+ await testdriver.scroll('right', 3);
260
146
  await new Promise(r => setTimeout(r, 500));
261
147
 
262
148
  const nextImage = await testdriver.find('next image in carousel');
@@ -287,8 +173,8 @@ describe('Scrolling', () => {
287
173
  it('should scroll to find elements', async () => {
288
174
  await testdriver.focusApplication('Google Chrome');
289
175
 
290
- // Scroll to footer
291
- await testdriver.scrollUntilText('Contact Information');
176
+ // Scroll down the page
177
+ await testdriver.scroll('down', 5);
292
178
 
293
179
  // Click footer link
294
180
  const privacyLink = await testdriver.find('Privacy Policy link');
@@ -302,29 +188,13 @@ describe('Scrolling', () => {
302
188
 
303
189
  // Scroll multiple times to load content
304
190
  for (let i = 0; i < 3; i++) {
305
- await testdriver.scroll('down', 500);
191
+ await testdriver.scroll('down', 5);
306
192
  await new Promise(r => setTimeout(r, 1500)); // Wait for load
307
193
  }
308
194
 
309
195
  // Verify content loaded
310
196
  await testdriver.assert('more than 10 items are visible');
311
197
  });
312
-
313
- it('should scroll until loading completes', async () => {
314
- // Scroll until loading spinner disappears
315
- await testdriver.scrollUntilImage(
316
- 'loading spinner',
317
- 'down',
318
- 5000,
319
- 'keyboard',
320
- null,
321
- true // invert - wait for it to disappear
322
- );
323
-
324
- // Now interact with loaded content
325
- const firstResult = await testdriver.find('first search result');
326
- await firstResult.click();
327
- });
328
198
  });
329
199
  ```
330
200
 
@@ -392,8 +392,6 @@ await element.click();
392
392
 
393
393
  ```javascript
394
394
  await testdriver.scroll("down");
395
- await testdriver.scrollUntilText("Footer text");
396
- await testdriver.scrollUntilImage("Product image at bottom");
397
395
  ```
398
396
 
399
397
  ### Executing Code in Sandbox
@@ -34,7 +34,7 @@ Use this agent when the user asks to:
34
34
  4. **⚠️ WRITE CODE IMMEDIATELY**: After EVERY successful action, append the generated code to the test file RIGHT AWAY. Do NOT wait until the end.
35
35
  5. **Verify Actions**: Use `check` after actions to verify they succeeded (for YOUR understanding only).
36
36
  6. **Add Assertions**: Use `assert` for test conditions that should be in the final test file.
37
- 7. **⚠️ RUN THE TEST YOURSELF**: Use `vitest run <testFile> --reporter=dot` to run the test - do NOT tell the user to run it. Iterate until it passes. **NEVER use `npx vitest`** - always use `vitest` directly.
37
+ 7. **⚠️ RUN THE TEST YOURSELF**: Use `vitest run <testFile>` to run the test - do NOT tell the user to run it. Iterate until it passes. **NEVER use `npx vitest`** - always use `vitest` directly.
38
38
  8. **⚠️ SHARE THE TEST REPORT**: After EVERY test run, find the `TESTDRIVER_RUN_URL` in the output (e.g., `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...`) and share it with the user so they can view the recording and results.
39
39
 
40
40
  ## Prerequisites
@@ -305,11 +305,9 @@ assert({ assertion: "the dashboard is visible" })
305
305
  **⚠️ YOU must run the test - do NOT tell the user to run it. NEVER use `npx vitest` - always use `vitest` directly:**
306
306
 
307
307
  ```bash
308
- vitest run tests/login.test.mjs --reporter=dot
308
+ vitest run tests/login.test.mjs
309
309
  ```
310
310
 
311
- **Always use `--reporter=dot`** for cleaner, more concise output that's easier to parse.
312
-
313
311
  Analyze the output, fix any issues, and iterate until the test passes.
314
312
 
315
313
  **⚠️ ALWAYS share the test report link with the user.** After each test run, look for `TESTDRIVER_RUN_URL` in the test output (e.g., `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...`) and share it with the user so they can view the recording and results. This is CRITICAL - users need to see the visual recording to understand test behavior.
@@ -558,8 +556,6 @@ await testdriver.pressKeys(["escape"]);
558
556
 
559
557
  // Now scroll
560
558
  await testdriver.scroll("down");
561
- await testdriver.scrollUntilText("Footer text");
562
- await testdriver.scrollUntilImage("Product image at bottom");
563
559
 
564
560
  // If scroll is not working, try using Page Down key directly
565
561
  await testdriver.pressKeys(["pagedown"]);
@@ -604,7 +600,7 @@ await testdriver.screenshot(1, false, true);
604
600
  ## Tips for Agents
605
601
 
606
602
  1. **⚠️ WRITE CODE IMMEDIATELY** - After EVERY successful MCP action, append the generated code to the test file RIGHT AWAY. Do NOT wait until the session ends.
607
- 2. **⚠️ RUN TESTS YOURSELF** - Do NOT tell the user to run tests. YOU must run the tests using `vitest run <testFile> --reporter=dot` (NEVER use `npx vitest` - it breaks the reporter). Always use `--reporter=dot` for cleaner output. Analyze the output and iterate until the test passes.
603
+ 2. **⚠️ RUN TESTS YOURSELF** - Do NOT tell the user to run tests. YOU must run the tests using `vitest run <testFile>` (NEVER use `npx vitest`). Analyze the output and iterate until the test passes.
608
604
  3. **⚠️ SHARE THE TEST REPORT URL** - After EVERY test run, find `TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/...` in the output and share it with the user. This is CRITICAL - users need to view the recording to understand what happened.
609
605
  3. **Screenshots are automatic** - TestDriver captures screenshots before/after every command by default. Each screenshot filename includes the line number (e.g., `001-click-before-L42-submit-button.png`) making it easy to trace issues.
610
606
  4. **⚠️ USE SCREENSHOT VIEWING FOR DEBUGGING** - When tests fail, use `list_local_screenshots` and `view_local_screenshot` MCP commands to see exactly what the UI looked like. The filenames tell you which line of code triggered each screenshot.
@@ -2,16 +2,16 @@
2
2
  "$schema": "./examples-manifest.schema.json",
3
3
  "examples": {
4
4
  "assert.test.mjs": {
5
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb166df6a1c5774e8059ab",
6
- "lastUpdated": "2026-03-31T00:53:17.643Z"
5
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8f7248d4e274f31c128",
6
+ "lastUpdated": "2026-04-02T00:49:48.926Z"
7
7
  },
8
8
  "drag-and-drop.test.mjs": {
9
9
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62b42fc0ac3cc632a918b",
10
10
  "lastUpdated": "2026-03-03T00:32:25.275Z"
11
11
  },
12
12
  "exec-pwsh.test.mjs": {
13
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb165ef6a1c5774e80599f",
14
- "lastUpdated": "2026-03-31T00:34:42.693Z"
13
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8e1248d4e274f31c11c",
14
+ "lastUpdated": "2026-04-02T00:33:08.610Z"
15
15
  },
16
16
  "match-image.test.mjs": {
17
17
  "url": "https://console-test.testdriver.ai/runs/69c8738614b73310c7839412/69c8738c14b73310c783941d",
@@ -22,84 +22,84 @@
22
22
  "lastUpdated": "2026-03-03T00:32:25.282Z"
23
23
  },
24
24
  "hover-text-with-description.test.mjs": {
25
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1660f6a1c5774e8059a0",
26
- "lastUpdated": "2026-03-31T00:33:36.228Z"
25
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8e4248d4e274f31c11d",
26
+ "lastUpdated": "2026-04-02T00:31:31.665Z"
27
27
  },
28
28
  "windows-installer.test.mjs": {
29
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1663f6a1c5774e8059a3",
30
- "lastUpdated": "2026-03-31T00:34:47.170Z"
29
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8e8248d4e274f31c120",
30
+ "lastUpdated": "2026-04-02T00:33:15.383Z"
31
31
  },
32
32
  "exec-output.test.mjs": {
33
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1665f6a1c5774e8059a4",
34
- "lastUpdated": "2026-03-31T00:34:48.538Z"
33
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8eb248d4e274f31c121",
34
+ "lastUpdated": "2026-04-02T00:33:18.021Z"
35
35
  },
36
36
  "chrome-extension.test.mjs": {
37
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb165df6a1c5774e80599e",
38
- "lastUpdated": "2026-03-31T00:34:07.368Z"
37
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8df248d4e274f31c11b",
38
+ "lastUpdated": "2026-04-02T00:32:16.921Z"
39
39
  },
40
40
  "launch-vscode-linux.test.mjs": {
41
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1662f6a1c5774e8059a1",
42
- "lastUpdated": "2026-03-31T00:40:26.271Z"
41
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8e6248d4e274f31c11e",
42
+ "lastUpdated": "2026-04-02T00:38:43.485Z"
43
43
  },
44
44
  "hover-image.test.mjs": {
45
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1666f6a1c5774e8059a5",
46
- "lastUpdated": "2026-03-31T00:34:17.480Z"
45
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8ed248d4e274f31c122",
46
+ "lastUpdated": "2026-04-02T00:32:29.925Z"
47
47
  },
48
48
  "installer.test.mjs": {
49
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1668f6a1c5774e8059a6",
50
- "lastUpdated": "2026-03-31T00:33:44.335Z"
49
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8f0248d4e274f31c123",
50
+ "lastUpdated": "2026-04-02T00:31:43.411Z"
51
51
  },
52
52
  "type.test.mjs": {
53
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb166af6a1c5774e8059a9",
54
- "lastUpdated": "2026-03-31T00:34:20.745Z"
53
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8f2248d4e274f31c126",
54
+ "lastUpdated": "2026-04-02T00:32:35.729Z"
55
55
  },
56
56
  "press-keys.test.mjs": {
57
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb166cf6a1c5774e8059aa",
58
- "lastUpdated": "2026-03-31T00:51:20.389Z"
57
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8f5248d4e274f31c127",
58
+ "lastUpdated": "2026-04-02T00:48:38.124Z"
59
59
  },
60
60
  "scroll-keyboard.test.mjs": {
61
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1671f6a1c5774e8059ad",
62
- "lastUpdated": "2026-03-31T00:34:59.681Z"
61
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8fc248d4e274f31c12a",
62
+ "lastUpdated": "2026-04-02T00:33:33.877Z"
63
63
  },
64
64
  "scroll.test.mjs": {
65
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1677f6a1c5774e8059b1",
66
- "lastUpdated": "2026-03-31T00:57:48.346Z"
65
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb905248d4e274f31c12e",
66
+ "lastUpdated": "2026-04-02T00:56:49.118Z"
67
67
  },
68
68
  "scroll-until-image.test.mjs": {
69
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1672f6a1c5774e8059ae",
70
- "lastUpdated": "2026-03-31T00:33:54.647Z"
69
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8fe248d4e274f31c12b",
70
+ "lastUpdated": "2026-04-02T00:31:58.929Z"
71
71
  },
72
72
  "prompt.test.mjs": {
73
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1674f6a1c5774e8059af",
74
- "lastUpdated": "2026-03-31T00:35:02.499Z"
73
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb900248d4e274f31c12c",
74
+ "lastUpdated": "2026-04-02T00:33:38.547Z"
75
75
  },
76
76
  "focus-window.test.mjs": {
77
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1675f6a1c5774e8059b0",
78
- "lastUpdated": "2026-03-31T00:33:57.527Z"
77
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb902248d4e274f31c12d",
78
+ "lastUpdated": "2026-04-02T00:32:03.120Z"
79
79
  },
80
80
  "captcha-api.test.mjs": {
81
81
  "url": "https://console.testdriver.ai/runs/698f7df69e27ce1528d7d087/698f7fb0d3b320ad547d9d44",
82
82
  "lastUpdated": "2026-02-13T19:55:05.951Z"
83
83
  },
84
84
  "element-not-found.test.mjs": {
85
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb1678f6a1c5774e8059b2",
86
- "lastUpdated": "2026-03-31T00:35:06.837Z"
85
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb907248d4e274f31c12f",
86
+ "lastUpdated": "2026-04-02T00:33:44.522Z"
87
87
  },
88
88
  "formatted-logging.test.mjs": {
89
89
  "url": "https://console-test.testdriver.ai/runs/69c8738614b73310c7839412/69c873a714b73310c7839450",
90
90
  "lastUpdated": "2026-03-29T00:36:10.628Z"
91
91
  },
92
92
  "hover-text.test.mjs": {
93
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb167bf6a1c5774e8059b4",
94
- "lastUpdated": "2026-03-31T00:34:03.859Z"
93
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb90c248d4e274f31c131",
94
+ "lastUpdated": "2026-04-02T00:32:11.939Z"
95
95
  },
96
96
  "no-provision.test.mjs": {
97
97
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62b7706a177a05bccd1cf",
98
98
  "lastUpdated": "2026-03-03T00:32:25.279Z"
99
99
  },
100
100
  "ai.test.mjs": {
101
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb167af6a1c5774e8059b3",
102
- "lastUpdated": "2026-03-31T01:00:46.789Z"
101
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb90a248d4e274f31c130",
102
+ "lastUpdated": "2026-04-02T01:00:30.163Z"
103
103
  },
104
104
  "popup-loading.test.mjs": {
105
105
  "url": "https://console.testdriver.ai/runs/698bc89f7140c3fa7daaca8d/698bca7f7140c3fa7daacbf7",
@@ -134,12 +134,12 @@
134
134
  "lastUpdated": "2026-02-13T19:55:05.953Z"
135
135
  },
136
136
  "findall-coffee-icons.test.mjs": {
137
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb166ff6a1c5774e8059ac",
138
- "lastUpdated": "2026-03-31T00:34:26.048Z"
137
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb8fa248d4e274f31c129",
138
+ "lastUpdated": "2026-04-02T00:32:43.247Z"
139
139
  },
140
140
  "parse.test.mjs": {
141
- "url": "https://console-test.testdriver.ai/runs/69cb165bf6a1c5774e80599d/69cb167df6a1c5774e8059b5",
142
- "lastUpdated": "2026-03-31T00:35:11.393Z"
141
+ "url": "https://console-test.testdriver.ai/runs/69cdb8dd248d4e274f31c11a/69cdb90e248d4e274f31c132",
142
+ "lastUpdated": "2026-04-02T00:33:51.354Z"
143
143
  },
144
144
  "flake-diffthreshold-001.test.mjs": {
145
145
  "url": "https://console.testdriver.ai/runs/69a62b3aaa712ecd3dea730a/69a62bcafc0ac3cc632a91aa",
@@ -14,7 +14,7 @@ steps:
14
14
  - command: press-keys
15
15
  keys:
16
16
  - enter
17
- - prompt: scroll down with the mouse 1000 pixels
17
+ - prompt: scroll down with the mouse 10 clicks
18
18
  commands:
19
19
  - command: hover-text
20
20
  text: "HTML: HyperText Markup Language"
@@ -22,7 +22,7 @@ steps:
22
22
  action: click
23
23
  - command: scroll
24
24
  direction: down
25
- amount: 1000
25
+ amount: 10
26
26
  - prompt: assert the page is scrolled
27
27
  commands:
28
28
  - command: assert
@@ -22,7 +22,7 @@ The `scroll-until-image` command is used to scroll the screen in a specified dir
22
22
  | :-----------: | :-------: | :---------------------------------------------------------------------------------------------------------------------- |
23
23
  | `description` | `string` | A description of the image and what it represents. |
24
24
  | `direction` | `string` | (Optional) The direction to scroll. Available directions are: `up`, `down`, `left`, `right`. Defaults to `down`. |
25
- | `distance` | `number` | (Optional) The maximum number of pixels to scroll before giving up. Default is `10000`. |
25
+ | `distance` | `number` | (Optional) The maximum number of scroll clicks before giving up. Default is `100`. |
26
26
  | `method` | `string` | (Optional) The method to use to scroll the page. Available methods are: `mouse` and `keyboard`. Defaults to `keyboard`. |
27
27
  | `path` | `string` | (Optional) The relative path to the image file that needs to be matched on the screen. |
28
28
  | `invert` | `boolean` | (Optional) If set to `true`, the command will scroll until the specified image is NOT detected. Default is `false`. |