testdriverai 6.2.2 → 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 +15 -4
  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,474 @@
1
+ # TestDriver SDK Migration Guide
2
+
3
+ ## New Element Finding API
4
+
5
+ We've introduced a new, more flexible API for finding and interacting with elements. The new `find()` API provides better control and enables polling patterns for dynamic content.
6
+
7
+ ## Quick Comparison
8
+
9
+ ### Old API (Deprecated)
10
+
11
+ ```javascript
12
+ // Find and click text
13
+ await client.hoverText("Sign In", "black button below password", "click");
14
+
15
+ // Wait for text to appear
16
+ await client.waitForText("Login button", 10000);
17
+
18
+ // Find and click image
19
+ await client.hoverImage("submit button icon", "click");
20
+ ```
21
+
22
+ ### New API (Recommended)
23
+
24
+ ```javascript
25
+ // Find and click text or image
26
+ const element = await client
27
+ .find("Sign In, black button below password")
28
+ .find();
29
+ await element.click();
30
+
31
+ // Poll until element appears (replaces waitForText/waitForImage)
32
+ let element = client.find("login button");
33
+ while (!element.found()) {
34
+ console.log("waiting for element to be found");
35
+ element = await element.find();
36
+ await new Promise((resolve) => setTimeout(resolve, 1000));
37
+ }
38
+ await element.click();
39
+ ```
40
+
41
+ ## Migration Examples
42
+
43
+ ### Example 1: Simple Click
44
+
45
+ **Before:**
46
+
47
+ ```javascript
48
+ await client.hoverText("Submit", "submit button", "click");
49
+ ```
50
+
51
+ **After:**
52
+
53
+ ```javascript
54
+ const submitBtn = await client.find("Submit button");
55
+ await submitBtn.click();
56
+ ```
57
+
58
+ ### Example 2: Waiting for Elements
59
+
60
+ **Before:**
61
+
62
+ ```javascript
63
+ await client.waitForText("Welcome", 10000);
64
+ await client.hoverText("Welcome", null, "click");
65
+ ```
66
+
67
+ **After:**
68
+
69
+ ```javascript
70
+ let element;
71
+ const maxAttempts = 10;
72
+ let attempts = 0;
73
+
74
+ while (!element?.found() && attempts < maxAttempts) {
75
+ element = await client.find("Welcome");
76
+ if (!element.found()) {
77
+ await new Promise((resolve) => setTimeout(resolve, 1000));
78
+ }
79
+ attempts++;
80
+ }
81
+
82
+ if (element?.found()) {
83
+ await element.click();
84
+ }
85
+ ```
86
+
87
+ ### Example 3: Hover Actions
88
+
89
+ **Before:**
90
+
91
+ ```javascript
92
+ await client.hoverText("Menu", null, "hover");
93
+ ```
94
+
95
+ **After:**
96
+
97
+ ```javascript
98
+ const menu = await client.find("Menu").find();
99
+ await menu.hover();
100
+ ```
101
+
102
+ ### Example 4: Different Click Types
103
+
104
+ **Before:**
105
+
106
+ ```javascript
107
+ await client.hoverText("File", null, "right-click");
108
+ await client.hoverText("Save", null, "double-click");
109
+ ```
110
+
111
+ **After:**
112
+
113
+ ```javascript
114
+ const file = await client.find("File").find();
115
+ await file.rightClick();
116
+
117
+ const save = await client.find("Save").find();
118
+ await save.doubleClick();
119
+
120
+ // Or use the generic click() method
121
+ await file.click("right-click");
122
+ await save.click("double-click");
123
+ ```
124
+
125
+ ### Example 5: Conditional Logic
126
+
127
+ **Before:**
128
+
129
+ ```javascript
130
+ try {
131
+ await client.waitForText("Error message", 2000);
132
+ // Handle error
133
+ } catch (e) {
134
+ // No error present
135
+ }
136
+ ```
137
+
138
+ **After:**
139
+
140
+ ```javascript
141
+ const errorMsg = await client.find("Error message").find();
142
+ if (errorMsg.found()) {
143
+ // Handle error
144
+ console.log("Error found at:", errorMsg.getCoordinates());
145
+ } else {
146
+ // No error present
147
+ }
148
+ ```
149
+
150
+ ## New Element API Reference
151
+
152
+ ### `client.find(description)`
153
+
154
+ Creates an Element instance for finding and interacting with elements.
155
+
156
+ **Parameters:**
157
+
158
+ - `description` (string): Natural language description of the element
159
+
160
+ **Returns:** `Element` instance
161
+
162
+ **Example:**
163
+
164
+ ```javascript
165
+ const button = client.find("the sign in button");
166
+ ```
167
+
168
+ ### `element.find([newDescription])`
169
+
170
+ Attempts to locate the element on screen.
171
+
172
+ **Parameters:**
173
+
174
+ - `newDescription` (optional string): New description to search for
175
+
176
+ **Returns:** `Promise<Element>` - The same Element instance (for chaining)
177
+
178
+ **Example:**
179
+
180
+ ```javascript
181
+ const element = await client.find("login button").find();
182
+
183
+ // Or with a new description
184
+ element = await element.find("sign in button");
185
+ ```
186
+
187
+ ### `element.found()`
188
+
189
+ Check if the element was successfully located.
190
+
191
+ **Returns:** `boolean` - true if element coordinates were found
192
+
193
+ **Example:**
194
+
195
+ ```javascript
196
+ const element = await client.find("button").find();
197
+ if (element.found()) {
198
+ console.log("Element found!");
199
+ }
200
+ ```
201
+
202
+ ### `element.click([action])`
203
+
204
+ Click on the element.
205
+
206
+ **Parameters:**
207
+
208
+ - `action` (optional): Click action type - `'click'`, `'right-click'`, `'double-click'`
209
+
210
+ **Returns:** `Promise<void>`
211
+
212
+ **Example:**
213
+
214
+ ```javascript
215
+ await element.click();
216
+ await element.click("right-click");
217
+ ```
218
+
219
+ ### `element.hover()`
220
+
221
+ Hover over the element.
222
+
223
+ **Returns:** `Promise<void>`
224
+
225
+ **Example:**
226
+
227
+ ```javascript
228
+ await element.hover();
229
+ ```
230
+
231
+ ### `element.doubleClick()`
232
+
233
+ Double-click on the element. Convenience method for `element.click('double-click')`.
234
+
235
+ **Returns:** `Promise<void>`
236
+
237
+ **Example:**
238
+
239
+ ```javascript
240
+ await element.doubleClick();
241
+ ```
242
+
243
+ ### `element.rightClick()`
244
+
245
+ Right-click on the element. Convenience method for `element.click('right-click')`.
246
+
247
+ **Returns:** `Promise<void>`
248
+
249
+ **Example:**
250
+
251
+ ```javascript
252
+ await element.rightClick();
253
+ ```
254
+
255
+ ### `element.mouseDown()`
256
+
257
+ Press mouse button down on this element (useful for drag operations).
258
+
259
+ **Returns:** `Promise<void>`
260
+
261
+ **Example:**
262
+
263
+ ```javascript
264
+ const source = await client.find("draggable item").find();
265
+ await source.mouseDown();
266
+ ```
267
+
268
+ ### `element.mouseUp()`
269
+
270
+ Release mouse button on this element (useful for drag operations).
271
+
272
+ **Returns:** `Promise<void>`
273
+
274
+ **Example:**
275
+
276
+ ```javascript
277
+ const target = await client.find("drop zone").find();
278
+ await target.mouseUp();
279
+ ```
280
+
281
+ ### `element.getCoordinates()`
282
+
283
+ Get the screen coordinates of the element.
284
+
285
+ **Returns:** `{x, y, centerX, centerY}` or `null` if not found
286
+
287
+ **Example:**
288
+
289
+ ```javascript
290
+ const coords = element.getCoordinates();
291
+ if (coords) {
292
+ console.log(`Element at: ${coords.x}, ${coords.y}`);
293
+ }
294
+ ```
295
+
296
+ ### `element.getResponse()`
297
+
298
+ Get the full API response data from the locate operation.
299
+
300
+ **Returns:** `Object | null` - Full response containing all available data
301
+
302
+ **Example:**
303
+
304
+ ```javascript
305
+ const response = element.getResponse();
306
+ console.log("Full response:", response);
307
+ ```
308
+
309
+ ## Element Properties
310
+
311
+ The Element class exposes many properties from the API response:
312
+
313
+ ### Coordinate Properties
314
+
315
+ - `element.x` - X coordinate (top-left corner)
316
+ - `element.y` - Y coordinate (top-left corner)
317
+ - `element.centerX` - X coordinate of element center
318
+ - `element.centerY` - Y coordinate of element center
319
+
320
+ ### Dimension Properties
321
+
322
+ - `element.width` - Width of the element (if available)
323
+ - `element.height` - Height of the element (if available)
324
+ - `element.boundingBox` - Bounding box data (if available)
325
+
326
+ ### Match Quality Properties
327
+
328
+ - `element.confidence` - Confidence score of the match (0-1)
329
+ - `element.screenshot` - Base64 encoded screenshot of the element
330
+ - `element.text` - Text content of the element (if available)
331
+ - `element.label` - Label/aria-label of the element (if available)
332
+
333
+ ### Example Usage
334
+
335
+ ```javascript
336
+ const button = await client.find("login button");
337
+
338
+ if (button.found()) {
339
+ console.log("Position:", { x: button.x, y: button.y });
340
+ console.log("Center:", { x: button.centerX, y: button.centerY });
341
+ console.log("Size:", { width: button.width, height: button.height });
342
+ console.log("Confidence:", button.confidence);
343
+ console.log("Text:", button.text);
344
+
345
+ // Save screenshot for debugging
346
+ if (button.screenshot) {
347
+ const fs = require("fs");
348
+ fs.writeFileSync("button.png", Buffer.from(button.screenshot, "base64"));
349
+ }
350
+
351
+ // Conditional actions based on properties
352
+ if (button.confidence > 0.8) {
353
+ await button.click();
354
+ }
355
+ }
356
+ ```
357
+
358
+ For a complete example, see `examples/sdk-element-properties.js`.
359
+
360
+ ## Common Patterns
361
+
362
+ ### Pattern 1: Find and Click
363
+
364
+ ```javascript
365
+ const element = await client.find("description").find();
366
+ if (element.found()) {
367
+ await element.click();
368
+ }
369
+ ```
370
+
371
+ ### Pattern 2: Polling with Timeout
372
+
373
+ ```javascript
374
+ const element = client.find("element description");
375
+ const timeoutMs = 10000;
376
+ const startTime = Date.now();
377
+
378
+ while (!element.found() && Date.now() - startTime < timeoutMs) {
379
+ element = await element.find();
380
+ if (!element.found()) {
381
+ await new Promise((resolve) => setTimeout(resolve, 500));
382
+ }
383
+ }
384
+
385
+ if (!element.found()) {
386
+ throw new Error("Element not found within timeout");
387
+ }
388
+ ```
389
+
390
+ ### Pattern 3: Retry with Different Descriptions
391
+
392
+ ```javascript
393
+ let element = client.find("primary button");
394
+ element = await element.find();
395
+
396
+ if (!element.found()) {
397
+ element = await element.find("submit button");
398
+ }
399
+
400
+ if (!element.found()) {
401
+ element = await element.find("blue button on the right");
402
+ }
403
+
404
+ if (element.found()) {
405
+ await element.click();
406
+ }
407
+ ```
408
+
409
+ ### Pattern 4: Helper Function for Waiting
410
+
411
+ ```javascript
412
+ async function waitForElement(client, description, timeoutMs = 10000) {
413
+ const element = client.find(description);
414
+ const startTime = Date.now();
415
+
416
+ while (!element.found() && Date.now() - startTime < timeoutMs) {
417
+ await element.find();
418
+ if (!element.found()) {
419
+ await new Promise((resolve) => setTimeout(resolve, 500));
420
+ }
421
+ }
422
+
423
+ if (!element.found()) {
424
+ throw new Error(`Element "${description}" not found within ${timeoutMs}ms`);
425
+ }
426
+
427
+ return element;
428
+ }
429
+
430
+ // Usage
431
+ const button = await waitForElement(client, "login button", 5000);
432
+ await button.click();
433
+ ```
434
+
435
+ ## Deprecated Methods
436
+
437
+ The following methods are now deprecated and will be removed in a future version:
438
+
439
+ - ❌ `client.hoverText()` → ✅ Use `client.find().find()` + `element.click()`
440
+ - ❌ `client.hoverImage()` → ✅ Use `client.find().find()` + `element.click()`
441
+ - ❌ `client.waitForText()` → ✅ Use polling pattern with `client.find()`
442
+ - ❌ `client.waitForImage()` → ✅ Use polling pattern with `client.find()`
443
+ - ❌ `client.wait()` → ✅ Use element polling instead of arbitrary waits when possible
444
+
445
+ ## Benefits of the New API
446
+
447
+ 1. **More Explicit**: Clear separation between finding and interacting
448
+ 2. **Better Error Handling**: Can check if element exists before interacting
449
+ 3. **Flexible Polling**: Custom polling logic for dynamic content
450
+ 4. **Unified Interface**: Same API for text and images
451
+ 5. **More Control**: Access to element state and coordinates
452
+ 6. **Composable**: Element instances can be stored and reused
453
+
454
+ ## TypeScript Support
455
+
456
+ The new API is fully typed:
457
+
458
+ ```typescript
459
+ import TestDriver, { Element } from "testdriverai";
460
+
461
+ const client = new TestDriver(process.env.TD_API_KEY);
462
+ await client.connect();
463
+
464
+ const element: Element = await client.find("button").find();
465
+ const found: boolean = element.found();
466
+ const coords = element.getCoordinates(); // {x, y, centerX, centerY} | null
467
+ ```
468
+
469
+ ## Questions?
470
+
471
+ For more examples, see:
472
+
473
+ - `examples/sdk-find-example.js` - Comprehensive examples of the new API
474
+ - `testdriver/acceptance-sdk/hover-text.test.mjs` - Updated test example