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,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.
@@ -0,0 +1,282 @@
1
+ ---
2
+ title: "exec"
3
+ sidebarTitle: "exec"
4
+ description: "Execute custom shell or Node.js scripts within your tests."
5
+ icon: "code"
6
+ mode: "wide"
7
+ ---
8
+
9
+ import Replay from "/snippets/tests/exec-shell-replay.mdx";
10
+ import Example from "/snippets/tests/exec-shell-yaml.mdx";
11
+
12
+ <Replay />
13
+ <Example />
14
+
15
+ ## Description
16
+
17
+ The `exec` command allows you to execute custom Node.js scripts within your TestDriver tests. This is useful for tasks like generating dynamic data, interacting with APIs, or performing custom logic during a test. The output of the script can be stored in a variable for use in subsequent steps. It's important to note that the output from `exec` must be a `string`.
18
+
19
+ ## Arguments
20
+
21
+ | Argument | Type | Description |
22
+ | :------: | :------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
23
+ | `lang` | `string` | The language of the script to execute. Supported values are `pwsh` and `js`. |
24
+ | `output` | `string` | The variable name to store the result of the script. This variable can be accessed as `${OUTPUT.<var>}` in future steps. |
25
+ | `code` | `string` | The script to execute on Windows systems. For `js`, the script must define the output as `result`. |
26
+ | `silent` | `string` | Defaults to `false`. The command will print the output of the script. This is useful for suppressing unnecessary or private output in the test logs and it's useful for debugging. |
27
+
28
+ ## Example usage
29
+
30
+ This example demonstrates how to use the `exec` command to generate a TOTP (Time-based One-Time Password) using the `totp-generator` library.
31
+
32
+ ```yaml otp-generator.yaml
33
+ version: 6.0.0
34
+ steps:
35
+ - commands:
36
+ - command: exec
37
+ lang: pwsh
38
+ code: |
39
+ npm install totp-generator
40
+ - command: exec
41
+ lang: js
42
+ output: totp
43
+ code: |
44
+ const { TOTP } = require("totp-generator");
45
+ let otp = TOTP.generate("JBSWY3DPEB3W64TMMQQQ").otp;
46
+ console.log(otp);
47
+ result = otp;
48
+ - command: type
49
+ text: ${OUTPUT.totp}
50
+ ```
51
+
52
+ ## Additional details
53
+
54
+ - Supported `lang` values are `js` or `pwsh`:
55
+ - `js` code is executed in a Node.js [VM](https://nodejs.org/api/vm.html) internally on the host machine (for example the machine where your CI/CD runs, or your computer if using the local agent).
56
+ - `pwsh` code is executed in the shell on target runner (which can be the cloud runner, local sandbox, or local machine, depending on where you run your tests).
57
+ - **Note:** You can also use `pwsh` in [lifecycle](/guide/lifecycle) scripts to install npm packages if you need them.
58
+ - Otherwise, the `pwsh` code can be used within test steps to launch applications or perform simple commands (like writing text to a file on the machine to perform a simple file upload).
59
+ - The `output`argument is assigned automatically by setting `result = somestringvalue` in the script you run.
60
+
61
+ ## Protips
62
+
63
+ - The `result` variable is already available in your script, overwrite it to store the output as shown in the examples.
64
+ - Do any handling of arrays or nested objects within your `js` script:
65
+ - ✅ `result = users[1].profile.firstName`
66
+ - ✅ `result = data.length > 0 ? data[0].userEmail : 'no user found'` if no data is found the value of output will be `null`
67
+ - ✅ `result = someTestUserEmail`
68
+ - ✅ `result = someTextToAssert`
69
+ - ✅ `result = someDescriptionOfAnImageToScrollTo`
70
+ - Don't try to pass any non-string values to `output`:
71
+ - ❌ `result = [...users, ...values]`
72
+ - ❌ `result = {name: "Dale Earnhardt", starts: 676, wins: 76}`
73
+ - ❌ `result = [{user1: ...}, {user2: ...}]`
74
+
75
+ ---
76
+
77
+ ## Ways to use `exec`
78
+
79
+ Here is an example using both `pwsh` and `js` contexts within a `prerun.yaml` script which creates a temporary email account and automatically clicks links found in received emails.
80
+
81
+ ```yaml ./lifecycle/prerun.yaml [expandable]
82
+ version: 6.0.0
83
+ steps:
84
+ - commands:
85
+ - command: exec
86
+ lang: pwsh
87
+ code: |
88
+ npm install @sendgrid/mail
89
+ - command: exec
90
+ lang: js
91
+ output: accountData
92
+ code: |
93
+ const Mailjs = require("@cemalgnlts/mailjs");
94
+ const mailjs = new Mailjs();
95
+ let account = await mailjs.createOneAccount()
96
+ console.log("Account created:", account);
97
+ result = JSON.stringify(account.data)
98
+ - command: exec
99
+ lang: js
100
+ output: emailAddress
101
+ code: |
102
+ const accountData = ${OUTPUT.accountData};
103
+ result = accountData.username
104
+ - prompt: Enter the generated email into the email field
105
+ commands:
106
+ - command: hover-text
107
+ text: standard_user
108
+ description: email input field label
109
+ action: click
110
+ - command: type
111
+ text: ${OUTPUT.emailAddress}
112
+ - prompt: Wait for an email, extract links, and open each link
113
+ commands:
114
+ - command: exec
115
+ lang: js
116
+ code: |
117
+ const Mailjs = require("@cemalgnlts/mailjs");
118
+ const { JSDOM } = require('jsdom'); // To parse HTML and extract links
119
+
120
+ const accountData = ${OUTPUT.accountData};
121
+
122
+ const getLatestEmailAndClickLinks = async () => {
123
+ try {
124
+ // Initialize the Mailjs client
125
+ const mailjs = new Mailjs();
126
+
127
+ // Login to your account
128
+ await mailjs.login(accountData.username, accountData.password);
129
+
130
+ // Fetch list of messages
131
+ const messages = await mailjs.getMessages();
132
+
133
+ if (messages.length === 0) {
134
+ console.log('No emails found.');
135
+ return;
136
+ }
137
+
138
+ // Assuming the latest email is the first one in the list
139
+ const latestMessage = messages[0];
140
+
141
+ // Fetch the full details of the latest email
142
+ const fullMessage = await mailjs.getMessage(latestMessage.id);
143
+
144
+ console.log('Latest Email Details:', fullMessage);
145
+
146
+ // Parse the HTML content to extract links
147
+ const dom = new JSDOM(fullMessage.html);
148
+ const links = Array.from(dom.window.document.querySelectorAll('a')).map(a => a.href);
149
+
150
+ console.log('Found Links:', links);
151
+
152
+ // Click (fetch) every link using native fetch
153
+ for (const link of links) {
154
+ try {
155
+ const response = await fetch(link);
156
+ console.log('Clicked ${link}: ${response.status}');
157
+ } catch (linkError) {
158
+ console.error('Error clicking ${link}:', linkError);
159
+ }
160
+ }
161
+
162
+ } catch (error) {
163
+ console.error('Error fetching latest email or clicking links:', error);
164
+ }
165
+ };
166
+
167
+ getLatestEmailAndClickLinks();
168
+ ```
169
+
170
+ ### Using `exec` pwsh commands in a test file
171
+
172
+ In a test file, you can use the `pwsh` context directly:
173
+
174
+ ```yaml calculator.yaml highlight={5-8} [expandable]
175
+ version: 6.0.0
176
+ steps:
177
+ - prompt: launch a calculator
178
+ commands:
179
+ - command: exec
180
+ lang: pwsh
181
+ code: |
182
+ start /B calc.exe
183
+ timeout /t 5
184
+ - command: wait-for-text
185
+ text: "calculator"
186
+ timeout: 30000
187
+ - prompt: performing the operation 2 + 2 = on the calculator that is opened
188
+ commands:
189
+ - command: focus-application
190
+ name: galculator
191
+ - command: hover-image
192
+ description: button with number 2 on the calculator
193
+ action: click
194
+ - command: hover-image
195
+ description: plus button on the calculator
196
+ action: click
197
+ - command: hover-image
198
+ description: button with number 2 on the calculator
199
+ action: click
200
+ - command: hover-image
201
+ description: equals button on the calculator
202
+ action: click
203
+ ```
204
+
205
+ ### One more option
206
+
207
+ You can also save reusable snippets (like launching the calculator) to be inserted into a script later with the [`run`](/commands/run) command. That version would look something like this:
208
+
209
+ ```yaml snippets/launch-calculator.yaml [expandable]
210
+ version: 6.0.0
211
+ steps:
212
+ - prompt: launch a calculator
213
+ commands:
214
+ - command: exec
215
+ lang: pwsh
216
+ code: |
217
+ start /B calc.exe
218
+ timeout /t 5
219
+ - command: wait-for-text
220
+ text: "calculator"
221
+ timeout: 30000
222
+ ```
223
+
224
+ Then in the test:
225
+
226
+ ```yaml calculator.yaml highlight={5-6} [expandable]
227
+ version: 6.0.0
228
+ steps:
229
+ - prompt: launch a calculator
230
+ commands:
231
+ - command: run
232
+ file: snippets/launch-calculator.yaml
233
+ - prompt: performing the operation 2 + 2 = on the calculator that is opened
234
+ commands:
235
+ - command: focus-application
236
+ name: galculator
237
+ - command: hover-image
238
+ description: button with number 2 on the calculator
239
+ action: click
240
+ - command: hover-image
241
+ description: plus button on the calculator
242
+ action: click
243
+ - command: hover-image
244
+ description: button with number 2 on the calculator
245
+ action: click
246
+ - command: hover-image
247
+ description: equals button on the calculator
248
+ action: click
249
+ ```
250
+
251
+ ### Don't try to run `js` within a test field
252
+
253
+ This example will fail at runtime, so don't try to execute `js` context directly in a test file. Remember - use this in `prerun` to setup your test!
254
+
255
+ ```yaml badtestfile.yaml [expandable]
256
+ version: 6.0.0
257
+ commands:
258
+ - command: exec
259
+ lang: pwsh
260
+ code: |
261
+ npm install -g axios json2csv
262
+ - prompt: fetch user data from API
263
+ commands:
264
+ - command: exec
265
+ output: user
266
+ lang: js
267
+ code: |
268
+ const axios = require('axios');
269
+ const { Parser } = require('json2csv');
270
+ const fs = require('fs');
271
+
272
+ const response = await axios.get('https://jsonplaceholder.typicode.com/users');
273
+ const parser = new Parser();
274
+ const csv = parser.parse(response.data);
275
+ fs.writeFileSync('users.csv', csv);
276
+ const user = response.data[0].name;
277
+ result = user;
278
+ console.log('username', user);
279
+ ...
280
+ ```
281
+
282
+ This example will produce errors in the TestDriver output or CLI since the runner won't have access to the Node.js VM context.
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: "focus-application"
3
+ sidebarTitle: "focus-application"
4
+ description: "Bring a specific application window to the foreground."
5
+ icon: "window-restore"
6
+ mode: "wide"
7
+ ---
8
+
9
+ ## Description
10
+
11
+ The `focus-application` command displays a specific application window to the foreground. This ensures that subsequent commands interact with the correct application during a test.
12
+
13
+ ## Arguments
14
+
15
+ | Argument | Type | Description |
16
+ | -------- | -------- | --------------------------------------------------------------------------------------- |
17
+ | `name` | `string` | The name of the application to focus. This should match the application's display name. |
18
+
19
+ ## Example usage
20
+
21
+ ```yaml
22
+ command: focus-application
23
+ name: Google Chrome
24
+ ```
25
+
26
+ ## Protips
27
+
28
+ - Ensure the application name matches the exact name displayed in your operating system's task manager.
29
+ - Use this command at the start of a test or before interacting with an application to avoid focus-related issues.
30
+
31
+ <Note>
32
+ If the specified application isn't running, the command will fail. Ensure the application is open before using this command.
33
+ For example, to launch chrome try using the exec command:
34
+
35
+ ```yaml
36
+ - command: exec
37
+ lang: pwsh
38
+ code: start chrome
39
+ ```
40
+
41
+ </Note>
42
+ ## Notes
43
+
44
+ - The `focus-application` command is useful for multi-application workflows where you need to switch between different apps during a test.