testdriverai 6.2.2 → 7.1.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 (300) 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/AGENTS.md +550 -0
  5. package/CODEOWNERS +0 -1
  6. package/README.md +126 -0
  7. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  8. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  9. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  10. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  11. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  12. package/_testdriver/lifecycle/prerun.yaml +15 -0
  13. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  14. package/agent/index.js +300 -85
  15. package/agent/interface.js +15 -0
  16. package/agent/lib/cache.js +142 -0
  17. package/agent/lib/commander.js +1 -39
  18. package/agent/lib/commands.js +910 -296
  19. package/agent/lib/redraw.js +129 -41
  20. package/agent/lib/sandbox.js +29 -6
  21. package/agent/lib/sdk.js +22 -0
  22. package/agent/lib/system.js +0 -3
  23. package/agent/lib/validation.js +1 -7
  24. package/debug-locate-response.js +82 -0
  25. package/debugger/index.html +15 -4
  26. package/docs/ARCHITECTURE.md +424 -0
  27. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  28. package/docs/MIGRATION.md +425 -0
  29. package/docs/PRESETS.md +210 -0
  30. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  31. package/docs/SDK_AWESOME_LOGS.md +468 -0
  32. package/docs/TEST_RECORDING.md +388 -0
  33. package/docs/docs.json +286 -152
  34. package/docs/guide/best-practices-polling.mdx +154 -0
  35. package/docs/sdk-browser-rendering.md +167 -0
  36. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  37. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  38. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  39. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  40. package/docs/v6/overview/comparison.mdx +101 -0
  41. package/docs/v7/README.md +135 -0
  42. package/docs/v7/api/ai.mdx +205 -0
  43. package/docs/v7/api/assert.mdx +285 -0
  44. package/docs/v7/api/assertions.mdx +403 -0
  45. package/docs/v7/api/click.mdx +287 -0
  46. package/docs/v7/api/client.mdx +322 -0
  47. package/docs/v7/api/dashcam.mdx +497 -0
  48. package/docs/v7/api/doubleClick.mdx +102 -0
  49. package/docs/v7/api/elements.mdx +479 -0
  50. package/docs/v7/api/exec.mdx +346 -0
  51. package/docs/v7/api/find.mdx +316 -0
  52. package/docs/v7/api/focusApplication.mdx +294 -0
  53. package/docs/v7/api/hover.mdx +279 -0
  54. package/docs/v7/api/mouseDown.mdx +161 -0
  55. package/docs/v7/api/mouseUp.mdx +164 -0
  56. package/docs/v7/api/pressKeys.mdx +349 -0
  57. package/docs/v7/api/rightClick.mdx +123 -0
  58. package/docs/v7/api/sandbox.mdx +404 -0
  59. package/docs/v7/api/scroll.mdx +300 -0
  60. package/docs/v7/api/type.mdx +314 -0
  61. package/docs/v7/commands/assert.mdx +45 -0
  62. package/docs/v7/commands/exec.mdx +282 -0
  63. package/docs/v7/commands/focus-application.mdx +44 -0
  64. package/docs/v7/commands/hover-image.mdx +69 -0
  65. package/docs/v7/commands/hover-text.mdx +47 -0
  66. package/docs/v7/commands/if.mdx +53 -0
  67. package/docs/v7/commands/match-image.mdx +67 -0
  68. package/docs/v7/commands/press-keys.mdx +87 -0
  69. package/docs/v7/commands/remember.mdx +49 -0
  70. package/docs/v7/commands/run.mdx +44 -0
  71. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  72. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  73. package/docs/v7/commands/scroll.mdx +69 -0
  74. package/docs/v7/commands/type.mdx +45 -0
  75. package/docs/v7/commands/wait-for-image.mdx +54 -0
  76. package/docs/v7/commands/wait-for-text.mdx +48 -0
  77. package/docs/v7/commands/wait.mdx +45 -0
  78. package/docs/v7/getting-started/configuration.mdx +380 -0
  79. package/docs/v7/getting-started/quickstart.mdx +332 -0
  80. package/docs/v7/guides/best-practices.mdx +486 -0
  81. package/docs/v7/guides/caching-ai.mdx +215 -0
  82. package/docs/v7/guides/caching-selectors.mdx +292 -0
  83. package/docs/v7/guides/caching.mdx +366 -0
  84. package/docs/v7/guides/ci-cd/azure.mdx +587 -0
  85. package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
  86. package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
  87. package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
  88. package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
  89. package/docs/v7/guides/ci-cd/travis.mdx +438 -0
  90. package/docs/v7/guides/debugging.mdx +349 -0
  91. package/docs/v7/guides/faq.mdx +393 -0
  92. package/docs/v7/guides/migration.mdx +562 -0
  93. package/docs/v7/guides/performance.mdx +517 -0
  94. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  95. package/docs/v7/guides/troubleshooting.mdx +526 -0
  96. package/docs/v7/guides/vitest-plugin.mdx +477 -0
  97. package/docs/v7/guides/vitest.mdx +535 -0
  98. package/docs/v7/platforms/linux.mdx +308 -0
  99. package/docs/v7/platforms/macos.mdx +433 -0
  100. package/docs/v7/platforms/windows.mdx +430 -0
  101. package/docs/v7/playwright.mdx +342 -0
  102. package/docs/v7/presets/chrome-extension.mdx +223 -0
  103. package/docs/v7/presets/chrome.mdx +287 -0
  104. package/docs/v7/presets/electron.mdx +435 -0
  105. package/docs/v7/presets/vscode.mdx +398 -0
  106. package/docs/v7/presets/webapp.mdx +396 -0
  107. package/docs/v7/progressive-apis/CORE.md +459 -0
  108. package/docs/v7/progressive-apis/HOOKS.md +360 -0
  109. package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
  110. package/docs/v7/progressive-apis/PROVISION.md +266 -0
  111. package/eslint.config.js +19 -1
  112. package/interfaces/cli/lib/base.js +10 -4
  113. package/interfaces/logger.js +2 -1
  114. package/interfaces/shared-test-state.mjs +69 -0
  115. package/interfaces/vitest-plugin.mjs +830 -0
  116. package/package.json +29 -5
  117. package/schema.json +8 -29
  118. package/scripts/view-test-results.mjs +96 -0
  119. package/sdk-log-formatter.js +714 -0
  120. package/sdk.d.ts +1028 -0
  121. package/sdk.js +2567 -0
  122. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  123. package/setup/aws/cloudformation.yaml +9 -2
  124. package/src/core/Dashcam.js +469 -0
  125. package/src/core/index.d.ts +150 -0
  126. package/src/core/index.js +12 -0
  127. package/src/presets/index.mjs +331 -0
  128. package/src/vitest/extended.mjs +108 -0
  129. package/src/vitest/hooks.d.ts +119 -0
  130. package/src/vitest/hooks.mjs +298 -0
  131. package/src/vitest/index.mjs +64 -0
  132. package/src/vitest/lifecycle.mjs +277 -0
  133. package/src/vitest/utils.mjs +150 -0
  134. package/test/dashcam.test.js +137 -0
  135. package/test/mcp-example-test.yaml +27 -0
  136. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  137. package/testdriver/acceptance-sdk/README.md +128 -0
  138. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  139. package/testdriver/acceptance-sdk/assert.test.mjs +26 -0
  140. package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
  141. package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
  142. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +58 -0
  143. package/testdriver/acceptance-sdk/element-not-found.test.mjs +25 -0
  144. package/testdriver/acceptance-sdk/exec-js.test.mjs +43 -0
  145. package/testdriver/acceptance-sdk/exec-output.test.mjs +59 -0
  146. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +57 -0
  147. package/testdriver/acceptance-sdk/focus-window.test.mjs +36 -0
  148. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +26 -0
  149. package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
  150. package/testdriver/acceptance-sdk/hover-image.test.mjs +34 -0
  151. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +38 -0
  152. package/testdriver/acceptance-sdk/hover-text.test.mjs +27 -0
  153. package/testdriver/acceptance-sdk/match-image.test.mjs +36 -0
  154. package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
  155. package/testdriver/acceptance-sdk/press-keys.test.mjs +50 -0
  156. package/testdriver/acceptance-sdk/prompt.test.mjs +33 -0
  157. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +38 -0
  158. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +39 -0
  159. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +28 -0
  160. package/testdriver/acceptance-sdk/scroll.test.mjs +41 -0
  161. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  162. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +420 -0
  163. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  164. package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
  165. package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
  166. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  167. package/testdriver/acceptance-sdk/type.test.mjs +45 -0
  168. package/verify-element-api.js +89 -0
  169. package/verify-types.js +0 -0
  170. package/vitest.config.example.js +19 -0
  171. package/vitest.config.mjs +66 -0
  172. package/vitest.config.mjs.bak +44 -0
  173. package/.github/workflows/acceptance-v6.yml +0 -169
  174. package/.vscode/mcp.json +0 -9
  175. package/docs/overview/comparison.mdx +0 -82
  176. package/testdriver/lifecycle/prerun.yaml +0 -17
  177. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  178. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  179. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  180. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  181. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  182. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  183. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  184. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  185. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  186. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  187. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  188. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  189. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  190. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  191. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  192. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  193. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  194. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  195. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  196. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  197. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  198. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  199. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  200. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  201. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  202. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  203. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  204. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  205. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  206. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  207. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  208. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  209. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  210. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  211. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  212. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  213. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  214. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  215. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  216. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  217. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  218. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  219. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  220. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  221. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  222. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  223. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  224. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  225. /package/docs/{account → v6/account}/projects.mdx +0 -0
  226. /package/docs/{account → v6/account}/team.mdx +0 -0
  227. /package/docs/{action → v6/action}/ami.mdx +0 -0
  228. /package/docs/{action → v6/action}/performance.mdx +0 -0
  229. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  230. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  231. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  232. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  233. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  234. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  235. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  236. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  237. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  238. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  239. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  240. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  241. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  242. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  243. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  244. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  245. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  246. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  247. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  248. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  249. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  250. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  251. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  252. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  253. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  254. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  255. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  256. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  257. /package/docs/{features → v6/features}/generation.mdx +0 -0
  258. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  259. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  260. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  261. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  262. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  263. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  264. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  265. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  266. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  267. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  268. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  269. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  270. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  271. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  272. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  273. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  274. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  275. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  276. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  277. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  278. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  279. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  280. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  281. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  282. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  283. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  284. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  285. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  286. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  287. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  288. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  289. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  290. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  291. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  292. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  293. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  294. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  295. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  296. /package/docs/{security → v6/security}/action.mdx +0 -0
  297. /package/docs/{security → v6/security}/agent.mdx +0 -0
  298. /package/docs/{security → v6/security}/platform.mdx +0 -0
  299. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  300. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -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
