testdriverai 6.2.1 → 7.0.0

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 (264) hide show
  1. package/.github/workflows/acceptance-linux.yml +75 -0
  2. package/.github/workflows/acceptance-sdk-tests.yml +133 -0
  3. package/.vscode/settings.json +5 -1
  4. package/MIGRATION.md +389 -0
  5. package/PLUGIN_MIGRATION.md +222 -0
  6. package/PROMPT_CACHE.md +200 -0
  7. package/SDK_LOGGING.md +222 -0
  8. package/SDK_MIGRATION.md +474 -0
  9. package/SDK_README.md +1122 -0
  10. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  11. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  12. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  13. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  14. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  15. package/_testdriver/lifecycle/prerun.yaml +15 -0
  16. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  17. package/agent/index.js +258 -68
  18. package/agent/interface.js +15 -0
  19. package/agent/lib/cache.js +142 -0
  20. package/agent/lib/commander.js +1 -39
  21. package/agent/lib/commands.js +143 -188
  22. package/agent/lib/redraw.js +6 -3
  23. package/agent/lib/sandbox.js +19 -5
  24. package/agent/lib/sdk.js +1 -0
  25. package/agent/lib/system.js +0 -3
  26. package/agent/lib/validation.js +1 -7
  27. package/debug-locate-response.js +82 -0
  28. package/debug-screenshot-1763401388589.png +0 -0
  29. package/debugger/index.html +16 -5
  30. package/docs/ARCHITECTURE.md +424 -0
  31. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  32. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  33. package/docs/SDK_AWESOME_LOGS.md +468 -0
  34. package/docs/TEST_RECORDING.md +388 -0
  35. package/docs/docs.json +232 -152
  36. package/docs/sdk-browser-rendering.md +167 -0
  37. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  38. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  39. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  40. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  41. package/docs/v6/overview/comparison.mdx +101 -0
  42. package/docs/v7/README.md +135 -0
  43. package/docs/v7/api/ai.mdx +205 -0
  44. package/docs/v7/api/assert.mdx +285 -0
  45. package/docs/v7/api/assertions.mdx +403 -0
  46. package/docs/v7/api/click.mdx +287 -0
  47. package/docs/v7/api/client.mdx +322 -0
  48. package/docs/v7/api/elements.mdx +479 -0
  49. package/docs/v7/api/exec.mdx +346 -0
  50. package/docs/v7/api/find.mdx +316 -0
  51. package/docs/v7/api/focusApplication.mdx +294 -0
  52. package/docs/v7/api/hover.mdx +279 -0
  53. package/docs/v7/api/pressKeys.mdx +349 -0
  54. package/docs/v7/api/sandbox.mdx +404 -0
  55. package/docs/v7/api/scroll.mdx +300 -0
  56. package/docs/v7/api/type.mdx +314 -0
  57. package/docs/v7/commands/assert.mdx +45 -0
  58. package/docs/v7/commands/exec.mdx +282 -0
  59. package/docs/v7/commands/focus-application.mdx +44 -0
  60. package/docs/v7/commands/hover-image.mdx +69 -0
  61. package/docs/v7/commands/hover-text.mdx +47 -0
  62. package/docs/v7/commands/if.mdx +53 -0
  63. package/docs/v7/commands/match-image.mdx +67 -0
  64. package/docs/v7/commands/press-keys.mdx +87 -0
  65. package/docs/v7/commands/remember.mdx +49 -0
  66. package/docs/v7/commands/run.mdx +44 -0
  67. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  68. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  69. package/docs/v7/commands/scroll.mdx +69 -0
  70. package/docs/v7/commands/type.mdx +45 -0
  71. package/docs/v7/commands/wait-for-image.mdx +54 -0
  72. package/docs/v7/commands/wait-for-text.mdx +48 -0
  73. package/docs/v7/commands/wait.mdx +45 -0
  74. package/docs/v7/getting-started/quickstart.mdx +199 -0
  75. package/docs/v7/guides/migration.mdx +562 -0
  76. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  77. package/docs/v7/playwright.mdx +342 -0
  78. package/eslint.config.js +19 -1
  79. package/examples/run-tests-with-recording.sh +70 -0
  80. package/examples/screenshot-example.js +63 -0
  81. package/examples/sdk-awesome-logs-demo.js +177 -0
  82. package/examples/sdk-cache-thresholds.js +96 -0
  83. package/examples/sdk-element-properties.js +155 -0
  84. package/examples/sdk-simple-example.js +65 -0
  85. package/examples/test-recording-example.test.js +166 -0
  86. package/interfaces/cli/lib/base.js +10 -4
  87. package/interfaces/logger.js +2 -1
  88. package/interfaces/shared-test-state.mjs +69 -0
  89. package/interfaces/vitest-plugin.mjs +744 -0
  90. package/mcp-server/AI_GUIDELINES.md +57 -0
  91. package/package.json +18 -5
  92. package/schema.json +8 -29
  93. package/scripts/view-test-results.mjs +96 -0
  94. package/sdk-log-formatter.js +714 -0
  95. package/sdk.d.ts +735 -0
  96. package/sdk.js +1906 -0
  97. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  98. package/setup/aws/cloudformation.yaml +9 -2
  99. package/test/mcp-example-test.yaml +27 -0
  100. package/test-find-api.js +73 -0
  101. package/test-prompt-cache.js +96 -0
  102. package/test-sandbox-render.js +28 -0
  103. package/test-sdk-methods.js +15 -0
  104. package/test-sdk-refactor.js +53 -0
  105. package/test-stack-trace.mjs +57 -0
  106. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  107. package/testdriver/acceptance-sdk/README.md +128 -0
  108. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  109. package/testdriver/acceptance-sdk/assert.test.mjs +44 -0
  110. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +70 -0
  111. package/testdriver/acceptance-sdk/element-not-found.test.mjs +38 -0
  112. package/testdriver/acceptance-sdk/exec-js.test.mjs +55 -0
  113. package/testdriver/acceptance-sdk/exec-output.test.mjs +71 -0
  114. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +69 -0
  115. package/testdriver/acceptance-sdk/focus-window.test.mjs +48 -0
  116. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +41 -0
  117. package/testdriver/acceptance-sdk/hover-image.test.mjs +43 -0
  118. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +50 -0
  119. package/testdriver/acceptance-sdk/hover-text.test.mjs +41 -0
  120. package/testdriver/acceptance-sdk/match-image.test.mjs +48 -0
  121. package/testdriver/acceptance-sdk/press-keys.test.mjs +64 -0
  122. package/testdriver/acceptance-sdk/prompt.test.mjs +45 -0
  123. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +52 -0
  124. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +51 -0
  125. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +42 -0
  126. package/testdriver/acceptance-sdk/scroll.test.mjs +50 -0
  127. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  128. package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +239 -0
  129. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +648 -0
  130. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  131. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  132. package/testdriver/acceptance-sdk/type.test.mjs +84 -0
  133. package/verify-element-api.js +89 -0
  134. package/verify-types.js +0 -0
  135. package/vitest.config.example.js +19 -0
  136. package/vitest.config.mjs +65 -0
  137. package/vitest.config.mjs.bak +44 -0
  138. package/.github/workflows/acceptance-v6.yml +0 -169
  139. package/docs/overview/comparison.mdx +0 -82
  140. package/testdriver/lifecycle/prerun.yaml +0 -17
  141. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  142. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  143. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  144. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  145. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  146. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  147. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  148. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  149. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  150. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  151. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  152. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  153. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  154. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  155. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  156. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  157. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  158. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  159. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  160. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  161. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  162. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  163. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  164. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  165. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  166. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  167. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  168. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  169. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  170. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  171. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  172. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  173. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  174. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  175. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  176. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  177. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  178. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  179. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  180. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  181. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  182. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  183. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  184. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  185. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  186. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  187. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  188. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  189. /package/docs/{account → v6/account}/projects.mdx +0 -0
  190. /package/docs/{account → v6/account}/team.mdx +0 -0
  191. /package/docs/{action → v6/action}/ami.mdx +0 -0
  192. /package/docs/{action → v6/action}/performance.mdx +0 -0
  193. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  194. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  195. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  196. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  197. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  198. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  199. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  200. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  201. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  202. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  203. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  204. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  205. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  206. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  207. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  208. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  209. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  210. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  211. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  212. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  213. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  214. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  215. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  216. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  217. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  218. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  219. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  220. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  221. /package/docs/{features → v6/features}/generation.mdx +0 -0
  222. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  223. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  224. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  225. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  226. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  227. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  228. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  229. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  230. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  231. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  232. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  233. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  234. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  235. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  236. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  237. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  238. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  239. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  240. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  241. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  242. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  243. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  244. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  245. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  246. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  247. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  248. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  249. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  250. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  251. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  252. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  253. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  254. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  255. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  256. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  257. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  258. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  259. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  260. /package/docs/{security → v6/security}/action.mdx +0 -0
  261. /package/docs/{security → v6/security}/agent.mdx +0 -0
  262. /package/docs/{security → v6/security}/platform.mdx +0 -0
  263. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  264. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -0,0 +1,404 @@
