@testdriverai/agent 7.8.0-test.38

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 (528) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.env.example +4 -0
  3. package/.prettierignore +4 -0
  4. package/.prettierrc +1 -0
  5. package/CHANGELOG.md +953 -0
  6. package/README.md +81 -0
  7. package/agent/events.js +135 -0
  8. package/agent/index.js +2450 -0
  9. package/agent/interface.js +35 -0
  10. package/agent/lib/analytics.js +22 -0
  11. package/agent/lib/censorship.js +75 -0
  12. package/agent/lib/commander.js +246 -0
  13. package/agent/lib/commands.js +1684 -0
  14. package/agent/lib/config.js +60 -0
  15. package/agent/lib/generator.js +91 -0
  16. package/agent/lib/http.js +144 -0
  17. package/agent/lib/logger.js +56 -0
  18. package/agent/lib/outputs.js +29 -0
  19. package/agent/lib/parser.js +209 -0
  20. package/agent/lib/redraw.js +386 -0
  21. package/agent/lib/resources/cursor-2.png +0 -0
  22. package/agent/lib/sandbox.js +1104 -0
  23. package/agent/lib/sdk.js +633 -0
  24. package/agent/lib/session.js +25 -0
  25. package/agent/lib/source-mapper.js +342 -0
  26. package/agent/lib/subimage/index.js +77 -0
  27. package/agent/lib/subimage/opencv.js +69 -0
  28. package/agent/lib/system.js +204 -0
  29. package/agent/lib/theme.js +14 -0
  30. package/agent/lib/valid-version.js +21 -0
  31. package/agent/lib/validation.js +169 -0
  32. package/ai/.claude-plugin/plugin.json +9 -0
  33. package/ai/agents/testdriver.md +638 -0
  34. package/ai/skills/testdriver-ai/SKILL.md +204 -0
  35. package/ai/skills/testdriver-assert/SKILL.md +315 -0
  36. package/ai/skills/testdriver-aws-setup/SKILL.md +448 -0
  37. package/ai/skills/testdriver-cache/SKILL.md +221 -0
  38. package/ai/skills/testdriver-caching/SKILL.md +124 -0
  39. package/ai/skills/testdriver-captcha/SKILL.md +158 -0
  40. package/ai/skills/testdriver-ci-cd/SKILL.md +602 -0
  41. package/ai/skills/testdriver-click/SKILL.md +286 -0
  42. package/ai/skills/testdriver-client/SKILL.md +477 -0
  43. package/ai/skills/testdriver-cloud/SKILL.md +119 -0
  44. package/ai/skills/testdriver-customizing-devices/SKILL.md +319 -0
  45. package/ai/skills/testdriver-dashcam/SKILL.md +418 -0
  46. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +401 -0
  47. package/ai/skills/testdriver-device-config/SKILL.md +317 -0
  48. package/ai/skills/testdriver-double-click/SKILL.md +102 -0
  49. package/ai/skills/testdriver-elements/SKILL.md +605 -0
  50. package/ai/skills/testdriver-enterprise/SKILL.md +114 -0
  51. package/ai/skills/testdriver-errors/SKILL.md +246 -0
  52. package/ai/skills/testdriver-events/SKILL.md +356 -0
  53. package/ai/skills/testdriver-examples/SKILL.md +7 -0
  54. package/ai/skills/testdriver-exec/SKILL.md +317 -0
  55. package/ai/skills/testdriver-find/SKILL.md +829 -0
  56. package/ai/skills/testdriver-focus-application/SKILL.md +293 -0
  57. package/ai/skills/testdriver-generating-tests/SKILL.md +36 -0
  58. package/ai/skills/testdriver-hover/SKILL.md +278 -0
  59. package/ai/skills/testdriver-locating-elements/SKILL.md +71 -0
  60. package/ai/skills/testdriver-making-assertions/SKILL.md +32 -0
  61. package/ai/skills/testdriver-mcp/SKILL.md +7 -0
  62. package/ai/skills/testdriver-mcp-workflow/SKILL.md +410 -0
  63. package/ai/skills/testdriver-mouse-down/SKILL.md +161 -0
  64. package/ai/skills/testdriver-mouse-up/SKILL.md +164 -0
  65. package/ai/skills/testdriver-parse/SKILL.md +236 -0
  66. package/ai/skills/testdriver-performing-actions/SKILL.md +54 -0
  67. package/ai/skills/testdriver-press-keys/SKILL.md +348 -0
  68. package/ai/skills/testdriver-provision/SKILL.md +331 -0
  69. package/ai/skills/testdriver-quickstart/SKILL.md +144 -0
  70. package/ai/skills/testdriver-redraw/SKILL.md +214 -0
  71. package/ai/skills/testdriver-reusable-code/SKILL.md +249 -0
  72. package/ai/skills/testdriver-right-click/SKILL.md +123 -0
  73. package/ai/skills/testdriver-running-tests/SKILL.md +185 -0
  74. package/ai/skills/testdriver-screenshot/SKILL.md +248 -0
  75. package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
  76. package/ai/skills/testdriver-scroll/SKILL.md +335 -0
  77. package/ai/skills/testdriver-secrets/SKILL.md +115 -0
  78. package/ai/skills/testdriver-self-hosted/SKILL.md +65 -0
  79. package/ai/skills/testdriver-test-writer/SKILL.md +448 -0
  80. package/ai/skills/testdriver-testdriver/SKILL.md +628 -0
  81. package/ai/skills/testdriver-testdriver-mechanic/SKILL.md +165 -0
  82. package/ai/skills/testdriver-type/SKILL.md +357 -0
  83. package/ai/skills/testdriver-variables/SKILL.md +111 -0
  84. package/ai/skills/testdriver-wait/SKILL.md +50 -0
  85. package/ai/skills/testdriver-waiting-for-elements/SKILL.md +90 -0
  86. package/ai/skills/testdriver-what-is-testdriver/SKILL.md +54 -0
  87. package/bin/testdriverai.js +22 -0
  88. package/debugger/bg.png +0 -0
  89. package/debugger/icon.png +0 -0
  90. package/debugger/index.html +469 -0
  91. package/debugger/td.png +0 -0
  92. package/debugger/tray-buffered.png +0 -0
  93. package/debugger/tray.png +0 -0
  94. package/docs/GITHUB_COMMENTS.md +330 -0
  95. package/docs/GITHUB_COMMENTS_ANNOUNCEMENT.md +167 -0
  96. package/docs/QUICK-START-GITHUB-COMMENTS.md +84 -0
  97. package/docs/TEST-GITHUB-COMMENTS.md +129 -0
  98. package/docs/_data/examples-manifest.json +177 -0
  99. package/docs/_data/examples-manifest.schema.json +41 -0
  100. package/docs/_scripts/extract-example-urls.js +165 -0
  101. package/docs/_scripts/generate-examples.js +560 -0
  102. package/docs/_scripts/generate-skills.js +154 -0
  103. package/docs/_scripts/link-replacer.js +164 -0
  104. package/docs/_scripts/upload-docs-to-openai.js +284 -0
  105. package/docs/changelog.mdx +161 -0
  106. package/docs/claude-mcp-plugin.mdx +160 -0
  107. package/docs/docs.json +442 -0
  108. package/docs/github-integration-setup.md +266 -0
  109. package/docs/guide/best-practices-polling.mdx +174 -0
  110. package/docs/images/content/account/newprojectsettings.png +0 -0
  111. package/docs/images/content/account/projectpage.png +0 -0
  112. package/docs/images/content/account/projectreplays.png +0 -0
  113. package/docs/images/content/account/team-manage.png +0 -0
  114. package/docs/images/content/account/teampage.png +0 -0
  115. package/docs/images/content/extension/cursor.svg +1 -0
  116. package/docs/images/content/extension/vscode.svg +57 -0
  117. package/docs/images/content/extension/windsurf.svg +3 -0
  118. package/docs/images/content/parse/output.png +0 -0
  119. package/docs/images/content/self-hosted/launchtemplateid.png +0 -0
  120. package/docs/images/content/side-by-side.png +0 -0
  121. package/docs/images/content/vscode/ide-full.png +0 -0
  122. package/docs/images/content/vscode/running.png +0 -0
  123. package/docs/images/content/vscode/v7-chat.png +0 -0
  124. package/docs/images/content/vscode/v7-choose-agent.png +0 -0
  125. package/docs/images/content/vscode/v7-full.png +0 -0
  126. package/docs/images/content/vscode/v7-onboarding.png +0 -0
  127. package/docs/images/content/vscode/vscode-2-assert.png +0 -0
  128. package/docs/images/content/vscode/vscode-agent-preview.png +0 -0
  129. package/docs/images/content/vscode/vscode-copilot-ask.png +0 -0
  130. package/docs/images/content/vscode/vscode-file-creation.png +0 -0
  131. package/docs/images/content/vscode/vscode-install.png +0 -0
  132. package/docs/images/content/vscode/vscode-overview.png +0 -0
  133. package/docs/images/content/vscode/vscode-setup-walkthrough.png +0 -0
  134. package/docs/images/content/vscode/vscode-stopchat.png +0 -0
  135. package/docs/images/content/vscode/vscode-stoptest.png +0 -0
  136. package/docs/images/content/vscode/vscode-tdservice.png +0 -0
  137. package/docs/images/content/vscode/vscode-test-output.png +0 -0
  138. package/docs/images/content/vscode/vscode-testhistory.png +0 -0
  139. package/docs/images/content/vscode/vscode-testpane-runtests.png +0 -0
  140. package/docs/images/content/vscode/vscode-testpane.png +0 -0
  141. package/docs/images/template/dark.png +0 -0
  142. package/docs/images/template/icon.png +0 -0
  143. package/docs/images/template/light.png +0 -0
  144. package/docs/snippets/calendar-link.mdx +4 -0
  145. package/docs/snippets/gitignore-warning.mdx +7 -0
  146. package/docs/snippets/lifecycle-warning.mdx +6 -0
  147. package/docs/snippets/test-prereqs.mdx +12 -0
  148. package/docs/snippets/tests/assert-replay.mdx +7 -0
  149. package/docs/snippets/tests/assert-yaml.mdx +8 -0
  150. package/docs/snippets/tests/exec-js-replay.mdx +7 -0
  151. package/docs/snippets/tests/exec-js-yaml.mdx +32 -0
  152. package/docs/snippets/tests/exec-shell-replay.mdx +7 -0
  153. package/docs/snippets/tests/exec-shell-yaml.mdx +15 -0
  154. package/docs/snippets/tests/hover-image-replay.mdx +7 -0
  155. package/docs/snippets/tests/hover-image-yaml.mdx +17 -0
  156. package/docs/snippets/tests/hover-text-replay.mdx +7 -0
  157. package/docs/snippets/tests/hover-text-with-description-replay.mdx +7 -0
  158. package/docs/snippets/tests/hover-text-with-description-yaml.mdx +24 -0
  159. package/docs/snippets/tests/hover-text-yaml.mdx +14 -0
  160. package/docs/snippets/tests/match-image-replay.mdx +7 -0
  161. package/docs/snippets/tests/match-image-yaml.mdx +17 -0
  162. package/docs/snippets/tests/press-keys-replay.mdx +7 -0
  163. package/docs/snippets/tests/press-keys-yaml.mdx +36 -0
  164. package/docs/snippets/tests/remember-replay.mdx +7 -0
  165. package/docs/snippets/tests/remember-yaml.mdx +28 -0
  166. package/docs/snippets/tests/scroll-replay.mdx +7 -0
  167. package/docs/snippets/tests/scroll-until-image-replay.mdx +7 -0
  168. package/docs/snippets/tests/scroll-until-image-yaml.mdx +14 -0
  169. package/docs/snippets/tests/scroll-until-text-replay.mdx +7 -0
  170. package/docs/snippets/tests/scroll-until-text-yaml.mdx +17 -0
  171. package/docs/snippets/tests/scroll-yaml.mdx +30 -0
  172. package/docs/snippets/tests/type-repeated-replay.mdx +7 -0
  173. package/docs/snippets/tests/type-repeated-yaml.mdx +22 -0
  174. package/docs/snippets/tests/type-replay.mdx +7 -0
  175. package/docs/snippets/tests/type-yaml.mdx +28 -0
  176. package/docs/snippets/tests/wait-for-image-replay.mdx +7 -0
  177. package/docs/snippets/tests/wait-for-image-yaml.mdx +18 -0
  178. package/docs/snippets/tests/wait-for-text-replay.mdx +7 -0
  179. package/docs/snippets/tests/wait-for-text-yaml.mdx +18 -0
  180. package/docs/snippets/tests/wait-replay.mdx +7 -0
  181. package/docs/snippets/tests/wait-yaml.mdx +13 -0
  182. package/docs/styles.css +65 -0
  183. package/docs/v6/account/dashboard.mdx +16 -0
  184. package/docs/v6/account/enterprise.mdx +110 -0
  185. package/docs/v6/account/pricing.mdx +33 -0
  186. package/docs/v6/account/projects.mdx +33 -0
  187. package/docs/v6/account/team.mdx +35 -0
  188. package/docs/v6/action/ami.mdx +109 -0
  189. package/docs/v6/action/performance.mdx +105 -0
  190. package/docs/v6/action/secrets.mdx +93 -0
  191. package/docs/v6/apps/chrome-extensions.mdx +48 -0
  192. package/docs/v6/apps/desktop-apps.mdx +93 -0
  193. package/docs/v6/apps/mobile-apps.mdx +26 -0
  194. package/docs/v6/apps/static-websites.mdx +54 -0
  195. package/docs/v6/apps/tauri-apps.mdx +361 -0
  196. package/docs/v6/bugs/jira.mdx +232 -0
  197. package/docs/v6/cli/overview.mdx +66 -0
  198. package/docs/v6/commands/assert.mdx +45 -0
  199. package/docs/v6/commands/exec.mdx +276 -0
  200. package/docs/v6/commands/focus-application.mdx +44 -0
  201. package/docs/v6/commands/hover-image.mdx +69 -0
  202. package/docs/v6/commands/hover-text.mdx +47 -0
  203. package/docs/v6/commands/if.mdx +53 -0
  204. package/docs/v6/commands/match-image.mdx +67 -0
  205. package/docs/v6/commands/press-keys.mdx +87 -0
  206. package/docs/v6/commands/remember.mdx +49 -0
  207. package/docs/v6/commands/run.mdx +44 -0
  208. package/docs/v6/commands/scroll-until-image.mdx +66 -0
  209. package/docs/v6/commands/scroll-until-text.mdx +60 -0
  210. package/docs/v6/commands/scroll.mdx +69 -0
  211. package/docs/v6/commands/type.mdx +45 -0
  212. package/docs/v6/commands/wait-for-image.mdx +54 -0
  213. package/docs/v6/commands/wait-for-text.mdx +48 -0
  214. package/docs/v6/commands/wait.mdx +45 -0
  215. package/docs/v6/exporting/junit.mdx +218 -0
  216. package/docs/v6/exporting/playwright.mdx +197 -0
  217. package/docs/v6/features/auto-healing.mdx +144 -0
  218. package/docs/v6/features/generation.mdx +116 -0
  219. package/docs/v6/features/parallel-testing.mdx +151 -0
  220. package/docs/v6/features/reusable-snippets.mdx +131 -0
  221. package/docs/v6/features/selectorless.mdx +80 -0
  222. package/docs/v6/features/visual-assertions.mdx +139 -0
  223. package/docs/v6/getting-started/ci.mdx +146 -0
  224. package/docs/v6/getting-started/cli.mdx +91 -0
  225. package/docs/v6/getting-started/editing.mdx +100 -0
  226. package/docs/v6/getting-started/playwright.mdx +342 -0
  227. package/docs/v6/getting-started/running.mdx +48 -0
  228. package/docs/v6/getting-started/self-hosting.mdx +408 -0
  229. package/docs/v6/getting-started/vscode.mdx +88 -0
  230. package/docs/v6/guide/assertions.mdx +189 -0
  231. package/docs/v6/guide/authentication.mdx +136 -0
  232. package/docs/v6/guide/code.mdx +65 -0
  233. package/docs/v6/guide/dashcam.mdx +118 -0
  234. package/docs/v6/guide/environment-variables.mdx +26 -0
  235. package/docs/v6/guide/lifecycle.mdx +242 -0
  236. package/docs/v6/guide/locating.mdx +141 -0
  237. package/docs/v6/guide/protips.mdx +43 -0
  238. package/docs/v6/guide/variables.mdx +143 -0
  239. package/docs/v6/guide/waiting.mdx +130 -0
  240. package/docs/v6/importing/csv.mdx +196 -0
  241. package/docs/v6/importing/gherkin.mdx +143 -0
  242. package/docs/v6/importing/jira.mdx +164 -0
  243. package/docs/v6/importing/testrail.mdx +162 -0
  244. package/docs/v6/integrations/electron.mdx +146 -0
  245. package/docs/v6/integrations/netlify.mdx +100 -0
  246. package/docs/v6/integrations/vercel.mdx +125 -0
  247. package/docs/v6/interactive/explore.mdx +99 -0
  248. package/docs/v6/interactive/run.mdx +52 -0
  249. package/docs/v6/interactive/save.mdx +63 -0
  250. package/docs/v6/overview/comparison.mdx +101 -0
  251. package/docs/v6/overview/faq.mdx +162 -0
  252. package/docs/v6/overview/performance.mdx +52 -0
  253. package/docs/v6/overview/quickstart.mdx +137 -0
  254. package/docs/v6/overview/what-is-testdriver.mdx +85 -0
  255. package/docs/v6/scenarios/ai-chatbot.mdx +28 -0
  256. package/docs/v6/scenarios/cookie-banner.mdx +32 -0
  257. package/docs/v6/scenarios/file-upload.mdx +33 -0
  258. package/docs/v6/scenarios/form-filling.mdx +32 -0
  259. package/docs/v6/scenarios/log-in.mdx +75 -0
  260. package/docs/v6/scenarios/pdf-generation.mdx +25 -0
  261. package/docs/v6/scenarios/spell-check.mdx +22 -0
  262. package/docs/v6/security/action.mdx +84 -0
  263. package/docs/v6/security/agent.mdx +73 -0
  264. package/docs/v6/security/platform.mdx +77 -0
  265. package/docs/v6/tutorials/advanced-test.mdx +81 -0
  266. package/docs/v6/tutorials/basic-test.mdx +45 -0
  267. package/docs/v7/_drafts/agents.mdx +843 -0
  268. package/docs/v7/_drafts/architecture.mdx +399 -0
  269. package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
  270. package/docs/v7/_drafts/awesome-logs-quick-ref.mdx +100 -0
  271. package/docs/v7/_drafts/best-practices.mdx +486 -0
  272. package/docs/v7/_drafts/caching-ai.mdx +215 -0
  273. package/docs/v7/_drafts/caching-selectors.mdx +424 -0
  274. package/docs/v7/_drafts/caching.mdx +366 -0
  275. package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
  276. package/docs/v7/_drafts/commands/assert.mdx +45 -0
  277. package/docs/v7/_drafts/commands/exec.mdx +276 -0
  278. package/docs/v7/_drafts/commands/focus-application.mdx +44 -0
  279. package/docs/v7/_drafts/commands/hover-image.mdx +69 -0
  280. package/docs/v7/_drafts/commands/hover-text.mdx +47 -0
  281. package/docs/v7/_drafts/commands/if.mdx +53 -0
  282. package/docs/v7/_drafts/commands/match-image.mdx +67 -0
  283. package/docs/v7/_drafts/commands/press-keys.mdx +87 -0
  284. package/docs/v7/_drafts/commands/remember.mdx +49 -0
  285. package/docs/v7/_drafts/commands/run.mdx +44 -0
  286. package/docs/v7/_drafts/commands/scroll-until-image.mdx +66 -0
  287. package/docs/v7/_drafts/commands/scroll-until-text.mdx +60 -0
  288. package/docs/v7/_drafts/commands/scroll.mdx +69 -0
  289. package/docs/v7/_drafts/commands/type.mdx +45 -0
  290. package/docs/v7/_drafts/commands/wait-for-image.mdx +54 -0
  291. package/docs/v7/_drafts/commands/wait-for-text.mdx +48 -0
  292. package/docs/v7/_drafts/commands/wait.mdx +45 -0
  293. package/docs/v7/_drafts/configuration.mdx +378 -0
  294. package/docs/v7/_drafts/contributing.mdx +174 -0
  295. package/docs/v7/_drafts/core.mdx +458 -0
  296. package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
  297. package/docs/v7/_drafts/debugging.mdx +349 -0
  298. package/docs/v7/_drafts/error-handling.mdx +501 -0
  299. package/docs/v7/_drafts/faq.mdx +393 -0
  300. package/docs/v7/_drafts/hooks.mdx +360 -0
  301. package/docs/v7/_drafts/init-command.mdx +95 -0
  302. package/docs/v7/_drafts/installation.mdx +420 -0
  303. package/docs/v7/_drafts/migration.mdx +562 -0
  304. package/docs/v7/_drafts/observable.mdx +604 -0
  305. package/docs/v7/_drafts/playwright.mdx +342 -0
  306. package/docs/v7/_drafts/plugin-migration.mdx +220 -0
  307. package/docs/v7/_drafts/powerful.mdx +419 -0
  308. package/docs/v7/_drafts/presets.mdx +210 -0
  309. package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
  310. package/docs/v7/_drafts/prompt-cache.mdx +200 -0
  311. package/docs/v7/_drafts/provision.mdx +390 -0
  312. package/docs/v7/_drafts/quick-start-test-recording.mdx +214 -0
  313. package/docs/v7/_drafts/readme.mdx +135 -0
  314. package/docs/v7/_drafts/reports.mdx +414 -0
  315. package/docs/v7/_drafts/scalable.mdx +763 -0
  316. package/docs/v7/_drafts/screenshot.mdx +155 -0
  317. package/docs/v7/_drafts/sdk-awesome-logs.mdx +468 -0
  318. package/docs/v7/_drafts/sdk-browser-rendering.mdx +167 -0
  319. package/docs/v7/_drafts/sdk-migration.mdx +474 -0
  320. package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
  321. package/docs/v7/_drafts/self-hosting.mdx +369 -0
  322. package/docs/v7/_drafts/test-recording.mdx +382 -0
  323. package/docs/v7/_drafts/troubleshooting.mdx +526 -0
  324. package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
  325. package/docs/v7/_drafts/vitest.mdx +535 -0
  326. package/docs/v7/_drafts/writing-tests.mdx +25 -0
  327. package/docs/v7/ai.mdx +205 -0
  328. package/docs/v7/assert.mdx +316 -0
  329. package/docs/v7/aws-setup.mdx +449 -0
  330. package/docs/v7/cache.mdx +223 -0
  331. package/docs/v7/caching.mdx +128 -0
  332. package/docs/v7/captcha.mdx +159 -0
  333. package/docs/v7/ci-cd.mdx +603 -0
  334. package/docs/v7/click.mdx +287 -0
  335. package/docs/v7/client.mdx +478 -0
  336. package/docs/v7/copilot/auto-healing.mdx +265 -0
  337. package/docs/v7/copilot/creating-tests.mdx +156 -0
  338. package/docs/v7/copilot/github.mdx +143 -0
  339. package/docs/v7/copilot/running-tests.mdx +149 -0
  340. package/docs/v7/copilot/setup.mdx +143 -0
  341. package/docs/v7/customizing-devices.mdx +319 -0
  342. package/docs/v7/dashcam.mdx +419 -0
  343. package/docs/v7/debugging-with-screenshots.mdx +402 -0
  344. package/docs/v7/device-config.mdx +317 -0
  345. package/docs/v7/double-click.mdx +102 -0
  346. package/docs/v7/elements.mdx +606 -0
  347. package/docs/v7/enterprise.mdx +9 -0
  348. package/docs/v7/errors.mdx +248 -0
  349. package/docs/v7/events.mdx +358 -0
  350. package/docs/v7/examples/ai.mdx +72 -0
  351. package/docs/v7/examples/assert.mdx +72 -0
  352. package/docs/v7/examples/captcha-api.mdx +92 -0
  353. package/docs/v7/examples/chrome-extension.mdx +132 -0
  354. package/docs/v7/examples/drag-and-drop.mdx +100 -0
  355. package/docs/v7/examples/element-not-found.mdx +67 -0
  356. package/docs/v7/examples/exec-output.mdx +85 -0
  357. package/docs/v7/examples/exec-pwsh.mdx +83 -0
  358. package/docs/v7/examples/focus-window.mdx +62 -0
  359. package/docs/v7/examples/hover-image.mdx +94 -0
  360. package/docs/v7/examples/hover-text.mdx +69 -0
  361. package/docs/v7/examples/installer.mdx +91 -0
  362. package/docs/v7/examples/launch-vscode-linux.mdx +101 -0
  363. package/docs/v7/examples/match-image.mdx +96 -0
  364. package/docs/v7/examples/press-keys.mdx +92 -0
  365. package/docs/v7/examples/scroll-keyboard.mdx +79 -0
  366. package/docs/v7/examples/scroll-until-image.mdx +81 -0
  367. package/docs/v7/examples/scroll-until-text.mdx +109 -0
  368. package/docs/v7/examples/scroll.mdx +81 -0
  369. package/docs/v7/examples/type.mdx +92 -0
  370. package/docs/v7/examples/windows-installer.mdx +89 -0
  371. package/docs/v7/exec.mdx +318 -0
  372. package/docs/v7/find.mdx +830 -0
  373. package/docs/v7/focus-application.mdx +294 -0
  374. package/docs/v7/generating-tests.mdx +36 -0
  375. package/docs/v7/hosted.mdx +158 -0
  376. package/docs/v7/hover.mdx +279 -0
  377. package/docs/v7/locating-elements.mdx +71 -0
  378. package/docs/v7/making-assertions.mdx +32 -0
  379. package/docs/v7/mcp.mdx +9 -0
  380. package/docs/v7/mouse-down.mdx +161 -0
  381. package/docs/v7/mouse-up.mdx +164 -0
  382. package/docs/v7/parse.mdx +237 -0
  383. package/docs/v7/performing-actions.mdx +54 -0
  384. package/docs/v7/press-keys.mdx +349 -0
  385. package/docs/v7/provision.mdx +333 -0
  386. package/docs/v7/quickstart.mdx +173 -0
  387. package/docs/v7/redraw.mdx +216 -0
  388. package/docs/v7/reusable-code.mdx +249 -0
  389. package/docs/v7/right-click.mdx +123 -0
  390. package/docs/v7/running-tests.mdx +185 -0
  391. package/docs/v7/screenshot.mdx +249 -0
  392. package/docs/v7/screenshots.mdx +186 -0
  393. package/docs/v7/scroll.mdx +336 -0
  394. package/docs/v7/secrets.mdx +115 -0
  395. package/docs/v7/self-hosted.mdx +149 -0
  396. package/docs/v7/type.mdx +358 -0
  397. package/docs/v7/variables.mdx +111 -0
  398. package/docs/v7/wait.mdx +52 -0
  399. package/docs/v7/waiting-for-elements.mdx +90 -0
  400. package/docs/v7/what-is-testdriver.mdx +54 -0
  401. package/eslint.config.js +67 -0
  402. package/examples/ai.test.mjs +31 -0
  403. package/examples/assert.test.mjs +47 -0
  404. package/examples/chrome-extension.test.mjs +97 -0
  405. package/examples/config.mjs +5 -0
  406. package/examples/element-not-found.test.mjs +27 -0
  407. package/examples/exec-output.test.mjs +60 -0
  408. package/examples/exec-pwsh.test.mjs +58 -0
  409. package/examples/findall-coffee-icons.test.mjs +42 -0
  410. package/examples/focus-window.test.mjs +37 -0
  411. package/examples/formatted-logging.test.mjs +27 -0
  412. package/examples/hover-image.test.mjs +53 -0
  413. package/examples/hover-text-with-description.test.mjs +57 -0
  414. package/examples/hover-text.test.mjs +28 -0
  415. package/examples/installer.test.mjs +50 -0
  416. package/examples/launch-vscode-linux.test.mjs +55 -0
  417. package/examples/match-image.test.mjs +55 -0
  418. package/examples/parse.test.mjs +19 -0
  419. package/examples/press-keys.test.mjs +44 -0
  420. package/examples/prompt.test.mjs +34 -0
  421. package/examples/scroll-keyboard.test.mjs +38 -0
  422. package/examples/scroll-until-image.test.mjs +40 -0
  423. package/examples/scroll.test.mjs +42 -0
  424. package/examples/type.test.mjs +46 -0
  425. package/examples/windows-installer.test.mjs +54 -0
  426. package/index.js +2 -0
  427. package/interfaces/cli/commands/init.js +438 -0
  428. package/interfaces/cli/commands/setup.js +382 -0
  429. package/interfaces/cli/lib/base.js +285 -0
  430. package/interfaces/cli.js +20 -0
  431. package/interfaces/junit-reporter.js +290 -0
  432. package/interfaces/logger.js +388 -0
  433. package/interfaces/readline.js +234 -0
  434. package/interfaces/shared-test-state.mjs +64 -0
  435. package/interfaces/vitest-plugin.d.ts +115 -0
  436. package/interfaces/vitest-plugin.mjs +1698 -0
  437. package/lib/captcha/solver.js +358 -0
  438. package/lib/core/Dashcam.js +533 -0
  439. package/lib/core/index.d.ts +172 -0
  440. package/lib/core/index.js +12 -0
  441. package/lib/environments.json +18 -0
  442. package/lib/github-comment-formatter.js +263 -0
  443. package/lib/github-comment.mjs +452 -0
  444. package/lib/init-project.js +575 -0
  445. package/lib/presets/index.mjs +331 -0
  446. package/lib/resolve-channel.js +46 -0
  447. package/lib/sentry.js +417 -0
  448. package/lib/vitest/hooks.d.ts +57 -0
  449. package/lib/vitest/hooks.mjs +674 -0
  450. package/lib/vitest/setup-aws.mjs +247 -0
  451. package/lib/vitest/setup-self-hosted.mjs +151 -0
  452. package/lib/vitest/setup.mjs +46 -0
  453. package/manual/captcha-api.test.mjs +51 -0
  454. package/manual/drag-and-drop.test.mjs +59 -0
  455. package/manual/flake-diffthreshold-001.test.mjs +9 -0
  456. package/manual/flake-diffthreshold-01.test.mjs +9 -0
  457. package/manual/flake-diffthreshold-05.test.mjs +9 -0
  458. package/manual/flake-noredraw-cache.test.mjs +9 -0
  459. package/manual/flake-noredraw-nocache.test.mjs +9 -0
  460. package/manual/flake-redraw-cache.test.mjs +9 -0
  461. package/manual/flake-redraw-nocache.test.mjs +9 -0
  462. package/manual/flake-rocket-match.test.mjs +30 -0
  463. package/manual/flake-shared.mjs +51 -0
  464. package/manual/no-provision.test.mjs +31 -0
  465. package/manual/packer-hover-image.test.mjs +176 -0
  466. package/manual/scroll-until-text.test.mjs +68 -0
  467. package/manual/test-init-command.js +223 -0
  468. package/mcp-server/README.md +322 -0
  469. package/mcp-server/dist/codegen.d.ts +9 -0
  470. package/mcp-server/dist/codegen.js +165 -0
  471. package/mcp-server/dist/mcp-app.html +114 -0
  472. package/mcp-server/dist/package.json +1 -0
  473. package/mcp-server/dist/provision-types.d.ts +290 -0
  474. package/mcp-server/dist/provision-types.js +174 -0
  475. package/mcp-server/dist/server.d.ts +6 -0
  476. package/mcp-server/dist/server.mjs +1925 -0
  477. package/mcp-server/dist/session.d.ts +85 -0
  478. package/mcp-server/dist/session.js +152 -0
  479. package/mcp-server/mcp-app.html +28 -0
  480. package/mcp-server/mcp-config.example.json +19 -0
  481. package/mcp-server/package-lock.json +4027 -0
  482. package/mcp-server/package.json +31 -0
  483. package/mcp-server/src/codegen.ts +189 -0
  484. package/mcp-server/src/mcp-app.css +360 -0
  485. package/mcp-server/src/mcp-app.ts +547 -0
  486. package/mcp-server/src/provision-types.ts +209 -0
  487. package/mcp-server/src/server.ts +2391 -0
  488. package/mcp-server/src/session.ts +194 -0
  489. package/mcp-server/tsconfig.json +16 -0
  490. package/mcp-server/vite.config.ts +23 -0
  491. package/package.json +158 -0
  492. package/schema.json +1046 -0
  493. package/scripts/generate-skills.js +94 -0
  494. package/sdk-log-formatter.js +1157 -0
  495. package/sdk.d.ts +1486 -0
  496. package/sdk.js +4336 -0
  497. package/setup/aws/cloudformation.yaml +463 -0
  498. package/setup/aws/disable-defender.sh +42 -0
  499. package/setup/aws/install-dev-runner.sh +79 -0
  500. package/setup/aws/spawn-runner.sh +289 -0
  501. package/test/captcha-solver.test.mjs +152 -0
  502. package/test/chrome-remote-debugging.test.mjs +66 -0
  503. package/test/duckduckgo/experiment.test.mjs +28 -0
  504. package/test/duckduckgo/setup.test.mjs +29 -0
  505. package/test/manual/debug-locate-response.js +82 -0
  506. package/test/manual/reconnect-provision.test.mjs +49 -0
  507. package/test/manual/test-console-logs.test.mjs +42 -0
  508. package/test/manual/test-find-api.js +73 -0
  509. package/test/manual/test-init.sh +54 -0
  510. package/test/manual/test-prompt-cache.js +97 -0
  511. package/test/manual/test-provision-auth.mjs +22 -0
  512. package/test/manual/test-sandbox-render.js +29 -0
  513. package/test/manual/test-sdk-methods.js +15 -0
  514. package/test/manual/test-sdk-refactor.js +53 -0
  515. package/test/manual/test-stack-trace.mjs +57 -0
  516. package/test/manual/verify-element-api.js +89 -0
  517. package/test/manual/verify-types.js +0 -0
  518. package/test/manual-unawaited-promise.test.mjs +31 -0
  519. package/vitest.config.mjs +58 -0
  520. package/vitest.runner.config.mjs +33 -0
  521. package/vscode-extension/.vscodeignore +12 -0
  522. package/vscode-extension/README.md +94 -0
  523. package/vscode-extension/media/icon.png +0 -0
  524. package/vscode-extension/package-lock.json +4126 -0
  525. package/vscode-extension/package.json +86 -0
  526. package/vscode-extension/src/extension.ts +829 -0
  527. package/vscode-extension/testdriverai-0.1.0.vsix +0 -0
  528. package/vscode-extension/tsconfig.json +16 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Vitest Setup File for AWS Self-Hosted TestDriver Instances
