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,161 @@
1
+ ---
2
+ title: "mouseDown"
3
+ description: "Press the mouse button without releasing it"
4
+ icon: "arrow-pointer"
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ The `mouseDown()` method presses the mouse button at an element's location without releasing it. This is useful for drag operations, custom gestures, or when you need precise control over mouse events. You can either call it on an [`Element`](/v7/core-concepts/elements) instance or use it directly with a selector.
10
+
11
+ ## Syntax
12
+
13
+ ```javascript
14
+ // Mouse down on an element
15
+ await element.mouseDown();
16
+
17
+ // Mouse down using a selector
18
+ await ai.mouseDown('selector');
19
+ ```
20
+
21
+ ## Parameters
22
+
23
+ When called on an `Element`, no parameters are required.
24
+
25
+ When called directly on the AI client:
26
+
27
+ | Parameter | Type | Description |
28
+ |-----------|------|-------------|
29
+ | `selector` | `string` | The selector describing the element where the mouse button should be pressed |
30
+
31
+ ## Returns
32
+
33
+ Returns a `Promise<void>` that resolves when the mouse button is pressed.
34
+
35
+ ## Examples
36
+
37
+ ### Basic Drag Operation
38
+
39
+ ```javascript
40
+ // Start dragging an item
41
+ const dragItem = await ai.find('file to drag');
42
+ await dragItem.mouseDown();
43
+
44
+ // Move to drop target
45
+ const dropTarget = await ai.find('folder to drop into');
46
+ await dropTarget.hover();
47
+
48
+ // Release
49
+ await ai.mouseUp();
50
+ ```
51
+
52
+ ### Drag and Drop with Direct Selectors
53
+
54
+ ```javascript
55
+ await ai.mouseDown('draggable card');
56
+ await ai.hover('drop zone');
57
+ await ai.mouseUp();
58
+ ```
59
+
60
+ ### Selecting Multiple Items
61
+
62
+ ```javascript
63
+ import { test } from 'vitest';
64
+ import { chrome } from '@testdriver/sdk';
65
+
66
+ test('selects multiple items with click and drag', async () => {
67
+ const { ai } = await chrome('https://app.example.com');
68
+
69
+ // Start selection at first item
70
+ await ai.mouseDown('first item in grid');
71
+
72
+ // Drag to last item
73
+ await ai.hover('last item in grid');
74
+
75
+ // Release to complete selection
76
+ await ai.mouseUp();
77
+
78
+ // Verify multiple items selected
79
+ const selectedItems = await ai.find('selected items count');
80
+ expect(selectedItems.text).toContain('5 items selected');
81
+ });
82
+ ```
83
+
84
+ ### Custom Drawing Application
85
+
86
+ ```javascript
87
+ test('draws on canvas', async () => {
88
+ const { ai } = await chrome('https://drawing-app.example.com');
89
+
90
+ // Start drawing
91
+ await ai.mouseDown('canvas at top-left corner');
92
+
93
+ // Draw a line by moving mouse
94
+ await ai.hover('canvas at center');
95
+ await ai.hover('canvas at bottom-right corner');
96
+
97
+ // Stop drawing
98
+ await ai.mouseUp();
99
+
100
+ // Verify something was drawn
101
+ const canvas = await ai.exec('document.querySelector("canvas").toDataURL()');
102
+ expect(canvas).toBeTruthy();
103
+ });
104
+ ```
105
+
106
+ ### Long Press Gesture
107
+
108
+ ```javascript
109
+ test('triggers long press menu', async () => {
110
+ const { ai } = await chrome('https://mobile-app.example.com');
111
+
112
+ // Press and hold
113
+ await ai.mouseDown('message in chat');
114
+
115
+ // Wait for long-press menu
116
+ await new Promise(resolve => setTimeout(resolve, 500));
117
+
118
+ // Verify menu appeared before releasing
119
+ const menu = await ai.find('message options menu');
120
+ expect(menu).toBeTruthy();
121
+
122
+ // Release
123
+ await ai.mouseUp();
124
+ });
125
+ ```
126
+
127
+ ### Resizing UI Elements
128
+
129
+ ```javascript
130
+ test('resizes panel', async () => {
131
+ const { ai } = await vscode();
132
+
133
+ // Grab resize handle
134
+ await ai.mouseDown('sidebar resize handle');
135
+
136
+ // Drag to new position
137
+ await ai.hover('position 300 pixels from left edge');
138
+
139
+ // Release
140
+ await ai.mouseUp();
141
+
142
+ // Verify new size
143
+ const sidebar = await ai.find('sidebar');
144
+ expect(sidebar.width).toBeGreaterThan(250);
145
+ });
146
+ ```
147
+
148
+ ## Important Notes
149
+
150
+ - Always pair `mouseDown()` with [`mouseUp()`](/v7/api/mouseUp) to complete the gesture
151
+ - The mouse button remains pressed until `mouseUp()` is called
152
+ - Use [`hover()`](/v7/api/hover) to move the mouse while the button is pressed
153
+ - For simple drag operations, consider using `ai()` with a natural language description like `"drag file to folder"`
154
+
155
+ ## Related Methods
156
+
157
+ - [`mouseUp()`](/v7/api/mouseUp) - Release the mouse button
158
+ - [`hover()`](/v7/api/hover) - Move mouse to element
159
+ - [`click()`](/v7/api/click) - Full click (mouseDown + mouseUp)
160
+ - [`doubleClick()`](/v7/api/doubleClick) - Double-click on element
161
+ - [`rightClick()`](/v7/api/rightClick) - Right-click for context menu
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: "mouseUp"
3
+ description: "Release the mouse button"
4
+ icon: "arrow-pointer"
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ The `mouseUp()` method releases the mouse button, completing a drag operation or custom mouse gesture that was started with [`mouseDown()`](/v7/api/mouseDown). You can call it without parameters to release at the current mouse position.
10
+
11
+ ## Syntax
12
+
13
+ ```javascript
14
+ // Release mouse button at current position
15
+ await ai.mouseUp();
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ None. The mouse button is released at the current cursor position.
21
+
22
+ ## Returns
23
+
24
+ Returns a `Promise<void>` that resolves when the mouse button is released.
25
+
26
+ ## Examples
27
+
28
+ ### Complete Drag and Drop
29
+
30
+ ```javascript
31
+ // Start dragging
32
+ await ai.mouseDown('file to drag');
33
+
34
+ // Move to drop location
35
+ await ai.hover('target folder');
36
+
37
+ // Complete the drop
38
+ await ai.mouseUp();
39
+ ```
40
+
41
+ ### Selecting Multiple Files
42
+
43
+ ```javascript
44
+ import { test } from 'vitest';
45
+ import { vscode } from '@testdriver/sdk';
46
+
47
+ test('selects range of files', async () => {
48
+ const { ai } = await vscode();
49
+
50
+ // Click first file
51
+ await ai.click('first-file.js in explorer');
52
+
53
+ // Hold shift and click last file
54
+ await ai.pressKeys('Shift');
55
+ await ai.mouseDown('last-file.js in explorer');
56
+ await ai.mouseUp();
57
+
58
+ // Verify multiple files selected
59
+ const selectedCount = await ai.find('status bar showing file count');
60
+ expect(selectedCount.text).toContain('5 files');
61
+ });
62
+ ```
63
+
64
+ ### Drawing Application
65
+
66
+ ```javascript
67
+ test('draws a shape', async () => {
68
+ const { ai } = await chrome('https://drawing-app.example.com');
69
+
70
+ // Select pencil tool
71
+ await ai.click('pencil tool');
72
+
73
+ // Draw a line
74
+ await ai.mouseDown('canvas near top-left');
75
+ await ai.hover('canvas center');
76
+ await ai.hover('canvas bottom-right');
77
+ await ai.mouseUp();
78
+
79
+ // Verify drawing exists
80
+ const strokes = await ai.exec('canvas.getContext("2d").getImageData(0,0,100,100)');
81
+ expect(strokes).toBeTruthy();
82
+ });
83
+ ```
84
+
85
+ ### Resizing Window Panels
86
+
87
+ ```javascript
88
+ test('resizes editor panel', async () => {
89
+ const { ai } = await vscode();
90
+
91
+ // Grab the divider
92
+ await ai.mouseDown('panel resize divider');
93
+
94
+ // Drag to new position
95
+ await ai.hover('position 400 pixels from left');
96
+
97
+ // Release to complete resize
98
+ await ai.mouseUp();
99
+
100
+ // Verify new panel size
101
+ const panel = await ai.find('editor panel');
102
+ expect(panel.width).toBeGreaterThan(350);
103
+ });
104
+ ```
105
+
106
+ ### Drag to Reorder List Items
107
+
108
+ ```javascript
109
+ import { test } from 'vitest';
110
+ import { chrome } from '@testdriver/sdk';
111
+
112
+ test('reorders tasks in list', async () => {
113
+ const { ai } = await chrome('https://todo-app.example.com');
114
+
115
+ // Start dragging first task
116
+ await ai.mouseDown('drag handle on first task');
117
+
118
+ // Move down to third position
119
+ await ai.hover('third task position');
120
+
121
+ // Drop the task
122
+ await ai.mouseUp();
123
+
124
+ // Verify new order
125
+ const thirdTask = await ai.find('third task in list');
126
+ expect(thirdTask.text).toContain('Original first task');
127
+ });
128
+ ```
129
+
130
+ ### Text Selection with Mouse
131
+
132
+ ```javascript
133
+ test('selects text with mouse drag', async () => {
134
+ const { ai } = await chrome('https://document.example.com');
135
+
136
+ // Start selection at beginning of word
137
+ await ai.mouseDown('start of "TestDriver" word');
138
+
139
+ // Drag to end of word
140
+ await ai.hover('end of "TestDriver" word');
141
+
142
+ // Complete selection
143
+ await ai.mouseUp();
144
+
145
+ // Verify selection
146
+ const selection = await ai.exec('window.getSelection().toString()');
147
+ expect(selection).toBe('TestDriver');
148
+ });
149
+ ```
150
+
151
+ ## Important Notes
152
+
153
+ - `mouseUp()` must be preceded by [`mouseDown()`](/v7/api/mouseDown) to have an effect
154
+ - Releases the button at the current cursor position
155
+ - Completes any drag or selection operation that was in progress
156
+ - For simple clicks, use [`click()`](/v7/api/click) instead of mouseDown/mouseUp pair
157
+
158
+ ## Related Methods
159
+
160
+ - [`mouseDown()`](/v7/api/mouseDown) - Press mouse button without releasing
161
+ - [`hover()`](/v7/api/hover) - Move mouse to element
162
+ - [`click()`](/v7/api/click) - Complete click (mouseDown + mouseUp)
163
+ - [`doubleClick()`](/v7/api/doubleClick) - Double-click on element
164
+ - [`rightClick()`](/v7/api/rightClick) - Right-click for context menu
@@ -0,0 +1,349 @@
1
+ ---
2
+ title: "pressKeys()"
3
+ sidebarTitle: "pressKeys"
4
+ description: "Press keyboard keys and shortcuts"
5
+ icon: "keyboard"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Press one or more keyboard keys simultaneously, useful for keyboard shortcuts, navigation, and special keys.
11
+
12
+ ## Syntax
13
+
14
+ ```javascript
15
+ await testdriver.pressKeys(keys)
16
+ ```
17
+
18
+ ## Parameters
19
+
20
+ <ParamField path="keys" type="Array&lt;string&gt;" required>
21
+ Array of keys to press simultaneously
22
+ </ParamField>
23
+
24
+ ## Returns
25
+
26
+ `Promise<void>`
27
+
28
+ ## Common Keys
29
+
30
+ ### Special Keys
31
+ - `'enter'`, `'tab'`, `'escape'`, `'backspace'`, `'delete'`
32
+ - `'space'`, `'up'`, `'down'`, `'left'`, `'right'`
33
+ - `'home'`, `'end'`, `'pageup'`, `'pagedown'`
34
+
35
+ ### Modifier Keys
36
+ - `'ctrl'`, `'alt'`, `'shift'`
37
+ - `'command'` (macOS), `'win'` (Windows)
38
+ - `'ctrlleft'`, `'ctrlright'`, `'shiftleft'`, `'shiftright'`
39
+
40
+ ### Function Keys
41
+ - `'f1'` through `'f24'`
42
+
43
+ ## Examples
44
+
45
+ ### Navigation
46
+
47
+ ```javascript
48
+ // Tab to next field
49
+ await testdriver.pressKeys(['tab']);
50
+
51
+ // Shift+Tab to previous field
52
+ await testdriver.pressKeys(['shift', 'tab']);
53
+
54
+ // Arrow keys
55
+ await testdriver.pressKeys(['down']);
56
+ await testdriver.pressKeys(['up']);
57
+ await testdriver.pressKeys(['left']);
58
+ await testdriver.pressKeys(['right']);
59
+
60
+ // Home/End
61
+ await testdriver.pressKeys(['home']); // Start of line
62
+ await testdriver.pressKeys(['end']); // End of line
63
+
64
+ // Page navigation
65
+ await testdriver.pressKeys(['pagedown']);
66
+ await testdriver.pressKeys(['pageup']);
67
+ ```
68
+
69
+ ### Keyboard Shortcuts
70
+
71
+ ```javascript
72
+ // Copy (Ctrl+C / Cmd+C)
73
+ await testdriver.pressKeys(['ctrl', 'c']);
74
+
75
+ // Paste (Ctrl+V / Cmd+V)
76
+ await testdriver.pressKeys(['ctrl', 'v']);
77
+
78
+ // Save (Ctrl+S)
79
+ await testdriver.pressKeys(['ctrl', 's']);
80
+
81
+ // Select All (Ctrl+A)
82
+ await testdriver.pressKeys(['ctrl', 'a']);
83
+
84
+ // Undo (Ctrl+Z)
85
+ await testdriver.pressKeys(['ctrl', 'z']);
86
+
87
+ // Redo (Ctrl+Y)
88
+ await testdriver.pressKeys(['ctrl', 'y']);
89
+
90
+ // Find (Ctrl+F)
91
+ await testdriver.pressKeys(['ctrl', 'f']);
92
+
93
+ // New tab (Ctrl+T)
94
+ await testdriver.pressKeys(['ctrl', 't']);
95
+
96
+ // Close tab (Ctrl+W)
97
+ await testdriver.pressKeys(['ctrl', 'w']);
98
+
99
+ // Refresh (F5 or Ctrl+R)
100
+ await testdriver.pressKeys(['f5']);
101
+ await testdriver.pressKeys(['ctrl', 'r']);
102
+ ```
103
+
104
+ ### System Shortcuts
105
+
106
+ ```javascript
107
+ // Alt+Tab (Windows - switch apps)
108
+ await testdriver.pressKeys(['alt', 'tab']);
109
+
110
+ // Alt+F4 (Windows - close window)
111
+ await testdriver.pressKeys(['alt', 'f4']);
112
+
113
+ // Win+D (Windows - show desktop)
114
+ await testdriver.pressKeys(['winleft', 'd']);
115
+
116
+ // Win+L (Windows - lock screen)
117
+ await testdriver.pressKeys(['winleft', 'l']);
118
+
119
+ // Cmd+Tab (macOS - switch apps)
120
+ await testdriver.pressKeys(['command', 'tab']);
121
+
122
+ // Cmd+Q (macOS - quit app)
123
+ await testdriver.pressKeys(['command', 'q']);
124
+ ```
125
+
126
+ ### Form Submission
127
+
128
+ ```javascript
129
+ // Submit form
130
+ await testdriver.pressKeys(['enter']);
131
+
132
+ // Cancel/Close
133
+ await testdriver.pressKeys(['escape']);
134
+
135
+ // Check checkbox
136
+ await testdriver.pressKeys(['space']);
137
+ ```
138
+
139
+ ### Text Editing
140
+
141
+ ```javascript
142
+ // Delete selected text
143
+ await testdriver.pressKeys(['delete']);
144
+
145
+ // Backspace
146
+ await testdriver.pressKeys(['backspace']);
147
+
148
+ // Select all and delete
149
+ await testdriver.pressKeys(['ctrl', 'a']);
150
+ await testdriver.pressKeys(['delete']);
151
+
152
+ // Cut text
153
+ await testdriver.pressKeys(['ctrl', 'x']);
154
+ ```
155
+
156
+ ## Best Practices
157
+
158
+ <Check>
159
+ **Wait after shortcuts**
160
+
161
+ Some keyboard shortcuts trigger animations or navigation:
162
+
163
+ ```javascript
164
+ await testdriver.pressKeys(['ctrl', 't']); // New tab
165
+ await new Promise(r => setTimeout(r, 500)); // Wait for tab
166
+ await testdriver.pressKeys(['ctrl', 'l']); // Focus URL bar
167
+ ```
168
+ </Check>
169
+
170
+ <Check>
171
+ **Use Tab for form navigation**
172
+
173
+ Tab is more reliable than clicking multiple fields:
174
+
175
+ ```javascript
176
+ const firstField = await testdriver.find('email input');
177
+ await firstField.click();
178
+ await testdriver.type('user@example.com');
179
+
180
+ await testdriver.pressKeys(['tab']);
181
+ await testdriver.type('password123');
182
+
183
+ await testdriver.pressKeys(['tab']);
184
+ await testdriver.pressKeys(['enter']); // Submit
185
+ ```
186
+ </Check>
187
+
188
+ <Warning>
189
+ **Platform-specific keys**
190
+
191
+ Use the appropriate modifier key for the platform:
192
+ - Windows/Linux: `'ctrl'`
193
+ - macOS: `'command'`
194
+
195
+ ```javascript
196
+ // For cross-platform, you might need to detect OS
197
+ const modKey = process.platform === 'darwin' ? 'command' : 'ctrl';
198
+ await testdriver.pressKeys([modKey, 'c']); // Copy
199
+ ```
200
+ </Warning>
201
+
202
+ ## Use Cases
203
+
204
+ <AccordionGroup>
205
+ <Accordion title="Form Navigation">
206
+ ```javascript
207
+ // Fill form using Tab
208
+ const firstField = await testdriver.find('name field');
209
+ await firstField.click();
210
+ await testdriver.type('John Doe');
211
+
212
+ await testdriver.pressKeys(['tab']);
213
+ await testdriver.type('john@example.com');
214
+
215
+ await testdriver.pressKeys(['tab']);
216
+ await testdriver.type('555-0123');
217
+
218
+ await testdriver.pressKeys(['tab']);
219
+ await testdriver.pressKeys(['enter']); // Submit
220
+ ```
221
+ </Accordion>
222
+
223
+ <Accordion title="Text Manipulation">
224
+ ```javascript
225
+ const textArea = await testdriver.find('comment textarea');
226
+ await textArea.click();
227
+
228
+ // Select all existing text
229
+ await testdriver.pressKeys(['ctrl', 'a']);
230
+
231
+ // Copy it
232
+ await testdriver.pressKeys(['ctrl', 'c']);
233
+
234
+ // Type new text
235
+ await testdriver.type('New comment');
236
+
237
+ // Undo if needed
238
+ await testdriver.pressKeys(['ctrl', 'z']);
239
+ ```
240
+ </Accordion>
241
+
242
+ <Accordion title="Browser Navigation">
243
+ ```javascript
244
+ // Open new tab
245
+ await testdriver.pressKeys(['ctrl', 't']);
246
+ await new Promise(r => setTimeout(r, 500));
247
+
248
+ // Focus address bar
249
+ await testdriver.pressKeys(['ctrl', 'l']);
250
+ await testdriver.type('https://example.com');
251
+ await testdriver.pressKeys(['enter']);
252
+
253
+ // Refresh page
254
+ await testdriver.pressKeys(['f5']);
255
+
256
+ // Close tab
257
+ await testdriver.pressKeys(['ctrl', 'w']);
258
+ ```
259
+ </Accordion>
260
+
261
+ <Accordion title="Application Shortcuts">
262
+ ```javascript
263
+ // Save document
264
+ await testdriver.pressKeys(['ctrl', 's']);
265
+
266
+ // Print
267
+ await testdriver.pressKeys(['ctrl', 'p']);
268
+
269
+ // Find in page
270
+ await testdriver.pressKeys(['ctrl', 'f']);
271
+ await testdriver.type('search term');
272
+ await testdriver.pressKeys(['escape']); // Close find
273
+ ```
274
+ </Accordion>
275
+ </AccordionGroup>
276
+
277
+ ## Complete Example
278
+
279
+ ```javascript
280
+ import { beforeAll, afterAll, describe, it } from 'vitest';
281
+ import TestDriver from 'testdriverai';
282
+
283
+ describe('Keyboard Navigation', () => {
284
+ let testdriver;
285
+
286
+ beforeAll(async () => {
287
+ client = new TestDriver(process.env.TD_API_KEY);
288
+ await testdriver.auth();
289
+ await testdriver.connect({ newSandbox: true });
290
+ });
291
+
292
+ afterAll(async () => {
293
+ await testdriver.disconnect();
294
+ });
295
+
296
+ it('should navigate form with keyboard', async () => {
297
+ await testdriver.focusApplication('Google Chrome');
298
+
299
+ // Find first field
300
+ const emailField = await testdriver.find('email input');
301
+ await emailField.click();
302
+ await testdriver.type('user@example.com');
303
+
304
+ // Tab through fields
305
+ await testdriver.pressKeys(['tab']);
306
+ await testdriver.type('John');
307
+
308
+ await testdriver.pressKeys(['tab']);
309
+ await testdriver.type('Doe');
310
+
311
+ await testdriver.pressKeys(['tab']);
312
+ await testdriver.type('password123');
313
+
314
+ // Submit with Enter
315
+ await testdriver.pressKeys(['tab']);
316
+ await testdriver.pressKeys(['enter']);
317
+
318
+ await testdriver.assert('form submitted successfully');
319
+ });
320
+
321
+ it('should use keyboard shortcuts', async () => {
322
+ // Open new browser tab
323
+ await testdriver.pressKeys(['ctrl', 't']);
324
+ await new Promise(r => setTimeout(r, 500));
325
+
326
+ // Focus address bar
327
+ await testdriver.pressKeys(['ctrl', 'l']);
328
+ await testdriver.type('https://example.com');
329
+ await testdriver.pressKeys(['enter']);
330
+
331
+ await new Promise(r => setTimeout(r, 2000));
332
+
333
+ // Select all page content
334
+ await testdriver.pressKeys(['ctrl', 'a']);
335
+
336
+ // Copy
337
+ await testdriver.pressKeys(['ctrl', 'c']);
338
+
339
+ // Refresh page
340
+ await testdriver.pressKeys(['f5']);
341
+ });
342
+ });
343
+ ```
344
+
345
+ ## Related Methods
346
+
347
+ - [`type()`](/v7/api/type) - Type text
348
+ - [`click()`](/v7/api/click) - Click elements
349
+ - [`scroll()`](/v7/api/scroll) - Scroll pages