@testdriverai/mcp 7.10.0-canary.0 → 7.10.1-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 (196) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/agent/index.js +116 -71
  3. package/agent/interface.js +13 -1
  4. package/agent/lib/commands.js +35 -15
  5. package/agent/lib/provision-commands.js +92 -11
  6. package/agent/lib/sandbox.js +263 -30
  7. package/agent/lib/sdk.js +16 -12
  8. package/agent/lib/system.js +107 -31
  9. package/ai/.claude-plugin/plugin.json +89 -4
  10. package/ai/agents/testdriver.md +4 -8
  11. package/ai/skills/testdriver-assert/SKILL.md +0 -1
  12. package/ai/skills/testdriver-aws-setup/SKILL.md +1 -1
  13. package/ai/skills/testdriver-caching/SKILL.md +13 -6
  14. package/ai/skills/testdriver-ci-cd/SKILL.md +57 -14
  15. package/ai/skills/testdriver-client/SKILL.md +10 -6
  16. package/ai/skills/testdriver-customizing-devices/SKILL.md +7 -5
  17. package/ai/skills/testdriver-dashcam/SKILL.md +36 -3
  18. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +28 -4
  19. package/ai/skills/testdriver-device-config/SKILL.md +5 -5
  20. package/ai/skills/testdriver-find/SKILL.md +50 -11
  21. package/ai/skills/testdriver-generating-tests/SKILL.md +163 -8
  22. package/ai/skills/testdriver-hosted/SKILL.md +1 -1
  23. package/ai/skills/testdriver-machine-setup/SKILL.md +331 -0
  24. package/ai/skills/testdriver-making-assertions/SKILL.md +78 -2
  25. package/ai/skills/testdriver-mcp-workflow/SKILL.md +2 -2
  26. package/ai/skills/testdriver-parse/SKILL.md +1 -1
  27. package/ai/skills/testdriver-performing-actions/SKILL.md +97 -3
  28. package/ai/skills/testdriver-provision/SKILL.md +0 -20
  29. package/ai/skills/testdriver-quickstart/SKILL.md +299 -21
  30. package/ai/skills/testdriver-reusable-code/SKILL.md +3 -3
  31. package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
  32. package/ai/skills/testdriver-screenshot/SKILL.md +5 -5
  33. package/ai/skills/testdriver-scroll/SKILL.md +30 -160
  34. package/ai/skills/testdriver-test-writer/SKILL.md +3 -5
  35. package/ai/skills/testdriver-testdriver/SKILL.md +3 -7
  36. package/ai/skills/testdriver-wait/SKILL.md +1 -1
  37. package/{docs/v7/ai.mdx → ai/skills/testdriver:ai/SKILL.md} +3 -4
  38. package/ai/skills/testdriver:assert/SKILL.md +315 -0
  39. package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
  40. package/ai/skills/testdriver:cache/SKILL.md +221 -0
  41. package/ai/skills/testdriver:caching/SKILL.md +124 -0
  42. package/ai/skills/testdriver:captcha/SKILL.md +158 -0
  43. package/ai/skills/testdriver:ci-cd/SKILL.md +659 -0
  44. package/ai/skills/testdriver:click/SKILL.md +286 -0
  45. package/ai/skills/testdriver:client/SKILL.md +477 -0
  46. package/ai/skills/testdriver:customizing-devices/SKILL.md +319 -0
  47. package/ai/skills/testdriver:dashcam/SKILL.md +451 -0
  48. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +415 -0
  49. package/{docs/v7/device-config.mdx → ai/skills/testdriver:device-config/SKILL.md} +8 -8
  50. package/ai/skills/testdriver:double-click/SKILL.md +102 -0
  51. package/ai/skills/testdriver:elements/SKILL.md +605 -0
  52. package/ai/skills/testdriver:enterprise/SKILL.md +7 -0
  53. package/ai/skills/testdriver:errors/SKILL.md +246 -0
  54. package/ai/skills/testdriver:events/SKILL.md +356 -0
  55. package/ai/skills/testdriver:exec/SKILL.md +317 -0
  56. package/ai/skills/testdriver:find/SKILL.md +860 -0
  57. package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
  58. package/ai/skills/testdriver:generating-tests/SKILL.md +25 -0
  59. package/ai/skills/testdriver:hosted/SKILL.md +156 -0
  60. package/ai/skills/testdriver:hover/SKILL.md +278 -0
  61. package/{docs/v7/locating-elements.mdx → ai/skills/testdriver:locating-elements/SKILL.md} +3 -3
  62. package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
  63. package/ai/skills/testdriver:mcp/SKILL.md +7 -0
  64. package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
  65. package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
  66. package/ai/skills/testdriver:parse/SKILL.md +236 -0
  67. package/ai/skills/testdriver:performing-actions/SKILL.md +53 -0
  68. package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
  69. package/ai/skills/testdriver:provision/SKILL.md +331 -0
  70. package/ai/skills/testdriver:quickstart/SKILL.md +172 -0
  71. package/ai/skills/testdriver:redraw/SKILL.md +214 -0
  72. package/ai/skills/testdriver:reusable-code/SKILL.md +249 -0
  73. package/ai/skills/testdriver:right-click/SKILL.md +123 -0
  74. package/{docs/v7/running-tests.mdx → ai/skills/testdriver:running-tests/SKILL.md} +4 -4
  75. package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
  76. package/ai/skills/testdriver:screenshots/SKILL.md +184 -0
  77. package/ai/skills/testdriver:scroll/SKILL.md +205 -0
  78. package/ai/skills/testdriver:secrets/SKILL.md +115 -0
  79. package/ai/skills/testdriver:self-hosted/SKILL.md +147 -0
  80. package/ai/skills/testdriver:test-results-json/SKILL.md +257 -0
  81. package/ai/skills/testdriver:testdriver/SKILL.md +624 -0
  82. package/ai/skills/testdriver:type/SKILL.md +357 -0
  83. package/ai/skills/testdriver:variables/SKILL.md +111 -0
  84. package/ai/skills/testdriver:wait/SKILL.md +50 -0
  85. package/{docs/v7/waiting-for-elements.mdx → ai/skills/testdriver:waiting-for-elements/SKILL.md} +3 -3
  86. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  87. package/debugger/index.html +12 -0
  88. package/docs/_data/examples-manifest.json +54 -46
  89. package/docs/_data/examples-manifest.schema.json +12 -2
  90. package/docs/_scripts/extract-example-urls.js +21 -3
  91. package/docs/_scripts/generate-examples.js +64 -16
  92. package/docs/changelog.mdx +29 -2
  93. package/docs/claude-mcp-plugin.mdx +65 -18
  94. package/docs/docs.json +16 -33
  95. package/docs/snippets/tests/scroll-yaml.mdx +2 -2
  96. package/docs/v6/commands/scroll-until-image.mdx +1 -1
  97. package/docs/v6/commands/scroll-until-text.mdx +2 -2
  98. package/docs/v6/commands/scroll.mdx +2 -2
  99. package/docs/v7/_drafts/agents.mdx +0 -4
  100. package/docs/v7/_drafts/best-practices.mdx +0 -12
  101. package/docs/v7/_drafts/commands/scroll-until-image.mdx +1 -1
  102. package/docs/v7/_drafts/commands/scroll-until-text.mdx +2 -2
  103. package/docs/v7/_drafts/commands/scroll.mdx +1 -1
  104. package/docs/v7/_drafts/configuration.mdx +0 -12
  105. package/docs/v7/_drafts/faq.mdx +2 -10
  106. package/docs/v7/_drafts/readme.mdx +0 -1
  107. package/docs/v7/_drafts/troubleshooting.mdx +1 -4
  108. package/docs/v7/assert.mdx +0 -1
  109. package/docs/v7/aws-setup.mdx +1 -1
  110. package/docs/v7/caching.mdx +14 -10
  111. package/docs/v7/ci-cd.mdx +98 -14
  112. package/docs/v7/client.mdx +10 -6
  113. package/docs/v7/copilot/auto-healing.mdx +167 -18
  114. package/docs/v7/copilot/running-tests.mdx +915 -54
  115. package/docs/v7/customizing-devices.mdx +7 -5
  116. package/docs/v7/dashcam.mdx +36 -3
  117. package/docs/v7/debugging-with-screenshots.mdx +31 -7
  118. package/docs/v7/examples/ai.mdx +13 -8
  119. package/docs/v7/examples/assert.mdx +1 -1
  120. package/docs/v7/examples/chrome-extension.mdx +30 -13
  121. package/docs/v7/examples/element-not-found.mdx +1 -1
  122. package/docs/v7/examples/findall-coffee-icons.mdx +3 -2
  123. package/docs/v7/examples/formatted-logging.mdx +74 -0
  124. package/docs/v7/examples/hover-image.mdx +1 -1
  125. package/docs/v7/examples/hover-text-with-description.mdx +2 -2
  126. package/docs/v7/examples/hover-text.mdx +1 -1
  127. package/docs/v7/examples/installer.mdx +1 -1
  128. package/docs/v7/examples/launch-vscode-linux.mdx +27 -27
  129. package/docs/v7/examples/match-image.mdx +1 -1
  130. package/docs/v7/examples/parse.mdx +3 -2
  131. package/docs/v7/examples/press-keys.mdx +2 -2
  132. package/docs/v7/examples/scroll-keyboard.mdx +2 -2
  133. package/docs/v7/examples/scroll-until-text.mdx +1 -1
  134. package/docs/v7/examples/scroll.mdx +1 -1
  135. package/docs/v7/examples/type.mdx +1 -1
  136. package/docs/v7/find.mdx +50 -11
  137. package/docs/v7/generating-tests.mdx +166 -10
  138. package/docs/v7/hosted.mdx +1 -1
  139. package/docs/v7/making-assertions.mdx +81 -4
  140. package/docs/v7/parse.mdx +1 -1
  141. package/docs/v7/performing-actions.mdx +100 -5
  142. package/docs/v7/provision.mdx +0 -20
  143. package/docs/v7/quickstart.mdx +299 -21
  144. package/docs/v7/reusable-code.mdx +3 -3
  145. package/docs/v7/screenshot.mdx +5 -5
  146. package/docs/v7/scroll.mdx +30 -160
  147. package/docs/v7/wait.mdx +1 -1
  148. package/examples/chrome-extension.test.mjs +29 -12
  149. package/examples/config.mjs +1 -1
  150. package/examples/launch-vscode-linux.test.mjs +25 -25
  151. package/interfaces/cli/commands/init.js +84 -2
  152. package/interfaces/vitest-plugin.mjs +51 -61
  153. package/lib/core/Dashcam.js +43 -2
  154. package/lib/core/index.d.ts +13 -1
  155. package/lib/github-comment.mjs +11 -5
  156. package/lib/init-project.js +98 -44
  157. package/lib/install-clients.js +470 -0
  158. package/lib/provision.js +749 -0
  159. package/lib/resolve-channel.js +2 -2
  160. package/lib/sentry.js +15 -2
  161. package/lib/vitest/hooks.mjs +44 -34
  162. package/mcp-server/README.md +32 -0
  163. package/mcp-server/dist/core/actions.d.ts +176 -0
  164. package/mcp-server/dist/core/actions.js +753 -0
  165. package/mcp-server/dist/env-utils.d.ts +45 -0
  166. package/mcp-server/dist/env-utils.js +63 -0
  167. package/mcp-server/dist/provision-types.d.ts +6 -2
  168. package/mcp-server/dist/provision-types.js +3 -1
  169. package/mcp-server/dist/server.mjs +449 -751
  170. package/mcp-server/package-lock.json +384 -1
  171. package/mcp-server/package.json +5 -2
  172. package/mcp-server/src/core/actions.ts +912 -0
  173. package/mcp-server/src/env-utils.test.ts +82 -0
  174. package/mcp-server/src/env-utils.ts +77 -0
  175. package/mcp-server/src/provision-types.ts +4 -1
  176. package/mcp-server/src/server.ts +533 -954
  177. package/mcp-server/tsconfig.json +1 -1
  178. package/mcp-server/vitest.config.ts +7 -0
  179. package/package.json +15 -3
  180. package/sdk.d.ts +11 -9
  181. package/sdk.js +116 -746
  182. package/setup/aws/spawn-runner.sh +24 -3
  183. package/docs/v7/_drafts/caching-ai.mdx +0 -215
  184. package/docs/v7/_drafts/caching.mdx +0 -366
  185. package/docs/v7/_drafts/prompt-cache.mdx +0 -200
  186. package/docs/v7/copilot/creating-tests.mdx +0 -156
  187. package/docs/v7/copilot/github.mdx +0 -143
  188. package/docs/v7/copilot/setup.mdx +0 -143
  189. package/docs/v7/examples/exec-output.mdx +0 -84
  190. package/docs/v7/examples/exec-pwsh.mdx +0 -82
  191. package/docs/v7/examples/focus-window.mdx +0 -61
  192. package/docs/v7/examples/scroll-until-image.mdx +0 -82
  193. package/docs/v7/examples/windows-installer.mdx +0 -95
  194. package/examples/formatted-logging.test.mjs +0 -27
  195. package/examples/match-image.test.mjs +0 -55
  196. package/manual/exec-stream-logs.test.mjs +0 -25
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: testdriver:screenshot
3
+ description: Capture and save screenshots during test execution
4
+ ---
5
+ <!-- Generated from screenshot.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ Capture a screenshot of the current screen and automatically save it to a local file. Screenshots are organized by test file for easy debugging and review.
10
+
11
+ <Note>
12
+ **Automatic Screenshots**: TestDriver can automatically capture screenshots before and after every command (click, type, find, etc.). These are saved with descriptive filenames like `001-click-before-L42-submit-button.png` that include the line number from your test file. Enable this with `autoScreenshots: true` in your TestDriver options.
13
+ </Note>
14
+
15
+ ## Syntax
16
+
17
+ ```javascript
18
+ const filePath = await testdriver.screenshot(filename)
19
+ ```
20
+
21
+ ## Parameters
22
+
23
+ <ParamField path="filename" type="string" optional>
24
+ Custom filename for the screenshot (without .png extension). If not provided, a timestamp-based filename is generated automatically.
25
+ </ParamField>
26
+
27
+ ## Returns
28
+
29
+ `Promise<string>` - The absolute file path where the screenshot was saved
30
+
31
+ ## File Organization
32
+
33
+ Screenshots are automatically saved to `.testdriver/screenshots/<test-file-name>/` in your project root:
34
+
35
+ ```
36
+ .testdriver/
37
+ screenshots/
38
+ login.test/
39
+ 001-find-before-L15-email-input.png # Auto: before find()
40
+ 002-find-after-L15-email-input.png # Auto: after find()
41
+ 003-click-before-L16-email-input.png # Auto: before click()
42
+ 004-click-after-L16-email-input.png # Auto: after click()
43
+ 005-type-before-L17-userexamplecom.png # Auto: before type()
44
+ 006-type-after-L17-userexamplecom.png # Auto: after type()
45
+ custom-screenshot.png # Manual: screenshot("custom-screenshot")
46
+ checkout.test/
47
+ 001-find-before-L12-checkout-button.png
48
+ ...
49
+ ```
50
+
51
+ ### Automatic Screenshot Naming
52
+
53
+ When `autoScreenshots` is enabled, filenames follow this format:
54
+
55
+ `<seq>-<action>-<phase>-L<line>-<description>.png`
56
+
57
+ | Component | Description | Example |
58
+ |-----------|-------------|---------|
59
+ | `seq` | Sequential number (001, 002, ...) | `001` |
60
+ | `action` | Command name | `click`, `type`, `find` |
61
+ | `phase` | Before, after, or error | `before`, `after` |
62
+ | `L<line>` | Line number from test file | `L42` |
63
+ | `description` | Element description or action target | `submit-button` |
64
+
65
+ <Note>
66
+ The screenshot folder for each test file is automatically cleared when the test starts. This ensures you only see screenshots from the most recent test run.
67
+ </Note>
68
+
69
+ ## Examples
70
+
71
+ ### Basic Screenshot
72
+
73
+ ```javascript
74
+ // Capture a screenshot with auto-generated filename
75
+ const screenshotPath = await testdriver.screenshot();
76
+ console.log('Screenshot saved to:', screenshotPath);
77
+ ```
78
+
79
+ ### Custom Filename
80
+
81
+ ```javascript
82
+ // Save with a descriptive filename
83
+ await testdriver.screenshot("login-page");
84
+ // Saves to: .testdriver/screenshots/<test>/login-page.png
85
+
86
+ await testdriver.screenshot("after-click");
87
+ // Saves to: .testdriver/screenshots/<test>/after-click.png
88
+ ```
89
+
90
+ ### Debugging with Screenshots
91
+
92
+ ```javascript
93
+ import { describe, expect, it } from "vitest";
94
+ import { TestDriver } from "testdriverai/vitest/hooks";
95
+
96
+ describe("Login Flow", () => {
97
+ it("should log in successfully", async (context) => {
98
+ const testdriver = TestDriver(context);
99
+
100
+ await testdriver.provision.chrome({
101
+ url: 'https://myapp.com/login',
102
+ });
103
+
104
+ // Capture initial state
105
+ await testdriver.screenshot();
106
+
107
+ // Fill in login form
108
+ const emailInput = await testdriver.find("email input");
109
+ await emailInput.click();
110
+ await testdriver.type("user@example.com");
111
+
112
+ // Capture state after typing
113
+ await testdriver.screenshot();
114
+
115
+ const passwordInput = await testdriver.find("password input");
116
+ await passwordInput.click();
117
+ await testdriver.type("password123");
118
+
119
+ // Capture before clicking login
120
+ await testdriver.screenshot();
121
+
122
+ const loginButton = await testdriver.find("Login button");
123
+ await loginButton.click();
124
+
125
+ // Capture after login attempt
126
+ await testdriver.screenshot();
127
+
128
+ const result = await testdriver.assert("dashboard is visible");
129
+ expect(result).toBeTruthy();
130
+ });
131
+ });
132
+ ```
133
+
134
+ ## Automatic Screenshots
135
+
136
+ By default, TestDriver captures screenshots **automatically** before and after every command. This creates a complete visual timeline of your test execution without any additional code.
137
+
138
+ ### Enabling/Disabling
139
+
140
+ ```javascript
141
+ // Auto-screenshots enabled by default
142
+ const testdriver = TestDriver(context);
143
+
144
+ // Explicitly disable if needed (not recommended)
145
+ const testdriver = TestDriver(context, {
146
+ autoScreenshots: false
147
+ });
148
+ ```
149
+
150
+ ### What Gets Captured
151
+
152
+ Automatic screenshots are taken around these commands:
153
+ - `find()` / `findAll()`
154
+ - `click()` / `hover()` / `doubleClick()` / `rightClick()`
155
+ - `type()` / `pressKeys()`
156
+ - `scroll()`
157
+ - `waitForText()` / `waitForImage()`
158
+ - `focusApplication()`
159
+ - `assert()` / `extract()` / `exec()`
160
+
161
+ ### Example Output
162
+
163
+ For this test code:
164
+
165
+ ```javascript
166
+ // Line 15: Find email input
167
+ const emailInput = await testdriver.find("email input");
168
+ // Line 16: Click it
169
+ await emailInput.click();
170
+ // Line 17: Type email
171
+ await testdriver.type("user@example.com");
172
+ ```
173
+
174
+ TestDriver automatically saves:
175
+
176
+ ```
177
+ 001-find-before-L15-email-input.png
178
+ 002-find-after-L15-email-input.png
179
+ 003-click-before-L16-email-input.png
180
+ 004-click-after-L16-email-input.png
181
+ 005-type-before-L17-userexamplecom.png
182
+ 006-type-after-L17-userexamplecom.png
183
+ ```
184
+
185
+ If an error occurs, the phase will be `error` instead of `after`.
186
+
187
+ ## Best Practices
188
+
189
+ <AccordionGroup>
190
+ <Accordion title="Let automatic screenshots do the work">
191
+ With `autoScreenshots: true`, you get comprehensive coverage without adding manual `screenshot()` calls. Only add manual screenshots for specific named checkpoints.
192
+ </Accordion>
193
+
194
+ <Accordion title="Use screenshots for debugging flaky tests">
195
+ When a test fails intermittently, add screenshots at key steps to capture the actual screen state. This helps identify timing issues or unexpected UI states.
196
+ </Accordion>
197
+
198
+ <Accordion title="Capture before assertions">
199
+ Take a screenshot before making assertions. If the assertion fails, you'll have a visual record of what the screen looked like.
200
+
201
+ ```javascript
202
+ await testdriver.screenshot();
203
+ const result = await testdriver.assert("checkout button is visible");
204
+ ```
205
+ </Accordion>
206
+
207
+ <Accordion title="Add to .gitignore">
208
+ Add `.testdriver/screenshots/` to your `.gitignore` to avoid committing screenshots to version control:
209
+
210
+ ```
211
+ # .gitignore
212
+ .testdriver/screenshots/
213
+ ```
214
+ </Accordion>
215
+ </AccordionGroup>
216
+
217
+ ## Viewing Saved Screenshots
218
+
219
+ After saving screenshots during test execution, you can view them using TestDriver MCP commands. This is especially useful for debugging failed tests or verifying test behavior.
220
+
221
+ ### MCP Commands for Screenshot Viewing
222
+
223
+ **List all saved screenshots:**
224
+
225
+ ```
226
+ list_local_screenshots()
227
+ ```
228
+
229
+ **View a specific screenshot:**
230
+
231
+ ```
232
+ view_local_screenshot({ path: "/full/path/to/screenshot.png" })
233
+ ```
234
+
235
+ These commands allow you to:
236
+ - View screenshots from failed tests to understand what went wrong
237
+ - Review test execution flow by examining screenshots in chronological order
238
+ - Compare screenshots across test runs to identify flaky behavior
239
+
240
+ <Note>
241
+ For detailed workflows and examples of using these MCP commands for debugging, see the [Debugging with Screenshots](/v7/debugging-with-screenshots) guide.
242
+ </Note>
243
+
244
+ ## Related
245
+
246
+ - [Debugging with Screenshots](/v7/debugging-with-screenshots) - View and analyze saved screenshots using MCP
247
+ - [assert()](/v7/assert) - Make AI-powered assertions
248
+ - [find()](/v7/find) - Locate elements on screen
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: testdriver:screenshots
3
+ description: Capture and manage screenshots during test execution
4
+ ---
5
+ <!-- Generated from screenshots.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ TestDriver can capture screenshots manually at any point during a test, or automatically before and after every command. Screenshots are saved to a structured directory for easy debugging.
10
+
11
+ ## Manual Screenshots
12
+
13
+ Use `testdriver.screenshot()` to capture the current screen:
14
+
15
+ ```javascript
16
+ const path = await testdriver.screenshot();
17
+ console.log('Saved to:', path);
18
+ // .testdriver/screenshots/my-test/screenshot-1719849312345.png
19
+ ```
20
+
21
+ ### Options
22
+
23
+ ```javascript
24
+ await testdriver.screenshot(filename?)
25
+ ```
26
+
27
+ <ParamField path="filename" type="string">
28
+ Custom filename for the screenshot. `.png` is appended automatically if missing. If omitted, defaults to `screenshot-<timestamp>.png`.
29
+ </ParamField>
30
+
31
+ **Returns:** `Promise<string>` — the absolute file path of the saved screenshot.
32
+
33
+ ```javascript
34
+ // Default filename
35
+ await testdriver.screenshot();
36
+ // → .testdriver/screenshots/my-test/screenshot-1719849312345.png
37
+
38
+ // Custom filename
39
+ await testdriver.screenshot('login-page');
40
+ // → .testdriver/screenshots/my-test/login-page.png
41
+
42
+ // With .png extension
43
+ await testdriver.screenshot('dashboard-loaded.png');
44
+ // → .testdriver/screenshots/my-test/dashboard-loaded.png
45
+ ```
46
+
47
+ ## Auto Screenshots
48
+
49
+ Enable automatic screenshots before and after every command:
50
+
51
+ ```javascript
52
+ const testdriver = new TestDriver({
53
+ autoScreenshots: true,
54
+ });
55
+ ```
56
+
57
+ <ParamField path="autoScreenshots" type="boolean" default={false}>
58
+ When `true`, captures a screenshot before and after every SDK command (`click`, `type`, `find`, `scroll`, `hover`, `pressKeys`, `assert`, `exec`, etc.). On error, an error-phase screenshot replaces the after-phase screenshot.
59
+ </ParamField>
60
+
61
+ ### Filename Format
62
+
63
+ Auto-screenshots follow this naming convention:
64
+
65
+ ```
66
+ <seq>-<action>-<phase>-L<line>-<description>.png
67
+ ```
68
+
69
+ | Part | Description | Example |
70
+ |---|---|---|
71
+ | `seq` | 3-digit zero-padded sequence number | `001` |
72
+ | `action` | Command name | `click`, `type`, `find` |
73
+ | `phase` | `before`, `after`, or `error` | `before` |
74
+ | `L<line>` | Source line number from your test file | `L42` |
75
+ | `description` | Sanitized from command arguments (max 30 chars) | `submit-button` |
76
+
77
+ **Examples:**
78
+ ```
79
+ 001-find-before-L15-login-button.png
80
+ 002-find-after-L15-login-button.png
81
+ 003-click-before-L16-login-button.png
82
+ 004-click-after-L16-login-button.png
83
+ 005-type-before-L18-username-field.png
84
+ 006-type-error-L18-username-field.png
85
+ ```
86
+
87
+ ### Phases
88
+
89
+ | Phase | When | Description |
90
+ |---|---|---|
91
+ | `before` | Before command executes | Captures the screen state before the action |
92
+ | `after` | After successful command | Captures the result of the action |
93
+ | `error` | After failed command | Captures the screen at the point of failure (replaces `after`) |
94
+
95
+ ## Screenshot Directory
96
+
97
+ Screenshots are saved to:
98
+
99
+ ```
100
+ <cwd>/.testdriver/screenshots/<testFileName>/
101
+ ```
102
+
103
+ Where `<testFileName>` is the test file name without its extension. For example, a test at `tests/login.test.mjs` saves screenshots to `.testdriver/screenshots/login.test/`.
104
+
105
+ ### Directory Cleanup
106
+
107
+ The screenshot directory for each test file is **automatically cleaned** at the start of a test run. This happens once per process per test file to prevent concurrent tests from the same file from interfering with each other.
108
+
109
+ ## Debug Screenshots
110
+
111
+ Elements have a `saveDebugScreenshot()` method for debugging element detection:
112
+
113
+ ```javascript
114
+ const el = await testdriver.find('submit button');
115
+
116
+ // Save the screenshot that was used to detect this element
117
+ const debugPath = await el.saveDebugScreenshot();
118
+ console.log('Debug screenshot:', debugPath);
119
+ // → ./debug-screenshot-1719849312345.png
120
+
121
+ // Custom path
122
+ await el.saveDebugScreenshot('./my-debug.png');
123
+ ```
124
+
125
+ This saves the screenshot that was captured during the `find()` call, which can be useful for understanding what the AI "saw" when locating the element.
126
+
127
+ ## Complete Example
128
+
129
+ ```javascript
130
+ import { describe, it, beforeAll, afterAll } from 'vitest';
131
+ import TestDriver from 'testdriverai';
132
+
133
+ describe('Screenshot Example', () => {
134
+ let testdriver;
135
+
136
+ beforeAll(async () => {
137
+ testdriver = new TestDriver({
138
+ autoScreenshots: true, // capture every step
139
+ });
140
+ await testdriver.ready();
141
+ await testdriver.provision.chrome({ url: 'https://example.com' });
142
+ });
143
+
144
+ afterAll(async () => {
145
+ await testdriver.disconnect();
146
+ });
147
+
148
+ it('captures the login flow', async () => {
149
+ // Auto-screenshots capture before/after each command
150
+
151
+ // Manual screenshot for a specific moment
152
+ await testdriver.screenshot('initial-page-load');
153
+
154
+ const username = await testdriver.find('username input');
155
+ await username.click();
156
+ await testdriver.type('testuser@example.com');
157
+
158
+ await testdriver.screenshot('after-username-entry');
159
+
160
+ const password = await testdriver.find('password input');
161
+ await password.click();
162
+ await testdriver.type('password123');
163
+
164
+ await testdriver.find('login button').click();
165
+
166
+ await testdriver.screenshot('after-login-click');
167
+ });
168
+ });
169
+ ```
170
+
171
+ After running, your screenshot directory will contain:
172
+ ```
173
+ .testdriver/screenshots/login-flow.test/
174
+ ├── initial-page-load.png
175
+ ├── 001-find-before-L18-username-input.png
176
+ ├── 002-find-after-L18-username-input.png
177
+ ├── 003-click-before-L19-username-input.png
178
+ ├── 004-click-after-L19-username-input.png
179
+ ├── 005-type-before-L20-testuser-example-com.png
180
+ ├── 006-type-after-L20-testuser-example-com.png
181
+ ├── after-username-entry.png
182
+ ├── 007-find-before-L24-password-input.png
183
+ ├── ...
184
+ ```
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: testdriver:scroll
3
+ description: Scroll pages and elements
4
+ ---
5
+ <!-- Generated from scroll.mdx. DO NOT EDIT. -->
6
+
7
+ ## Overview
8
+
9
+ Scroll the page or active element in any direction using mouse wheel or keyboard.
10
+
11
+ <Warning>
12
+ **Focus Requirements**
13
+
14
+ Scrolling requires the page or a frame to be focused. If an input field or other interactive element has focus, scroll commands may not work as expected. Before scrolling, ensure focus is on the page by:
15
+ - Clicking on a non-interactive area (e.g., page background)
16
+ - Pressing the Escape key to unfocus interactive elements
17
+ - Clicking outside of input fields or text areas
18
+
19
+ **If scroll is still not working**, try using Page Down/Page Up keys directly:
20
+ ```javascript
21
+ await testdriver.pressKeys(['pagedown']); // Scroll down
22
+ await testdriver.pressKeys(['pageup']); // Scroll up
23
+ ```
24
+ </Warning>
25
+
26
+ ## Syntax
27
+
28
+ ```javascript
29
+ await testdriver.scroll(direction, options)
30
+ ```
31
+
32
+ ## Parameters
33
+
34
+ <ParamField path="direction" type="string" default="down">
35
+ Direction to scroll: `'up'`, `'down'`
36
+ </ParamField>
37
+
38
+ <ParamField path="options" type="object">
39
+ <Expandable title="properties">
40
+ <ParamField path="amount" type="number" default="300">
41
+ Amount to scroll in pixels
42
+ </ParamField>
43
+ </Expandable>
44
+ </ParamField>
45
+
46
+ ## Returns
47
+
48
+ `Promise<void>`
49
+
50
+ ## Examples
51
+
52
+ ### Basic Scrolling
53
+
54
+ ```javascript
55
+ // Scroll down (default)
56
+ await testdriver.scroll();
57
+
58
+ // Scroll down 5 clicks
59
+ await testdriver.scroll('down', { amount: 5 });
60
+
61
+ // Scroll up
62
+ await testdriver.scroll('up');
63
+
64
+ // Scroll up 2 clicks
65
+ await testdriver.scroll('up', { amount: 2 });
66
+ ```
67
+
68
+ ### Horizontal Scrolling
69
+
70
+ ```javascript
71
+ // Scroll right
72
+ await testdriver.scroll('right', { amount: 3 });
73
+
74
+ // Scroll left
75
+ await testdriver.scroll('left', { amount: 3 });
76
+ ```
77
+
78
+ ### Scroll Methods
79
+
80
+ ```javascript
81
+ // Mouse wheel scroll (default)
82
+ await testdriver.scroll('down', { amount: 3 });
83
+
84
+ // For keyboard-based scrolling, use pressKeys instead
85
+ await testdriver.pressKeys(['pagedown']);
86
+ ```
87
+
88
+ ## Best Practices
89
+
90
+ <Check>
91
+ **Ensure page has focus before scrolling**
92
+
93
+ ```javascript
94
+ // After typing in an input, unfocus it first
95
+ await testdriver.find('email input').click();
96
+ await testdriver.type('user@example.com');
97
+
98
+ // Click elsewhere or press Escape before scrolling
99
+ await testdriver.pressKeys(['escape']);
100
+ // Or click a non-interactive area
101
+ // await testdriver.find('page background').click();
102
+
103
+ // Now scroll will work properly
104
+ await testdriver.scroll('down');
105
+
106
+ // If scroll still doesn't work, use Page Down directly
107
+ // await testdriver.pressKeys(['pagedown']);
108
+ ```
109
+ </Check>
110
+
111
+ <Check>
112
+ **Control scroll distance with the options object**
113
+
114
+ ```javascript
115
+ // For web pages, mouse scroll works well
116
+ await testdriver.scroll('down', { amount: 3 });
117
+
118
+ // For desktop apps or when mouse doesn't work, use keyboard
119
+ await testdriver.pressKeys(['pagedown']);
120
+ ```
121
+ </Check>
122
+
123
+ <Warning>
124
+ **Keyboard scroll uses Page Down/Up**
125
+
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.
127
+ </Warning>
128
+
129
+ ## Use Cases
130
+
131
+ <AccordionGroup>
132
+ <Accordion title="Infinite Scroll">
133
+ ```javascript
134
+ // Scroll multiple times for infinite scroll
135
+ for (let i = 0; i < 5; i++) {
136
+ await testdriver.scroll('down', { amount: 5 });
137
+ await new Promise(r => setTimeout(r, 1000)); // Wait for load
138
+ }
139
+ ```
140
+ </Accordion>
141
+
142
+ <Accordion title="Horizontal Gallery">
143
+ ```javascript
144
+ // Navigate horizontal carousel
145
+ await testdriver.scroll('right', { amount: 3 });
146
+ await new Promise(r => setTimeout(r, 500));
147
+
148
+ const nextImage = await testdriver.find('next image in carousel');
149
+ await nextImage.click();
150
+ ```
151
+ </Accordion>
152
+ </AccordionGroup>
153
+
154
+ ## Complete Example
155
+
156
+ ```javascript
157
+ import { beforeAll, afterAll, describe, it } from 'vitest';
158
+ import TestDriver from 'testdriverai';
159
+
160
+ describe('Scrolling', () => {
161
+ let testdriver;
162
+
163
+ beforeAll(async () => {
164
+ client = new TestDriver(process.env.TD_API_KEY);
165
+ await testdriver.auth();
166
+ await testdriver.connect();
167
+ });
168
+
169
+ afterAll(async () => {
170
+ await testdriver.disconnect();
171
+ });
172
+
173
+ it('should scroll to find elements', async () => {
174
+ await testdriver.focusApplication('Google Chrome');
175
+
176
+ // Scroll down the page
177
+ await testdriver.scroll('down', { amount: 5 });
178
+
179
+ // Click footer link
180
+ const privacyLink = await testdriver.find('Privacy Policy link');
181
+ await privacyLink.click();
182
+
183
+ await testdriver.assert('privacy policy page is displayed');
184
+ });
185
+
186
+ it('should handle infinite scroll', async () => {
187
+ await testdriver.focusApplication('Google Chrome');
188
+
189
+ // Scroll multiple times to load content
190
+ for (let i = 0; i < 3; i++) {
191
+ await testdriver.scroll('down', { amount: 5 });
192
+ await new Promise(r => setTimeout(r, 1500)); // Wait for load
193
+ }
194
+
195
+ // Verify content loaded
196
+ await testdriver.assert('more than 10 items are visible');
197
+ });
198
+ });
199
+ ```
200
+
201
+ ## Related Methods
202
+
203
+ - [`find()`](/v7/find) - Locate elements after scrolling
204
+ - [`pressKeys()`](/v7/press-keys) - Use Page Down/Up keys
205
+ - [`wait()`](/v7/wait) - Wait after scrolling