1
+ ---
2
+ title: "Sandbox Management"
3
+ sidebarTitle: "Sandbox"
4
+ description: "Execute scripts and manage the sandbox environment"
5
+ icon: "server"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ The sandbox is a virtual machine where your tests run. You can execute shell commands, JavaScript, and manage applications within the sandbox environment.
11
+
12
+ ## Code Execution
13
+
14
+ ### exec()
15
+
16
+ Execute code or shell commands in the sandbox.
17
+
18
+ ```javascript
19
+ await testdriver.exec(language, code, timeout, silent)
20
+ ```
21
+
22
+ **Parameters:**
23
+ - `language` (string) - Language to execute: `'js'` (JavaScript) or `'pwsh'` (PowerShell)
24
+ - `code` (string) - Code or command to execute
25
+ - `timeout` (number) - Timeout in milliseconds
26
+ - `silent` (boolean, optional) - Suppress output if `true`
27
+
28
+ **Returns:** `Promise<string>` - Command output
29
+
30
+ ### JavaScript Execution
31
+
32
+ Execute JavaScript code in the browser context (Windows sandbox only).
33
+
34
+ ```javascript
35
+ // Execute JavaScript in the browser
36
+ const result = await testdriver.exec('js', 'document.title', 5000);
37
+ console.log('Page title:', result);
38
+
39
+ // Manipulate the DOM
40
+ await testdriver.exec('js', `
41
+ document.querySelector('#username').value = 'testuser';
42
+ `, 5000);
43
+
44
+ // Return data from the page
45
+ const elementText = await testdriver.exec('js', `
46
+ document.querySelector('.message').textContent
47
+ `, 5000);
48
+ ```
49
+
50
+ ### PowerShell Execution
51
+
52
+ Execute PowerShell commands in the Windows sandbox.
53
+
54
+ ```javascript
55
+ // Run a simple command
56
+ const output = await testdriver.exec('pwsh', 'Get-Process chrome', 5000);
57
+ console.log('Chrome processes:', output);
58
+
59
+ // Install software
60
+ await testdriver.exec('pwsh', 'npm install -g dashcam@beta', 10000);
61
+
62
+ // Start an application
63
+ await testdriver.exec('pwsh', `
64
+ Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "https://example.com"
65
+ `, 10000);
66
+
67
+ // File operations
68
+ await testdriver.exec('pwsh', 'New-Item -Path "C:\\test.txt" -ItemType File', 5000);
69
+ ```
70
+
71
+ ### Silent Execution
72
+
73
+ Use the `silent` parameter to suppress output for background operations:
74
+
75
+ ```javascript
76
+ // Silent installation
77
+ await testdriver.exec('pwsh', 'npm install -g some-package', 10000, true);
78
+
79
+ // Start background process
80
+ await testdriver.exec('pwsh', 'Start-Process notepad', 5000, true);
81
+ ```
82
+
83
+ ## Application Management
84
+
85
+ ### focusApplication()
86
+
87
+ Bring an application window to the foreground.
88
+
89
+ ```javascript
90
+ await testdriver.focusApplication(name)
91
+ ```
92
+
93
+ **Parameters:**
94
+ - `name` (string) - Application name (e.g., `'Google Chrome'`, `'Microsoft Edge'`, `'Notepad'`)
95
+
96
+ **Returns:** `Promise<string>` - Result message
97
+
98
+ **Example:**
99
+ ```javascript
100
+ // Focus Chrome browser
101
+ await testdriver.focusApplication('Google Chrome');
102
+
103
+ // Focus Edge
104
+ await testdriver.focusApplication('Microsoft Edge');
105
+
106
+ // Focus Notepad
107
+ await testdriver.focusApplication('Notepad');
108
+ ```
109
+
110
+ <Tip>
111
+ Call `focusApplication()` before interacting with UI elements to ensure the correct window is active.
112
+ </Tip>
113
+
114
+ ## Common Sandbox Operations
115
+
116
+ ### Installing Software
117
+
118
+ ```javascript
119
+ // Install npm package globally
120
+ await testdriver.exec('pwsh', 'npm install -g package-name', 30000);
121
+
122
+ // Install via Chocolatey (if available)
123
+ await testdriver.exec('pwsh', 'choco install firefox -y', 60000);
124
+
125
+ // Download and install
126
+ await testdriver.exec('pwsh', `
127
+ Invoke-WebRequest -Uri "https://example.com/installer.exe" -OutFile "C:\\installer.exe"
128
+ Start-Process -FilePath "C:\\installer.exe" -ArgumentList "/S" -Wait
129
+ `, 120000);
130
+ ```
131
+
132
+ ### File Operations
133
+
134
+ ```javascript
135
+ // Create a file
136
+ await testdriver.exec('pwsh', `
137
+ Set-Content -Path "C:\\test.txt" -Value "Hello World"
138
+ `, 5000);
139
+
140
+ // Read a file
141
+ const content = await testdriver.exec('pwsh', 'Get-Content -Path "C:\\test.txt"', 5000);
142
+
143
+ // Copy files
144
+ await testdriver.exec('pwsh', 'Copy-Item -Path "C:\\source.txt" -Destination "C:\\dest.txt"', 5000);
145
+
146
+ // Delete files
147
+ await testdriver.exec('pwsh', 'Remove-Item -Path "C:\\test.txt"', 5000);
148
+ ```
149
+
150
+ ### Environment Variables
151
+
152
+ ```javascript
153
+ // Set environment variable
154
+ await testdriver.exec('pwsh', '$env:MY_VAR = "value"', 5000);
155
+
156
+ // Get environment variable
157
+ const value = await testdriver.exec('pwsh', '$env:MY_VAR', 5000);
158
+
159
+ // Set persistent environment variable
160
+ await testdriver.exec('pwsh', '[Environment]::SetEnvironmentVariable("MY_VAR", "value", "User")', 5000);
161
+ ```
162
+
163
+ ### Network Operations
164
+
165
+ ```javascript
166
+ // Test connectivity
167
+ const pingResult = await testdriver.exec('pwsh', 'Test-NetConnection google.com', 10000);
168
+
169
+ // Download file
170
+ await testdriver.exec('pwsh', `
171
+ Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "C:\\Downloads\\file.zip"
172
+ `, 30000);
173
+
174
+ // Check if port is open
175
+ const portCheck = await testdriver.exec('pwsh', 'Test-NetConnection -ComputerName localhost -Port 3000', 5000);
176
+ ```
177
+
178
+ ### Process Management
179
+
180
+ ```javascript
181
+ // List running processes
182
+ const processes = await testdriver.exec('pwsh', 'Get-Process', 5000);
183
+
184
+ // Kill a process
185
+ await testdriver.exec('pwsh', 'Stop-Process -Name "chrome" -Force', 5000);
186
+
187
+ // Start a process and wait for it
188
+ await testdriver.exec('pwsh', 'Start-Process notepad -Wait', 30000);
189
+
190
+ // Start process with arguments
191
+ await testdriver.exec('pwsh', `
192
+ Start-Process "chrome.exe" -ArgumentList "--incognito", "https://example.com"
193
+ `, 5000);
194
+ ```
195
+
196
+ ## Browser Automation with JavaScript
197
+
198
+ ### DOM Manipulation
199
+
200
+ ```javascript
201
+ // Click an element
202
+ await testdriver.exec('js', `
203
+ document.querySelector('#submit-button').click();
204
+ `, 5000);
205
+
206
+ // Fill a form
207
+ await testdriver.exec('js', `
208
+ document.querySelector('#username').value = 'user@example.com';
209
+ document.querySelector('#password').value = 'secret';
210
+ document.querySelector('#login-form').submit();
211
+ `, 5000);
212
+
213
+ // Scroll to element
214
+ await testdriver.exec('js', `
215
+ document.querySelector('#footer').scrollIntoView();
216
+ `, 5000);
217
+ ```
218
+
219
+ ### Reading Page Data
220
+
221
+ ```javascript
222
+ // Get page title
223
+ const title = await testdriver.exec('js', 'document.title', 5000);
224
+
225
+ // Get all links
226
+ const links = await testdriver.exec('js', `
227
+ Array.from(document.querySelectorAll('a')).map(a => a.href).join('\\n')
228
+ `, 5000);
229
+
230
+ // Check if element exists
231
+ const exists = await testdriver.exec('js', `
232
+ document.querySelector('.error-message') !== null
233
+ `, 5000);
234
+
235
+ // Get element text
236
+ const text = await testdriver.exec('js', `
237
+ document.querySelector('.notification').textContent
238
+ `, 5000);
239
+ ```
240
+
241
+ ### Waiting for Conditions
242
+
243
+ ```javascript
244
+ // Wait for element to appear (using polling)
245
+ await testdriver.exec('js', `
246
+ await new Promise((resolve) => {
247
+ const interval = setInterval(() => {
248
+ if (document.querySelector('.loaded')) {
249
+ clearInterval(interval);
250
+ resolve();
251
+ }
252
+ }, 100);
253
+ });
254
+ `, 30000);
255
+
256
+ // Wait for page load
257
+ await testdriver.exec('js', `
258
+ if (document.readyState !== 'complete') {
259
+ await new Promise(resolve => window.addEventListener('load', resolve));
260
+ }
261
+ `, 10000);
262
+ ```
263
+
264
+ ## Complete Example
265
+
266
+ ```javascript
267
+ import { beforeAll, afterAll, describe, it } from 'vitest';
268
+ import TestDriver from 'testdriverai';
269
+
270
+ describe('Sandbox Operations', () => {
271
+ let testdriver;
272
+
273
+ beforeAll(async () => {
274
+ client = new TestDriver(process.env.TD_API_KEY, {
275
+ os: 'windows',
276
+ resolution: '1366x768'
277
+ });
278
+
279
+ await testdriver.auth();
280
+ await testdriver.connect({ newSandbox: true });
281
+ });
282
+
283
+ afterAll(async () => {
284
+ await testdriver.disconnect();
285
+ });
286
+
287
+ it('should install and use a tool', async () => {
288
+ // Install a tool
289
+ await testdriver.exec('pwsh', 'npm install -g http-server', 30000, true);
290
+
291
+ // Create a simple HTML file
292
+ await testdriver.exec('pwsh', `
293
+ Set-Content -Path "C:\\index.html" -Value "<h1>Hello World</h1>"
294
+ `, 5000);
295
+
296
+ // Start HTTP server (background process)
297
+ await testdriver.exec('pwsh', `
298
+ Start-Process pwsh -ArgumentList "-Command", "http-server C:\\ -p 8080"
299
+ `, 5000, true);
300
+
301
+ // Wait for server to start
302
+ await new Promise(resolve => setTimeout(resolve, 3000));
303
+
304
+ // Launch browser to view the page
305
+ await testdriver.exec('pwsh', `
306
+ Start-Process chrome -ArgumentList "http://localhost:8080"
307
+ `, 5000);
308
+
309
+ // Focus the browser
310
+ await testdriver.focusApplication('Google Chrome');
311
+
312
+ // Verify the page loaded
313
+ const pageText = await testdriver.exec('js', 'document.body.textContent', 5000);
314
+ expect(pageText).toContain('Hello World');
315
+ });
316
+
317
+ it('should manage files and processes', async () => {
318
+ // Create test file
319
+ await testdriver.exec('pwsh', `
320
+ "Test content" | Out-File -FilePath "C:\\test.txt"
321
+ `, 5000);
322
+
323
+ // Open file in notepad
324
+ await testdriver.exec('pwsh', 'Start-Process notepad C:\\test.txt', 5000);
325
+
326
+ // Focus notepad
327
+ await testdriver.focusApplication('Notepad');
328
+
329
+ // Wait a moment
330
+ await new Promise(resolve => setTimeout(resolve, 1000));
331
+
332
+ // Close notepad
333
+ await testdriver.exec('pwsh', 'Stop-Process -Name notepad -Force', 5000);
334
+ });
335
+ });
336
+ ```
337
+
338
+ ## Best Practices
339
+
340
+ <AccordionGroup>
341
+ <Accordion title="Use appropriate timeouts">
342
+ Set realistic timeouts based on the operation:
343
+
344
+ ```javascript
345
+ // Quick operations: 5000ms
346
+ await testdriver.exec('js', 'document.title', 5000);
347
+
348
+ // Installations: 30000-60000ms
349
+ await testdriver.exec('pwsh', 'npm install -g package', 30000);
350
+
351
+ // Downloads or complex operations: 60000-120000ms
352
+ await testdriver.exec('pwsh', 'Install-Module Something', 120000);
353
+ ```
354
+ </Accordion>
355
+
356
+ <Accordion title="Handle errors gracefully">
357
+ Wrap exec calls in try-catch for better error handling:
358
+
359
+ ```javascript
360
+ try {
361
+ await testdriver.exec('pwsh', 'Some-Command', 5000);
362
+ } catch (error) {
363
+ console.error('Command failed:', error.message);
364
+ // Fall back or retry
365
+ }
366
+ ```
367
+ </Accordion>
368
+
369
+ <Accordion title="Use silent mode for background operations">
370
+ Suppress output for installation and background tasks:
371
+
372
+ ```javascript
373
+ // Silent install
374
+ await testdriver.exec('pwsh', 'npm install -g tool', 30000, true);
375
+
376
+ // Background process
377
+ await testdriver.exec('pwsh', 'Start-Process app', 5000, true);
378
+ ```
379
+ </Accordion>
380
+
381
+ <Accordion title="Focus applications before interaction">
382
+ Always focus the target application before UI interactions:
383
+
384
+ ```javascript
385
+ await testdriver.focusApplication('Google Chrome');
386
+ const button = await testdriver.find('submit button');
387
+ await button.click();
388
+ ```
389
+ </Accordion>
390
+
391
+ <Accordion title="Escape strings properly in PowerShell">
392
+ Use proper escaping for special characters:
393
+
394
+ ```javascript
395
+ // Use backticks for newlines in PowerShell strings
396
+ await testdriver.exec('pwsh', `
397
+ Write-Host "Line 1\`nLine 2"
398
+ `, 5000);
399
+
400
+ // Use single quotes to avoid variable expansion
401
+ await testdriver.exec('pwsh', "Write-Host 'Text with $special chars'", 5000);
402
+ ```
403
+ </Accordion>
404
+ </AccordionGroup>
@@ -0,0 +1,300 @@
1
+ ---
2
+ title: "scroll()"
3
+ sidebarTitle: "scroll"
4
+ description: "Scroll pages and elements"
5
+ icon: "arrows-up-down"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Scroll the page or active element in any direction using mouse wheel or keyboard.
11
+
12
+ ## Syntax
13
+
14
+ ```javascript
15
+ await testdriver.scroll(direction, amount, method)
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ <ParamField path="direction" type="string" default="down">
21
+ Direction to scroll: `'up'`, `'down'`, `'left'`, `'right'`
22
+ </ParamField>
23
+
24
+ <ParamField path="amount" type="number" default="300">
25
+ Amount to scroll in pixels
26
+ </ParamField>
27
+
28
+ <ParamField path="method" type="string" default="mouse">
29
+ Scroll method: `'mouse'` or `'keyboard'`
30
+ </ParamField>
31
+
32
+ ## Returns
33
+
34
+ `Promise<void>`
35
+
36
+ ## Examples
37
+
38
+ ### Basic Scrolling
39
+
40
+ ```javascript
41
+ // Scroll down (default)
42
+ await testdriver.scroll();
43
+
44
+ // Scroll down 500 pixels
45
+ await testdriver.scroll('down', 500);
46
+
47
+ // Scroll up
48
+ await testdriver.scroll('up');
49
+
50
+ // Scroll up 200 pixels
51
+ await testdriver.scroll('up', 200);
52
+ ```
53
+
54
+ ### Horizontal Scrolling
55
+
56
+ ```javascript
57
+ // Scroll right
58
+ await testdriver.scroll('right', 300);
59
+
60
+ // Scroll left
61
+ await testdriver.scroll('left', 300);
62
+ ```
63
+
64
+ ### Scroll Methods
65
+
66
+ ```javascript
67
+ // Mouse wheel scroll (smooth, pixel-precise)
68
+ await testdriver.scroll('down', 300, 'mouse');
69
+
70
+ // Keyboard scroll (uses Page Down/Up, more compatible)
71
+ await testdriver.scroll('down', 300, 'keyboard');
72
+ ```
73
+
74
+ ## Scroll Until Found
75
+
76
+ ### scrollUntilText()
77
+
78
+ Scroll until specific text appears on screen.
79
+
80
+ ```javascript
81
+ await testdriver.scrollUntilText(text, direction, maxDistance, textMatchMethod, method, invert)
82
+ ```
83
+
84
+ **Parameters:**
85
+ - `text` (string) - Text to find
86
+ - `direction` (string) - Scroll direction (default: `'down'`)
87
+ - `maxDistance` (number) - Max pixels to scroll (default: 10000)
88
+ - `textMatchMethod` (string) - `'turbo'` or `'ai'` (default: `'turbo'`)
89
+ - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
90
+ - `invert` (boolean) - Scroll until text disappears (default: false)
91
+
92
+ **Examples:**
93
+ ```javascript
94
+ // Scroll down until "Contact Us" appears
95
+ await testdriver.scrollUntilText('Contact Us');
96
+
97
+ // Scroll up to find text
98
+ await testdriver.scrollUntilText('Header', 'up');
99
+
100
+ // Scroll until text disappears
101
+ await testdriver.scrollUntilText('Loading...', 'down', 5000, 'turbo', 'keyboard', true);
102
+
103
+ // Use AI matching for fuzzy text
104
+ await testdriver.scrollUntilText('footer content', 'down', 10000, 'ai');
105
+ ```
106
+
107
+ ### scrollUntilImage()
108
+
109
+ Scroll until a visual element appears.
110
+
111
+ ```javascript
112
+ await testdriver.scrollUntilImage(description, direction, maxDistance, method, path, invert)
113
+ ```
114
+
115
+ **Parameters:**
116
+ - `description` (string) - Description of the image/element
117
+ - `direction` (string) - Scroll direction (default: `'down'`)
118
+ - `maxDistance` (number) - Max pixels to scroll (default: 10000)
119
+ - `method` (string) - `'keyboard'` or `'mouse'` (default: `'keyboard'`)
120
+ - `path` (string | null) - Path to image template (optional)
121
+ - `invert` (boolean) - Scroll until image disappears (default: false)
122
+
123
+ **Examples:**
124
+ ```javascript
125
+ // Scroll until visual element appears
126
+ await testdriver.scrollUntilImage('red subscribe button');
127
+
128
+ // Scroll using image template
129
+ await testdriver.scrollUntilImage('', 'down', 10000, 'keyboard', './footer-logo.png');
130
+
131
+ // Scroll until image disappears
132
+ await testdriver.scrollUntilImage('loading spinner', 'down', 5000, 'keyboard', null, true);
133
+ ```
134
+
135
+ ## Best Practices
136
+
137
+ <Check>
138
+ **Choose the right scroll method**
139
+
140
+ ```javascript
141
+ // For web pages, mouse scroll is usually smoother
142
+ await testdriver.scroll('down', 300, 'mouse');
143
+
144
+ // For desktop apps or when mouse doesn't work
145
+ await testdriver.scroll('down', 300, 'keyboard');
146
+ ```
147
+ </Check>
148
+
149
+ <Check>
150
+ **Use scrollUntil for dynamic content**
151
+
152
+ ```javascript
153
+ // Instead of guessing scroll amount
154
+ await testdriver.scrollUntilText('Load More button');
155
+
156
+ const loadMoreBtn = await testdriver.find('Load More button');
157
+ await loadMoreBtn.click();
158
+ ```
159
+ </Check>
160
+
161
+ <Check>
162
+ **Set reasonable max distance**
163
+
164
+ ```javascript
165
+ // Avoid infinite scrolling
166
+ await testdriver.scrollUntilText('Footer', 'down', 5000); // Max 5000px
167
+ ```
168
+ </Check>
169
+
170
+ <Warning>
171
+ **Keyboard scroll uses Page Down/Up**
172
+
173
+ 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.
174
+ </Warning>
175
+
176
+ ## Use Cases
177
+
178
+ <AccordionGroup>
179
+ <Accordion title="Navigate to Footer">
180
+ ```javascript
181
+ // Scroll to bottom of page
182
+ await testdriver.scrollUntilText('Contact Us');
183
+
184
+ const contactLink = await testdriver.find('Contact Us link');
185
+ await contactLink.click();
186
+ ```
187
+ </Accordion>
188
+
189
+ <Accordion title="Load More Results">
190
+ ```javascript
191
+ // Scroll to load more button
192
+ await testdriver.scrollUntilText('Load More');
193
+
194
+ const loadBtn = await testdriver.find('Load More button');
195
+ await loadBtn.click();
196
+
197
+ await new Promise(r => setTimeout(r, 2000));
198
+ ```
199
+ </Accordion>
200
+
201
+ <Accordion title="Find Element in Long List">
202
+ ```javascript
203
+ // Scroll through list to find item
204
+ await testdriver.scrollUntilText('Product #42');
205
+
206
+ const product = await testdriver.find('Product #42');
207
+ await product.click();
208
+ ```
209
+ </Accordion>
210
+
211
+ <Accordion title="Infinite Scroll">
212
+ ```javascript
213
+ // Scroll multiple times for infinite scroll
214
+ for (let i = 0; i < 5; i++) {
215
+ await testdriver.scroll('down', 500);
216
+ await new Promise(r => setTimeout(r, 1000)); // Wait for load
217
+ }
218
+ ```
219
+ </Accordion>
220
+
221
+ <Accordion title="Horizontal Gallery">
222
+ ```javascript
223
+ // Navigate horizontal carousel
224
+ await testdriver.scroll('right', 300);
225
+ await new Promise(r => setTimeout(r, 500));
226
+
227
+ const nextImage = await testdriver.find('next image in carousel');
228
+ await nextImage.click();
229
+ ```
230
+ </Accordion>
231
+ </AccordionGroup>
232
+
233
+ ## Complete Example
234
+
235
+ ```javascript
236
+ import { beforeAll, afterAll, describe, it } from 'vitest';
237
+ import TestDriver from 'testdriverai';
238
+
239
+ describe('Scrolling', () => {
240
+ let testdriver;
241
+
242
+ beforeAll(async () => {
243
+ client = new TestDriver(process.env.TD_API_KEY);
244
+ await testdriver.auth();
245
+ await testdriver.connect({ newSandbox: true });
246
+ });
247
+
248
+ afterAll(async () => {
249
+ await testdriver.disconnect();
250
+ });
251
+
252
+ it('should scroll to find elements', async () => {
253
+ await testdriver.focusApplication('Google Chrome');
254
+
255
+ // Scroll to footer
256
+ await testdriver.scrollUntilText('Contact Information');
257
+
258
+ // Click footer link
259
+ const privacyLink = await testdriver.find('Privacy Policy link');
260
+ await privacyLink.click();
261
+
262
+ await testdriver.assert('privacy policy page is displayed');
263
+ });
264
+
265
+ it('should handle infinite scroll', async () => {
266
+ await testdriver.focusApplication('Google Chrome');
267
+
268
+ // Scroll multiple times to load content
269
+ for (let i = 0; i < 3; i++) {
270
+ await testdriver.scroll('down', 500);
271
+ await new Promise(r => setTimeout(r, 1500)); // Wait for load
272
+ }
273
+
274
+ // Verify content loaded
275
+ await testdriver.assert('more than 10 items are visible');
276
+ });
277
+
278
+ it('should scroll until loading completes', async () => {
279
+ // Scroll until loading spinner disappears
280
+ await testdriver.scrollUntilImage(
281
+ 'loading spinner',
282
+ 'down',
283
+ 5000,
284
+ 'keyboard',
285
+ null,
286
+ true // invert - wait for it to disappear
287
+ );
288
+
289
+ // Now interact with loaded content
290
+ const firstResult = await testdriver.find('first search result');
291
+ await firstResult.click();
292
+ });
293
+ });
294
+ ```
295
+
296
+ ## Related Methods
297
+
298
+ - [`find()`](/v7/api/find) - Locate elements after scrolling
299
+ - [`pressKeys()`](/v7/api/pressKeys) - Use Page Down/Up keys
300
+ - [`wait()`](/v7/api/wait) - Wait after scrolling