3
+ *
4
+ * This setup file spawns a fresh AWS instance before each test
5
+ * and terminates it after each test completes.
6
+ *
7
+ * Usage in vitest.config.mjs:
8
+ * ```js
9
+ * export default defineConfig({
10
+ * test: {
11
+ * setupFiles: [
12
+ * 'testdriverai/vitest/setup',
13
+ * 'testdriverai/vitest/setup-aws'
14
+ * ],
15
+ * },
16
+ * });
17
+ * ```
18
+ *
19
+ * Required environment variables:
20
+ * - AWS_ACCESS_KEY_ID
21
+ * - AWS_SECRET_ACCESS_KEY
22
+ * - AWS_REGION (default: us-east-2)
23
+ * - AWS_LAUNCH_TEMPLATE_ID
24
+ * - AMI_ID
25
+ */
26
+
27
+ import { execSync, spawn } from "child_process";
28
+ import { dirname, join } from "path";
29
+ import { fileURLToPath } from "url";
30
+ import { beforeEach } from "vitest";
31
+
32
+ const __filename = fileURLToPath(import.meta.url);
33
+ const __dirname = dirname(__filename);
34
+
35
+ // Store instance info per test
36
+ const testInstances = new Map();
37
+
38
+ // Global object to share instance termination callbacks with hooks.mjs
39
+ globalThis.__testdriverAWS = globalThis.__testdriverAWS || {
40
+ instances: testInstances,
41
+ /**
42
+ * Terminate the instance for a given test ID
43
+ * Called by hooks.mjs after dashcam.stop() completes
44
+ */
45
+ async terminateInstance(testId) {
46
+ const instanceInfo = testInstances.get(testId);
47
+ if (!instanceInfo) {
48
+ return; // No instance was spawned for this test
49
+ }
50
+
51
+ const { instanceId, awsRegion } = instanceInfo;
52
+
53
+ console.log(`[TestDriver] Terminating AWS instance: ${instanceId}`);
54
+
55
+ try {
56
+ execSync(
57
+ `aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
58
+ {
59
+ encoding: "utf-8",
60
+ env: process.env,
61
+ stdio: "inherit",
62
+ },
63
+ );
64
+
65
+ console.log(`[TestDriver] Instance terminated: ${instanceId}`);
66
+ } catch (error) {
67
+ console.error(
68
+ "[TestDriver] Failed to terminate instance:",
69
+ error.message,
70
+ );
71
+ // Don't throw - we don't want to fail the test because of cleanup issues
72
+ } finally {
73
+ testInstances.delete(testId);
74
+ }
75
+ },
76
+ };
77
+
78
+ /**
79
+ * Cleanup function to terminate all running instances
80
+ * Called on process exit to ensure no orphaned instances
81
+ */
82
+ function cleanupAllInstances() {
83
+ if (testInstances.size === 0) {
84
+ return;
85
+ }
86
+
87
+ console.log(
88
+ `[TestDriver] Emergency cleanup: terminating ${testInstances.size} instance(s)`,
89
+ );
90
+
91
+ for (const [testId, instanceInfo] of testInstances.entries()) {
92
+ const { instanceId, awsRegion } = instanceInfo;
93
+
94
+ try {
95
+ console.log(`[TestDriver] Terminating instance: ${instanceId}`);
96
+ execSync(
97
+ `aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
98
+ {
99
+ encoding: "utf-8",
100
+ stdio: "inherit",
101
+ },
102
+ );
103
+ } catch (error) {
104
+ console.error(
105
+ `[TestDriver] Failed to terminate instance ${instanceId}:`,
106
+ error.message,
107
+ );
108
+ }
109
+ }
110
+
111
+ testInstances.clear();
112
+ }
113
+
114
+ // Register cleanup handlers for various exit scenarios
115
+ process.on("exit", cleanupAllInstances);
116
+ process.on("SIGINT", () => {
117
+ cleanupAllInstances();
118
+ // Don't call process.exit here - let the signal handler do its job
119
+ });
120
+ process.on("SIGTERM", () => {
121
+ cleanupAllInstances();
122
+ // Don't call process.exit here - let the signal handler do its job
123
+ });
124
+ process.on("uncaughtException", (error) => {
125
+ console.error("[TestDriver] Uncaught exception:", error);
126
+ cleanupAllInstances();
127
+ // Don't call process.exit here - let Node.js handle the exception
128
+ });
129
+
130
+ beforeEach(async (context) => {
131
+ // Only spawn if TD_OS=windows (indicates Windows self-hosted mode)
132
+ if (process.env.TD_OS !== "windows") {
133
+ return;
134
+ }
135
+
136
+ // If TD_IP is already set, use it and skip spawning
137
+ if (process.env.TD_IP) {
138
+ console.log(`[TestDriver] Using existing instance at ${process.env.TD_IP}`);
139
+ context.ip = process.env.TD_IP;
140
+ return;
141
+ }
142
+
143
+ // If ip is provided via plugin options, skip spawning
144
+ const pluginIp = globalThis.__testdriverPlugin?.state?.testDriverOptions?.ip;
145
+ if (pluginIp) {
146
+ console.log(`[TestDriver] Using ip from plugin options: ${pluginIp}`);
147
+ context.ip = pluginIp;
148
+ return;
149
+ }
150
+
151
+ if (!process.env.AWS_LAUNCH_TEMPLATE_ID || !process.env.AMI_ID) {
152
+ throw new Error(
153
+ "[TestDriver] TD_OS=windows requires AWS_LAUNCH_TEMPLATE_ID and AMI_ID environment variables",
154
+ );
155
+ }
156
+
157
+ // Check if AWS CLI is installed
158
+ try {
159
+ execSync("which aws", { stdio: "ignore" });
160
+ } catch (error) {
161
+ throw new Error(
162
+ "[TestDriver] AWS CLI is not installed. Install it from https://aws.amazon.com/cli/",
163
+ );
164
+ }
165
+
166
+ const testId = context.task.id;
167
+
168
+ console.log(
169
+ `[TestDriver] Spawning AWS instance for test: ${context.task.name}`,
170
+ );
171
+
172
+ try {
173
+ // Find the spawn-runner.sh script (relative to this file)
174
+ const spawnScriptPath = join(__dirname, "../../setup/aws/spawn-runner.sh");
175
+
176
+ // Execute spawn-runner.sh with live output streaming
177
+ const output = await new Promise((resolve, reject) => {
178
+ const child = spawn("bash", [spawnScriptPath], {
179
+ env: {
180
+ ...process.env,
181
+ AWS_REGION: process.env.AWS_REGION || "us-east-2",
182
+ RESOLUTION: process.env.RESOLUTION || "1920x1080",
183
+ },
184
+ });
185
+
186
+ let stdout = "";
187
+ let stderr = "";
188
+
189
+ // Stream stdout in real-time
190
+ child.stdout.on("data", (data) => {
191
+ const str = data.toString();
192
+ process.stdout.write(str); // Show output immediately
193
+ stdout += str;
194
+ });
195
+
196
+ // Stream stderr in real-time
197
+ child.stderr.on("data", (data) => {
198
+ const str = data.toString();
199
+ process.stderr.write(str); // Show errors immediately
200
+ stderr += str;
201
+ });
202
+
203
+ child.on("close", (code) => {
204
+ if (code !== 0) {
205
+ reject(
206
+ new Error(`spawn-runner.sh exited with code ${code}\n${stderr}`),
207
+ );
208
+ } else {
209
+ resolve(stdout);
210
+ }
211
+ });
212
+
213
+ child.on("error", (err) => {
214
+ reject(err);
215
+ });
216
+ });
217
+
218
+ // Parse the output
219
+ const publicIpMatch = output.match(/PUBLIC_IP=(.+)/);
220
+ const instanceIdMatch = output.match(/INSTANCE_ID=(.+)/);
221
+ const awsRegionMatch = output.match(/AWS_REGION=(.+)/);
222
+
223
+ if (!publicIpMatch || !instanceIdMatch || !awsRegionMatch) {
224
+ throw new Error("Failed to parse spawn-runner.sh output");
225
+ }
226
+
227
+ const publicIp = publicIpMatch[1].trim();
228
+ const instanceId = instanceIdMatch[1].trim();
229
+ const awsRegion = awsRegionMatch[1].trim();
230
+
231
+ // Store instance info for this test
232
+ testInstances.set(testId, { publicIp, instanceId, awsRegion });
233
+
234
+ // Set IP on test context (not process.env to avoid conflicts in parallel tests)
235
+ context.ip = publicIp;
236
+ context.instanceId = instanceId;
237
+
238
+ console.log(`[TestDriver] Instance spawned: ${instanceId} at ${publicIp}`);
239
+ } catch (error) {
240
+ console.error("[TestDriver] Failed to spawn AWS instance:", error.message);
241
+ throw error;
242
+ }
243
+ });
244
+
245
+ // NOTE: No afterEach hook here!
246
+ // Instance termination is now handled by hooks.mjs AFTER dashcam.stop() completes.
247
+ // This ensures dashcam can properly stop before the instance is terminated.
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Vitest Setup File for Self-Hosted TestDriver Instances
3
+ *
4
+ * This setup file spawns a fresh AWS instance before each test
5
+ * and terminates it after each test completes.
6
+ *
7
+ * Usage in vitest.config.mjs:
8
+ * ```js
9
+ * export default defineConfig({
10
+ * test: {
11
+ * setupFiles: [
12
+ * 'testdriverai/vitest/setup',
13
+ * 'testdriverai/vitest/setup-self-hosted'
14
+ * ],
15
+ * },
16
+ * });
17
+ * ```
18
+ *
19
+ * Required environment variables:
20
+ * - AWS_ACCESS_KEY_ID
21
+ * - AWS_SECRET_ACCESS_KEY
22
+ * - AWS_REGION (default: us-east-2)
23
+ * - AWS_LAUNCH_TEMPLATE_ID
24
+ * - AMI_ID
25
+ */
26
+
27
+ import { execSync } from 'child_process';
28
+ import { dirname, join } from 'path';
29
+ import { fileURLToPath } from 'url';
30
+ import { beforeEach } from 'vitest';
31
+
32
+ const __filename = fileURLToPath(import.meta.url);
33
+ const __dirname = dirname(__filename);
34
+
35
+ // Store instance info per test
36
+ const testInstances = new Map();
37
+
38
+ // Global object to share instance termination callbacks with hooks.mjs
39
+ // Use the same global as setup-aws.mjs for consistency
40
+ if (!globalThis.__testdriverAWS) {
41
+ globalThis.__testdriverAWS = {
42
+ instances: testInstances,
43
+ /**
44
+ * Terminate the instance for a given test ID
45
+ * Called by hooks.mjs after dashcam.stop() completes
46
+ */
47
+ async terminateInstance(testId) {
48
+ const instanceInfo = testInstances.get(testId);
49
+ if (!instanceInfo) {
50
+ return; // No instance was spawned for this test
51
+ }
52
+
53
+ const { instanceId, awsRegion } = instanceInfo;
54
+
55
+ console.log(`[TestDriver] Terminating AWS instance: ${instanceId}`);
56
+
57
+ try {
58
+ execSync(
59
+ `aws ec2 terminate-instances --region "${awsRegion}" --instance-ids "${instanceId}"`,
60
+ {
61
+ encoding: 'utf-8',
62
+ env: process.env,
63
+ stdio: 'inherit',
64
+ }
65
+ );
66
+
67
+ console.log(`[TestDriver] Instance terminated: ${instanceId}`);
68
+ } catch (error) {
69
+ console.error('[TestDriver] Failed to terminate instance:', error.message);
70
+ // Don't throw - we don't want to fail the test because of cleanup issues
71
+ } finally {
72
+ testInstances.delete(testId);
73
+ }
74
+ }
75
+ };
76
+ }
77
+
78
+ beforeEach(async (context) => {
79
+ // Only spawn if TD_OS=windows (indicates Windows self-hosted mode)
80
+ if (process.env.TD_OS !== 'windows') {
81
+ return;
82
+ }
83
+
84
+ // If TD_IP is already set, use it and skip spawning
85
+ if (process.env.TD_IP) {
86
+ console.log(`[TestDriver] Using existing instance at ${process.env.TD_IP}`);
87
+ context.ip = process.env.TD_IP;
88
+ return;
89
+ }
90
+
91
+ // If ip is provided via plugin options, skip spawning
92
+ const pluginIp = globalThis.__testdriverPlugin?.state?.testDriverOptions?.ip;
93
+ if (pluginIp) {
94
+ console.log(`[TestDriver] Using ip from plugin options: ${pluginIp}`);
95
+ context.ip = pluginIp;
96
+ return;
97
+ }
98
+
99
+ // Verify AWS credentials are available
100
+ if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_LAUNCH_TEMPLATE_ID || !process.env.AMI_ID) {
101
+ throw new Error('[TestDriver] TD_OS=windows requires AWS credentials (AWS_ACCESS_KEY_ID, AWS_LAUNCH_TEMPLATE_ID, AMI_ID)');
102
+ }
103
+
104
+ const testId = context.task.id;
105
+
106
+ console.log(`[TestDriver] Spawning AWS instance for test: ${context.task.name}`);
107
+
108
+ try {
109
+ // Find the spawn-runner.sh script (relative to this file)
110
+ const spawnScriptPath = join(__dirname, '../../setup/aws/spawn-runner.sh');
111
+
112
+ // Execute spawn-runner.sh
113
+ const output = execSync(`sh ${spawnScriptPath}`, {
114
+ encoding: 'utf-8',
115
+ env: {
116
+ ...process.env,
117
+ AWS_REGION: process.env.AWS_REGION || 'us-east-2',
118
+ RESOLUTION: process.env.RESOLUTION || '1920x1080',
119
+ },
120
+ stdio: ['pipe', 'pipe', 'inherit'], // Inherit stderr for real-time logs
121
+ });
122
+
123
+ // Parse the output
124
+ const publicIpMatch = output.match(/PUBLIC_IP=(.+)/);
125
+ const instanceIdMatch = output.match(/INSTANCE_ID=(.+)/);
126
+ const awsRegionMatch = output.match(/AWS_REGION=(.+)/);
127
+
128
+ if (!publicIpMatch || !instanceIdMatch || !awsRegionMatch) {
129
+ throw new Error('Failed to parse spawn-runner.sh output');
130
+ }
131
+
132
+ const publicIp = publicIpMatch[1].trim();
133
+ const instanceId = instanceIdMatch[1].trim();
134
+ const awsRegion = awsRegionMatch[1].trim();
135
+
136
+ // Store instance info for this test (use global's map)
137
+ globalThis.__testdriverAWS.instances.set(testId, { publicIp, instanceId, awsRegion });
138
+
139
+ // Set IP on test context (not process.env to avoid conflicts in parallel tests)
140
+ context.ip = publicIp;
141
+
142
+ console.log(`[TestDriver] Instance spawned: ${instanceId} at ${publicIp}`);
143
+ } catch (error) {
144
+ console.error('[TestDriver] Failed to spawn AWS instance:', error.message);
145
+ throw error;
146
+ }
147
+ });
148
+
149
+ // NOTE: No afterEach hook here!
150
+ // Instance termination is now handled by hooks.mjs AFTER dashcam.stop() completes.
151
+ // This ensures dashcam can properly stop before the instance is terminated.
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Vitest Setup File for TestDriver
3
+ *
4
+ * This file is run by Vitest before each test file to set up
5
+ * the TestDriver plugin state and global helpers.
6
+ *
7
+ * Usage in vitest.config.mjs:
8
+ * ```js
9
+ * export default defineConfig({
10
+ * test: {
11
+ * setupFiles: ['testdriverai/vitest/setup'],
12
+ * },
13
+ * });
14
+ * ```
15
+ */
16
+
17
+ import {
18
+ clearDashcamUrls,
19
+ clearSuiteTestRun,
20
+ getAllDashcamUrls,
21
+ getDashcamUrl,
22
+ getPluginState,
23
+ getSuiteTestRun,
24
+ pluginState,
25
+ registerDashcamUrl,
26
+ setSuiteTestRun,
27
+ } from '../../interfaces/vitest-plugin.mjs';
28
+
29
+ // Set up global TestDriver plugin interface
30
+ // This allows tests and the SDK to communicate with the reporter
31
+ globalThis.__testdriverPlugin = {
32
+ state: pluginState,
33
+ registerDashcamUrl,
34
+ getDashcamUrl,
35
+ getAllDashcamUrls,
36
+ clearDashcamUrls,
37
+ getPluginState,
38
+ getSuiteTestRun,
39
+ setSuiteTestRun,
40
+ clearSuiteTestRun,
41
+ };
42
+
43
+ // Log that setup is complete (only in debug mode)
44
+ if (process.env.TD_LOG_LEVEL?.toLowerCase() === 'debug') {
45
+ console.log('[TestDriver] Setup file initialized, global plugin interface available');
46
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Test for testdriver.captcha() API
3
+ * Clean, simple API for solving captchas
4
+ */
5
+ import { describe, expect, it } from "vitest";
6
+ import { TestDriver } from "../lib/vitest/hooks.mjs";
7
+ import { getDefaults } from "./config.mjs";
8
+
9
+ console.log("DEBUG: process.env.TD_OS:", process.env.TD_OS);
10
+
11
+ describe("testdriver.captcha() API", () => {
12
+ it("should solve reCAPTCHA v3 with auto-detect", async (context) => {
13
+ const testdriver = TestDriver(context, { ...getDefaults(context) });
14
+
15
+ // Launch Chrome (remote debugging is enabled automatically on Linux)
16
+ await testdriver.provision.chrome({
17
+ url: "https://2captcha.com/demo/recaptcha-v3",
18
+ });
19
+
20
+ await testdriver.screenshot();
21
+
22
+ // Solve the captcha with just the API key - everything else is auto-detected!
23
+ const result = await testdriver.captcha({
24
+ apiKey: process.env.TWOCAPTCHA_API_KEY,
25
+ });
26
+
27
+ console.log("Captcha result:", result);
28
+ await testdriver.screenshot();
29
+
30
+ expect(result.success).toBe(true);
31
+ }, 180000);
32
+
33
+ it("should solve Cloudflare Turnstile", async (context) => {
34
+ const testdriver = TestDriver(context, { ...getDefaults(context) });
35
+
36
+ await testdriver.provision.chrome({
37
+ url: "https://2captcha.com/demo/cloudflare-turnstile",
38
+ });
39
+
40
+ await testdriver.screenshot();
41
+
42
+ const result = await testdriver.captcha({
43
+ apiKey: process.env.TWOCAPTCHA_API_KEY,
44
+ });
45
+
46
+ console.log("Turnstile result:", result);
47
+ await testdriver.screenshot();
48
+
49
+ expect(result.success).toBe(true);
50
+ }, 180000);
51
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * TestDriver SDK - Drag and Drop Test (Vitest)
3
+ * Converted from: testdriver/acceptance/drag-and-drop.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../lib/vitest/hooks.mjs";
8
+ import { getDefaults } from "./config.mjs";
9
+
10
+ const isLinux = (process.env.TD_OS || "linux") === "linux";
11
+
12
+ describe("Drag and Drop Test", () => {
13
+ it.skipIf(isLinux)(
14
+ 'should drag "New Text Document" to "Recycle Bin"',
15
+ async (context) => {
16
+ const testdriver = TestDriver(context, { ...getDefaults(context), headless: true });
17
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
18
+
19
+ //
20
+ // Show the desktop
21
+ await testdriver.pressKeys(["win", "d"]);
22
+
23
+ // Open the context menu
24
+ await testdriver.pressKeys(["shift", "f10"]);
25
+
26
+ // Hover over "New" in the context menu
27
+ const newOption = await testdriver.find(
28
+ "New, new option in the open context menu on the desktop",
29
+ );
30
+ await newOption.hover();
31
+
32
+ // Click "Text Document" in the context menu
33
+ const textDocOption = await testdriver.find(
34
+ "Text Document, text document option in the new submenu of the desktop context menu",
35
+ );
36
+ await textDocOption.click();
37
+
38
+ // Unfocus the "Text Document" text field
39
+ await testdriver.pressKeys(["esc"]);
40
+
41
+ // Drag the "New Text Document" icon to the "Recycle Bin"
42
+ const textDoc = await testdriver.find(
43
+ "New Text Document, new text document icon in the center of the desktop",
44
+ );
45
+ await textDoc.mouseDown();
46
+
47
+ const recycleBin = await testdriver.find(
48
+ "Recycle Bin, recycle bin icon in the top left corner of the desktop",
49
+ ).hover();
50
+ await recycleBin.mouseUp();
51
+
52
+ // Assert "New Text Document" icon is not on the Desktop
53
+ const result = await testdriver.assert(
54
+ 'the "New Text Document" icon is not visible on the Desktop',
55
+ );
56
+ expect(result).toBeTruthy();
57
+ },
58
+ );
59
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - diffThreshold=0.01, cache=true
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("screen=0.01, cache=true", {
7
+ redraw: { enabled: true, thresholds: { screen: 0.01 } },
8
+ cache: true,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - diffThreshold=0.1, cache=false
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("screen=0.1, cache=false", {
7
+ redraw: { enabled: true, thresholds: { screen: 0.1 } },
8
+ cache: false,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - diffThreshold=0.5, cache=true
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("screen=0.5, cache=true", {
7
+ redraw: { enabled: true, thresholds: { screen: 0.5 } },
8
+ cache: true,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - redraw=false, cache=true
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("redraw=false, cache=true", {
7
+ redraw: { enabled: false },
8
+ cache: true,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - redraw=false, cache=false
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("redraw=false, cache=false", {
7
+ redraw: { enabled: false },
8
+ cache: false,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - redraw=true, cache=true
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("redraw=true, cache=true", {
7
+ redraw: { enabled: true },
8
+ cache: true,
9
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Popup Loading - redraw=true, cache=false
3
+ */
4
+ import { popupLoadingTest } from "./flake-shared.mjs";
5
+
6
+ popupLoadingTest("redraw=true, cache=false", {
7
+ redraw: { enabled: true },
8
+ cache: false,
9
+ });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Popup Loading - Skip straight to the rocket match (skipToIcons=true)
3
+ */
4
+ import { describe, expect, it } from "vitest";
5
+ import { TestDriver } from "../lib/vitest/hooks.mjs";
6
+
7
+ describe("Rocket Match (skipToIcons)", () => {
8
+ it("should find the rocket in the icon grid", async (context) => {
9
+ const testdriver = TestDriver(context, {
10
+ preview: "ide",
11
+ ip: context.ip || process.env.TD_IP,
12
+ });
13
+
14
+ await testdriver.provision.chrome({
15
+ url: "https://v0-popup-with-loading-bar.vercel.app/?skipToIcons=true",
16
+ });
17
+
18
+ // Wait for the 5x5 grid of images to fully load and click the rocket
19
+ await testdriver.find("The icon of a rocket in the 5x5 grid of images", {
20
+ timeout: 60000,
21
+ zoom: 1,
22
+ }).click();
23
+
24
+ // Assert the success message appears
25
+ const rocketResult = await testdriver.assert(
26
+ "The text 'You found the rocket!' is visible on the page"
27
+ );
28
+ expect(rocketResult).toBeTruthy();
29
+ });
30
+ });