@@ -0,0 +1,314 @@
1
+ ---
2
+ title: "type()"
3
+ sidebarTitle: "type"
4
+ description: "Type text into focused input fields"
5
+ icon: "keyboard"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Type text or numbers into the currently focused input field with optional delay between keystrokes.
11
+
12
+ ## Syntax
13
+
14
+ ```javascript
15
+ await testdriver.type(text, delay)
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ <ParamField path="text" type="string | number" required>
21
+ Text to type (can be a string or number)
22
+ </ParamField>
23
+
24
+ <ParamField path="delay" type="number" default="250">
25
+ Delay between keystrokes in milliseconds
26
+ </ParamField>
27
+
28
+ ## Returns
29
+
30
+ `Promise<void>`
31
+
32
+ ## Examples
33
+
34
+ ### Basic Typing
35
+
36
+ ```javascript
37
+ // Type text
38
+ await testdriver.type('hello@example.com');
39
+
40
+ // Type numbers
41
+ await testdriver.type(12345);
42
+
43
+ // Type with custom delay
44
+ await testdriver.type('slow typing', 500); // 500ms between each character
45
+ ```
46
+
47
+ ### Form Filling
48
+
49
+ ```javascript
50
+ // Focus field and type
51
+ const emailField = await testdriver.find('email input');
52
+ await emailField.click();
53
+ await testdriver.type('user@example.com');
54
+
55
+ // Tab to next field and type
56
+ await testdriver.pressKeys(['tab']);
57
+ await testdriver.type('John Doe');
58
+
59
+ // Type password
60
+ await testdriver.pressKeys(['tab']);
61
+ await testdriver.type('MySecureP@ssw0rd');
62
+ ```
63
+
64
+ ### Clearing and Replacing Text
65
+
66
+ ```javascript
67
+ const searchBox = await testdriver.find('search input');
68
+ await searchBox.click();
69
+
70
+ // Clear existing text
71
+ await testdriver.pressKeys(['ctrl', 'a']); // Select all
72
+ await testdriver.type('new search query');
73
+ ```
74
+
75
+ ## Best Practices
76
+
77
+ <Check>
78
+ **Focus the field first**
79
+
80
+ Always click the input field or navigate to it before typing:
81
+
82
+ ```javascript
83
+ const input = await testdriver.find('username input');
84
+ await input.click();
85
+ await testdriver.type('testuser');
86
+ ```
87
+ </Check>
88
+
89
+ <Check>
90
+ **Use Tab for navigation**
91
+
92
+ Navigate between fields using Tab instead of clicking each one:
93
+
94
+ ```javascript
95
+ const firstField = await testdriver.find('first name');
96
+ await firstField.click();
97
+ await testdriver.type('John');
98
+
99
+ await testdriver.pressKeys(['tab']);
100
+ await testdriver.type('Doe');
101
+
102
+ await testdriver.pressKeys(['tab']);
103
+ await testdriver.type('john@example.com');
104
+ ```
105
+ </Check>
106
+
107
+ <Check>
108
+ **Clear fields before typing**
109
+
110
+ Clear existing content to avoid appending:
111
+
112
+ ```javascript
113
+ const input = await testdriver.find('search field');
114
+ await input.click();
115
+ await testdriver.pressKeys(['ctrl', 'a']); // Select all
116
+ await testdriver.type('new search');
117
+ ```
118
+ </Check>
119
+
120
+ <Warning>
121
+ **Field must be focused**
122
+
123
+ Typing will only work if an input field is currently focused. If no field is focused, the text may be lost or trigger unexpected keyboard shortcuts.
124
+ </Warning>
125
+
126
+ ## Use Cases
127
+
128
+ <AccordionGroup>
129
+ <Accordion title="Login Forms">
130
+ ```javascript
131
+ await testdriver.focusApplication('Google Chrome');
132
+
133
+ const usernameField = await testdriver.find('username input');
134
+ await usernameField.click();
135
+ await testdriver.type('testuser@example.com');
136
+
137
+ await testdriver.pressKeys(['tab']);
138
+ await testdriver.type('MyP@ssword123');
139
+
140
+ await testdriver.pressKeys(['enter']);
141
+ ```
142
+ </Accordion>
143
+
144
+ <Accordion title="Search Fields">
145
+ ```javascript
146
+ const searchBox = await testdriver.find('search input');
147
+ await searchBox.click();
148
+ await testdriver.type('laptop computers');
149
+ await testdriver.pressKeys(['enter']);
150
+
151
+ // Wait for results
152
+ await new Promise(r => setTimeout(r, 2000));
153
+ ```
154
+ </Accordion>
155
+
156
+ <Accordion title="Multi-Field Forms">
157
+ ```javascript
158
+ // First field
159
+ const nameField = await testdriver.find('full name input');
160
+ await nameField.click();
161
+ await testdriver.type('Jane Smith');
162
+
163
+ // Navigate with Tab
164
+ await testdriver.pressKeys(['tab']);
165
+ await testdriver.type('jane.smith@example.com');
166
+
167
+ await testdriver.pressKeys(['tab']);
168
+ await testdriver.type('+1-555-0123');
169
+
170
+ await testdriver.pressKeys(['tab']);
171
+ await testdriver.type('123 Main Street');
172
+ ```
173
+ </Accordion>
174
+
175
+ <Accordion title="Text Editors">
176
+ ```javascript
177
+ const editor = await testdriver.find('text editor area');
178
+ await editor.click();
179
+
180
+ await testdriver.type('# My Document', 100);
181
+ await testdriver.pressKeys(['enter', 'enter']);
182
+ await testdriver.type('This is the first paragraph.', 50);
183
+ ```
184
+ </Accordion>
185
+
186
+ <Accordion title="Numeric Input">
187
+ ```javascript
188
+ const quantityField = await testdriver.find('quantity input');
189
+ await quantityField.click();
190
+
191
+ // Clear field
192
+ await testdriver.pressKeys(['ctrl', 'a']);
193
+
194
+ // Type number
195
+ await testdriver.type(5);
196
+ ```
197
+ </Accordion>
198
+ </AccordionGroup>
199
+
200
+ ## Typing Speed
201
+
202
+ Adjust the delay parameter based on your needs:
203
+
204
+ ```javascript
205
+ // Fast typing (100ms delay)
206
+ await testdriver.type('quick entry', 100);
207
+
208
+ // Normal typing (250ms - default)
209
+ await testdriver.type('standard speed');
210
+
211
+ // Slow typing (500ms delay) - useful for fields with live validation
212
+ await testdriver.type('slow and steady', 500);
213
+
214
+ // Very slow (1000ms delay) - for problematic fields
215
+ await testdriver.type('one by one', 1000);
216
+ ```
217
+
218
+ <Note>
219
+ Some applications with live validation or autocomplete may require slower typing speeds to avoid race conditions.
220
+ </Note>
221
+
222
+ ## Special Characters
223
+
224
+ ```javascript
225
+ // Email addresses
226
+ await testdriver.type('user@example.com');
227
+
228
+ // URLs
229
+ await testdriver.type('https://example.com/path?query=value');
230
+
231
+ // Passwords with special characters
232
+ await testdriver.type('P@ssw0rd!#$%');
233
+
234
+ // Paths
235
+ await testdriver.type('C:\\Users\\Documents\\file.txt');
236
+
237
+ // Multi-line text (use pressKeys for Enter)
238
+ await testdriver.type('Line 1');
239
+ await testdriver.pressKeys(['enter']);
240
+ await testdriver.type('Line 2');
241
+ ```
242
+
243
+ ## Complete Example
244
+
245
+ ```javascript
246
+ import { beforeAll, afterAll, describe, it, expect } from 'vitest';
247
+ import TestDriver from 'testdriverai';
248
+
249
+ describe('Form Filling with Type', () => {
250
+ let testdriver;
251
+
252
+ beforeAll(async () => {
253
+ client = new TestDriver(process.env.TD_API_KEY);
254
+ await testdriver.auth();
255
+ await testdriver.connect({ newSandbox: true });
256
+ });
257
+
258
+ afterAll(async () => {
259
+ await testdriver.disconnect();
260
+ });
261
+
262
+ it('should fill out registration form', async () => {
263
+ await testdriver.focusApplication('Google Chrome');
264
+
265
+ // Email field
266
+ const emailField = await testdriver.find('email input field');
267
+ await emailField.click();
268
+ await testdriver.type('john.doe@example.com');
269
+
270
+ // Tab through form fields
271
+ await testdriver.pressKeys(['tab']);
272
+ await testdriver.type('John');
273
+
274
+ await testdriver.pressKeys(['tab']);
275
+ await testdriver.type('Doe');
276
+
277
+ await testdriver.pressKeys(['tab']);
278
+ await testdriver.type('MySecureP@ssword123');
279
+
280
+ await testdriver.pressKeys(['tab']);
281
+ await testdriver.type('MySecureP@ssword123'); // Confirm password
282
+
283
+ // Verify fields were filled
284
+ const result = await testdriver.assert('all form fields are filled');
285
+ expect(result).toBeTruthy();
286
+ });
287
+
288
+ it('should update search query', async () => {
289
+ const searchBox = await testdriver.find('search input');
290
+ await searchBox.click();
291
+
292
+ // Type initial search
293
+ await testdriver.type('laptops');
294
+ await testdriver.pressKeys(['enter']);
295
+
296
+ await new Promise(r => setTimeout(r, 2000));
297
+
298
+ // Update search
299
+ await searchBox.click();
300
+ await testdriver.pressKeys(['ctrl', 'a']); // Select all
301
+ await testdriver.type('gaming laptops');
302
+ await testdriver.pressKeys(['enter']);
303
+
304
+ // Verify new search
305
+ await testdriver.assert('search results for "gaming laptops" are shown');
306
+ });
307
+ });
308
+ ```
309
+
310
+ ## Related Methods
311
+
312
+ - [`pressKeys()`](/v7/api/pressKeys) - Press keyboard keys and shortcuts
313
+ - [`find()`](/v7/api/find) - Locate input fields
314
+ - [`click()`](/v7/api/click) - Focus input fields
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: "assert"
3
+ sidebarTitle: "assert"
4
+ description: "Validate conditions during a test using the assert command."
5
+ icon: "check"
6
+ mode: "wide"
7
+ ---
8
+
9
+ import Replay from "/snippets/tests/assert-replay.mdx";
10
+ import Example from "/snippets/tests/assert-yaml.mdx";
11
+
12
+ <Replay />
13
+ <Example />
14
+
15
+ ## Description
16
+
17
+ The `assert` command validates that a specific condition is true. It ensures that a task completed successfully by checking the screen for the expected outcome. If the condition isn't met, the test will fail.
18
+
19
+ ## Arguments
20
+
21
+ | Argument | Type | Description |
22
+ | -------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
23
+ | `expect` | `string` | The condition to check. This should describe what you expect to see on the screen. |
24
+ | `async` | `boolean` | (Optional) If set to `true`, the test will continue without waiting for the assertion to pass. Default is `false`. |
25
+ | `invert` | `boolean` | (Optional) If set to `true`, will fail if the assertion passes. |
26
+
27
+ ## Example usage
28
+
29
+ ```yaml
30
+ command: assert
31
+ expect: the video is playing
32
+ ```
33
+
34
+ ### Example with `async`
35
+
36
+ ```yaml
37
+ command: assert
38
+ expect: There is no error message
39
+ async: true
40
+ ```
41
+
42
+ ## Notes
43
+
44
+ - Use `async: true` to speed up tests by allowing non-blocking assertions. However, the test will still fail if the condition isn't met.
45
+ - Ensure the `expect` string clearly describes the condition to avoid ambiguity.