testdriverai 6.2.2 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/.github/workflows/acceptance-linux.yml +75 -0
  2. package/.github/workflows/acceptance-sdk-tests.yml +133 -0
  3. package/.vscode/settings.json +5 -1
  4. package/AGENTS.md +550 -0
  5. package/CODEOWNERS +0 -1
  6. package/README.md +126 -0
  7. package/{testdriver → _testdriver}/acceptance/drag-and-drop.yaml +2 -2
  8. package/{testdriver → _testdriver}/acceptance/snippets/login.yaml +1 -1
  9. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  10. package/{testdriver → _testdriver}/examples/web/lifecycle/prerun.yaml +6 -1
  11. package/{testdriver → _testdriver}/lifecycle/postrun.yaml +3 -2
  12. package/_testdriver/lifecycle/prerun.yaml +15 -0
  13. package/{testdriver → _testdriver}/lifecycle/provision.yaml +7 -2
  14. package/agent/index.js +300 -85
  15. package/agent/interface.js +15 -0
  16. package/agent/lib/cache.js +142 -0
  17. package/agent/lib/commander.js +1 -39
  18. package/agent/lib/commands.js +910 -296
  19. package/agent/lib/redraw.js +129 -41
  20. package/agent/lib/sandbox.js +29 -6
  21. package/agent/lib/sdk.js +22 -0
  22. package/agent/lib/system.js +0 -3
  23. package/agent/lib/validation.js +1 -7
  24. package/debug-locate-response.js +82 -0
  25. package/debugger/index.html +15 -4
  26. package/docs/ARCHITECTURE.md +424 -0
  27. package/docs/AWESOME_LOGS_QUICK_REF.md +100 -0
  28. package/docs/MIGRATION.md +425 -0
  29. package/docs/PRESETS.md +210 -0
  30. package/docs/QUICK_START_TEST_RECORDING.md +215 -0
  31. package/docs/SDK_AWESOME_LOGS.md +468 -0
  32. package/docs/TEST_RECORDING.md +388 -0
  33. package/docs/docs.json +286 -152
  34. package/docs/guide/best-practices-polling.mdx +154 -0
  35. package/docs/sdk-browser-rendering.md +167 -0
  36. package/docs/v6/getting-started/self-hosting.mdx +407 -0
  37. package/docs/{guide → v6/guide}/dashcam.mdx +1 -1
  38. package/docs/{guide → v6/guide}/environment-variables.mdx +4 -5
  39. package/docs/{guide → v6/guide}/lifecycle.mdx +1 -1
  40. package/docs/v6/overview/comparison.mdx +101 -0
  41. package/docs/v7/README.md +135 -0
  42. package/docs/v7/api/ai.mdx +205 -0
  43. package/docs/v7/api/assert.mdx +285 -0
  44. package/docs/v7/api/assertions.mdx +403 -0
  45. package/docs/v7/api/click.mdx +287 -0
  46. package/docs/v7/api/client.mdx +322 -0
  47. package/docs/v7/api/dashcam.mdx +497 -0
  48. package/docs/v7/api/doubleClick.mdx +102 -0
  49. package/docs/v7/api/elements.mdx +479 -0
  50. package/docs/v7/api/exec.mdx +346 -0
  51. package/docs/v7/api/find.mdx +316 -0
  52. package/docs/v7/api/focusApplication.mdx +294 -0
  53. package/docs/v7/api/hover.mdx +279 -0
  54. package/docs/v7/api/mouseDown.mdx +161 -0
  55. package/docs/v7/api/mouseUp.mdx +164 -0
  56. package/docs/v7/api/pressKeys.mdx +349 -0
  57. package/docs/v7/api/rightClick.mdx +123 -0
  58. package/docs/v7/api/sandbox.mdx +404 -0
  59. package/docs/v7/api/scroll.mdx +300 -0
  60. package/docs/v7/api/type.mdx +314 -0
  61. package/docs/v7/commands/assert.mdx +45 -0
  62. package/docs/v7/commands/exec.mdx +282 -0
  63. package/docs/v7/commands/focus-application.mdx +44 -0
  64. package/docs/v7/commands/hover-image.mdx +69 -0
  65. package/docs/v7/commands/hover-text.mdx +47 -0
  66. package/docs/v7/commands/if.mdx +53 -0
  67. package/docs/v7/commands/match-image.mdx +67 -0
  68. package/docs/v7/commands/press-keys.mdx +87 -0
  69. package/docs/v7/commands/remember.mdx +49 -0
  70. package/docs/v7/commands/run.mdx +44 -0
  71. package/docs/v7/commands/scroll-until-image.mdx +66 -0
  72. package/docs/v7/commands/scroll-until-text.mdx +60 -0
  73. package/docs/v7/commands/scroll.mdx +69 -0
  74. package/docs/v7/commands/type.mdx +45 -0
  75. package/docs/v7/commands/wait-for-image.mdx +54 -0
  76. package/docs/v7/commands/wait-for-text.mdx +48 -0
  77. package/docs/v7/commands/wait.mdx +45 -0
  78. package/docs/v7/getting-started/configuration.mdx +380 -0
  79. package/docs/v7/getting-started/quickstart.mdx +332 -0
  80. package/docs/v7/guides/best-practices.mdx +486 -0
  81. package/docs/v7/guides/caching-ai.mdx +215 -0
  82. package/docs/v7/guides/caching-selectors.mdx +292 -0
  83. package/docs/v7/guides/caching.mdx +366 -0
  84. package/docs/v7/guides/ci-cd/azure.mdx +587 -0
  85. package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
  86. package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
  87. package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
  88. package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
  89. package/docs/v7/guides/ci-cd/travis.mdx +438 -0
  90. package/docs/v7/guides/debugging.mdx +349 -0
  91. package/docs/v7/guides/faq.mdx +393 -0
  92. package/docs/v7/guides/migration.mdx +562 -0
  93. package/docs/v7/guides/performance.mdx +517 -0
  94. package/docs/{getting-started → v7/guides}/self-hosting.mdx +11 -12
  95. package/docs/v7/guides/troubleshooting.mdx +526 -0
  96. package/docs/v7/guides/vitest-plugin.mdx +477 -0
  97. package/docs/v7/guides/vitest.mdx +535 -0
  98. package/docs/v7/platforms/linux.mdx +308 -0
  99. package/docs/v7/platforms/macos.mdx +433 -0
  100. package/docs/v7/platforms/windows.mdx +430 -0
  101. package/docs/v7/playwright.mdx +342 -0
  102. package/docs/v7/presets/chrome-extension.mdx +223 -0
  103. package/docs/v7/presets/chrome.mdx +287 -0
  104. package/docs/v7/presets/electron.mdx +435 -0
  105. package/docs/v7/presets/vscode.mdx +398 -0
  106. package/docs/v7/presets/webapp.mdx +396 -0
  107. package/docs/v7/progressive-apis/CORE.md +459 -0
  108. package/docs/v7/progressive-apis/HOOKS.md +360 -0
  109. package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
  110. package/docs/v7/progressive-apis/PROVISION.md +266 -0
  111. package/eslint.config.js +19 -1
  112. package/interfaces/cli/lib/base.js +10 -4
  113. package/interfaces/logger.js +2 -1
  114. package/interfaces/shared-test-state.mjs +69 -0
  115. package/interfaces/vitest-plugin.mjs +830 -0
  116. package/package.json +29 -5
  117. package/schema.json +8 -29
  118. package/scripts/view-test-results.mjs +96 -0
  119. package/sdk-log-formatter.js +714 -0
  120. package/sdk.d.ts +1028 -0
  121. package/sdk.js +2567 -0
  122. package/{.github/workflows/self-hosted.yml → self-hosted.yml} +13 -4
  123. package/setup/aws/cloudformation.yaml +9 -2
  124. package/src/core/Dashcam.js +469 -0
  125. package/src/core/index.d.ts +150 -0
  126. package/src/core/index.js +12 -0
  127. package/src/presets/index.mjs +331 -0
  128. package/src/vitest/extended.mjs +108 -0
  129. package/src/vitest/hooks.d.ts +119 -0
  130. package/src/vitest/hooks.mjs +298 -0
  131. package/src/vitest/index.mjs +64 -0
  132. package/src/vitest/lifecycle.mjs +277 -0
  133. package/src/vitest/utils.mjs +150 -0
  134. package/test/dashcam.test.js +137 -0
  135. package/test/mcp-example-test.yaml +27 -0
  136. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +61 -0
  137. package/testdriver/acceptance-sdk/README.md +128 -0
  138. package/testdriver/acceptance-sdk/TEST_REPORTING.md +245 -0
  139. package/testdriver/acceptance-sdk/assert.test.mjs +26 -0
  140. package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
  141. package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
  142. package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +58 -0
  143. package/testdriver/acceptance-sdk/element-not-found.test.mjs +25 -0
  144. package/testdriver/acceptance-sdk/exec-js.test.mjs +43 -0
  145. package/testdriver/acceptance-sdk/exec-output.test.mjs +59 -0
  146. package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +57 -0
  147. package/testdriver/acceptance-sdk/focus-window.test.mjs +36 -0
  148. package/testdriver/acceptance-sdk/formatted-logging.test.mjs +26 -0
  149. package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
  150. package/testdriver/acceptance-sdk/hover-image.test.mjs +34 -0
  151. package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +38 -0
  152. package/testdriver/acceptance-sdk/hover-text.test.mjs +27 -0
  153. package/testdriver/acceptance-sdk/match-image.test.mjs +36 -0
  154. package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
  155. package/testdriver/acceptance-sdk/press-keys.test.mjs +50 -0
  156. package/testdriver/acceptance-sdk/prompt.test.mjs +33 -0
  157. package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +38 -0
  158. package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +39 -0
  159. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +28 -0
  160. package/testdriver/acceptance-sdk/scroll.test.mjs +41 -0
  161. package/testdriver/acceptance-sdk/setup/globalTeardown.mjs +11 -0
  162. package/testdriver/acceptance-sdk/setup/testHelpers.mjs +420 -0
  163. package/testdriver/acceptance-sdk/setup/vitestSetup.mjs +40 -0
  164. package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
  165. package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
  166. package/testdriver/acceptance-sdk/type-checking-demo.js +49 -0
  167. package/testdriver/acceptance-sdk/type.test.mjs +45 -0
  168. package/verify-element-api.js +89 -0
  169. package/verify-types.js +0 -0
  170. package/vitest.config.example.js +19 -0
  171. package/vitest.config.mjs +66 -0
  172. package/vitest.config.mjs.bak +44 -0
  173. package/.github/workflows/acceptance-v6.yml +0 -169
  174. package/.vscode/mcp.json +0 -9
  175. package/docs/overview/comparison.mdx +0 -82
  176. package/testdriver/lifecycle/prerun.yaml +0 -17
  177. /package/{testdriver/examples/desktop/lifecycle/prerun.yaml → .env.example} +0 -0
  178. /package/{testdriver → _testdriver}/acceptance/assert.yaml +0 -0
  179. /package/{testdriver → _testdriver}/acceptance/dashcam.yaml +0 -0
  180. /package/{testdriver → _testdriver}/acceptance/embed.yaml +0 -0
  181. /package/{testdriver → _testdriver}/acceptance/exec-js.yaml +0 -0
  182. /package/{testdriver → _testdriver}/acceptance/exec-output.yaml +0 -0
  183. /package/{testdriver → _testdriver}/acceptance/exec-shell.yaml +0 -0
  184. /package/{testdriver → _testdriver}/acceptance/focus-window.yaml +0 -0
  185. /package/{testdriver → _testdriver}/acceptance/hover-image.yaml +0 -0
  186. /package/{testdriver → _testdriver}/acceptance/hover-text-with-description.yaml +0 -0
  187. /package/{testdriver → _testdriver}/acceptance/hover-text.yaml +0 -0
  188. /package/{testdriver → _testdriver}/acceptance/if-else.yaml +0 -0
  189. /package/{testdriver → _testdriver}/acceptance/match-image.yaml +0 -0
  190. /package/{testdriver → _testdriver}/acceptance/press-keys.yaml +0 -0
  191. /package/{testdriver → _testdriver}/acceptance/prompt.yaml +0 -0
  192. /package/{testdriver → _testdriver}/acceptance/remember.yaml +0 -0
  193. /package/{testdriver → _testdriver}/acceptance/screenshots/cart.png +0 -0
  194. /package/{testdriver → _testdriver}/acceptance/scroll-keyboard.yaml +0 -0
  195. /package/{testdriver → _testdriver}/acceptance/scroll-until-image.yaml +0 -0
  196. /package/{testdriver → _testdriver}/acceptance/scroll-until-text.yaml +0 -0
  197. /package/{testdriver → _testdriver}/acceptance/scroll.yaml +0 -0
  198. /package/{testdriver → _testdriver}/acceptance/snippets/match-cart.yaml +0 -0
  199. /package/{testdriver → _testdriver}/acceptance/type.yaml +0 -0
  200. /package/{testdriver → _testdriver}/behavior/failure.yaml +0 -0
  201. /package/{testdriver → _testdriver}/behavior/hover-text.yaml +0 -0
  202. /package/{testdriver → _testdriver}/behavior/lifecycle/postrun.yaml +0 -0
  203. /package/{testdriver → _testdriver}/behavior/lifecycle/prerun.yaml +0 -0
  204. /package/{testdriver → _testdriver}/behavior/lifecycle/provision.yaml +0 -0
  205. /package/{testdriver → _testdriver}/behavior/secrets.yaml +0 -0
  206. /package/{testdriver → _testdriver}/edge-cases/dashcam-chrome.yaml +0 -0
  207. /package/{testdriver → _testdriver}/edge-cases/exec-pwsh-multiline.yaml +0 -0
  208. /package/{testdriver → _testdriver}/edge-cases/js-exception.yaml +0 -0
  209. /package/{testdriver → _testdriver}/edge-cases/js-promise.yaml +0 -0
  210. /package/{testdriver → _testdriver}/edge-cases/lifecycle/postrun.yaml +0 -0
  211. /package/{testdriver → _testdriver}/edge-cases/prompt-in-middle.yaml +0 -0
  212. /package/{testdriver → _testdriver}/edge-cases/prompt-nested.yaml +0 -0
  213. /package/{testdriver → _testdriver}/edge-cases/success-test.yaml +0 -0
  214. /package/{testdriver → _testdriver}/examples/android/example.yaml +0 -0
  215. /package/{testdriver → _testdriver}/examples/android/lifecycle/postrun.yaml +0 -0
  216. /package/{testdriver → _testdriver}/examples/android/lifecycle/provision.yaml +0 -0
  217. /package/{testdriver → _testdriver}/examples/android/readme.md +0 -0
  218. /package/{testdriver → _testdriver}/examples/chrome-extension/lifecycle/provision.yaml +0 -0
  219. /package/{testdriver → _testdriver}/examples/desktop/lifecycle/provision.yaml +0 -0
  220. /package/{testdriver → _testdriver}/examples/vscode-extension/lifecycle/provision.yaml +0 -0
  221. /package/{testdriver → _testdriver}/examples/web/lifecycle/postrun.yaml +0 -0
  222. /package/docs/{account → v6/account}/dashboard.mdx +0 -0
  223. /package/docs/{account → v6/account}/enterprise.mdx +0 -0
  224. /package/docs/{account → v6/account}/pricing.mdx +0 -0
  225. /package/docs/{account → v6/account}/projects.mdx +0 -0
  226. /package/docs/{account → v6/account}/team.mdx +0 -0
  227. /package/docs/{action → v6/action}/ami.mdx +0 -0
  228. /package/docs/{action → v6/action}/performance.mdx +0 -0
  229. /package/docs/{action → v6/action}/secrets.mdx +0 -0
  230. /package/docs/{apps → v6/apps}/chrome-extensions.mdx +0 -0
  231. /package/docs/{apps → v6/apps}/desktop-apps.mdx +0 -0
  232. /package/docs/{apps → v6/apps}/mobile-apps.mdx +0 -0
  233. /package/docs/{apps → v6/apps}/static-websites.mdx +0 -0
  234. /package/docs/{apps → v6/apps}/tauri-apps.mdx +0 -0
  235. /package/docs/{bugs → v6/bugs}/jira.mdx +0 -0
  236. /package/docs/{cli → v6/cli}/overview.mdx +0 -0
  237. /package/docs/{commands → v6/commands}/assert.mdx +0 -0
  238. /package/docs/{commands → v6/commands}/exec.mdx +0 -0
  239. /package/docs/{commands → v6/commands}/focus-application.mdx +0 -0
  240. /package/docs/{commands → v6/commands}/hover-image.mdx +0 -0
  241. /package/docs/{commands → v6/commands}/hover-text.mdx +0 -0
  242. /package/docs/{commands → v6/commands}/if.mdx +0 -0
  243. /package/docs/{commands → v6/commands}/match-image.mdx +0 -0
  244. /package/docs/{commands → v6/commands}/press-keys.mdx +0 -0
  245. /package/docs/{commands → v6/commands}/remember.mdx +0 -0
  246. /package/docs/{commands → v6/commands}/run.mdx +0 -0
  247. /package/docs/{commands → v6/commands}/scroll-until-image.mdx +0 -0
  248. /package/docs/{commands → v6/commands}/scroll-until-text.mdx +0 -0
  249. /package/docs/{commands → v6/commands}/scroll.mdx +0 -0
  250. /package/docs/{commands → v6/commands}/type.mdx +0 -0
  251. /package/docs/{commands → v6/commands}/wait-for-image.mdx +0 -0
  252. /package/docs/{commands → v6/commands}/wait-for-text.mdx +0 -0
  253. /package/docs/{commands → v6/commands}/wait.mdx +0 -0
  254. /package/docs/{exporting → v6/exporting}/junit.mdx +0 -0
  255. /package/docs/{exporting → v6/exporting}/playwright.mdx +0 -0
  256. /package/docs/{features → v6/features}/auto-healing.mdx +0 -0
  257. /package/docs/{features → v6/features}/generation.mdx +0 -0
  258. /package/docs/{features → v6/features}/parallel-testing.mdx +0 -0
  259. /package/docs/{features → v6/features}/reusable-snippets.mdx +0 -0
  260. /package/docs/{features → v6/features}/selectorless.mdx +0 -0
  261. /package/docs/{features → v6/features}/visual-assertions.mdx +0 -0
  262. /package/docs/{getting-started → v6/getting-started}/ci.mdx +0 -0
  263. /package/docs/{getting-started → v6/getting-started}/cli.mdx +0 -0
  264. /package/docs/{getting-started → v6/getting-started}/editing.mdx +0 -0
  265. /package/docs/{getting-started → v6/getting-started}/playwright.mdx +0 -0
  266. /package/docs/{getting-started → v6/getting-started}/running.mdx +0 -0
  267. /package/docs/{getting-started → v6/getting-started}/vscode.mdx +0 -0
  268. /package/docs/{guide → v6/guide}/assertions.mdx +0 -0
  269. /package/docs/{guide → v6/guide}/authentication.mdx +0 -0
  270. /package/docs/{guide → v6/guide}/code.mdx +0 -0
  271. /package/docs/{guide → v6/guide}/locating.mdx +0 -0
  272. /package/docs/{guide → v6/guide}/protips.mdx +0 -0
  273. /package/docs/{guide → v6/guide}/variables.mdx +0 -0
  274. /package/docs/{guide → v6/guide}/waiting.mdx +0 -0
  275. /package/docs/{importing → v6/importing}/csv.mdx +0 -0
  276. /package/docs/{importing → v6/importing}/gherkin.mdx +0 -0
  277. /package/docs/{importing → v6/importing}/jira.mdx +0 -0
  278. /package/docs/{importing → v6/importing}/testrail.mdx +0 -0
  279. /package/docs/{integrations → v6/integrations}/electron.mdx +0 -0
  280. /package/docs/{integrations → v6/integrations}/netlify.mdx +0 -0
  281. /package/docs/{integrations → v6/integrations}/vercel.mdx +0 -0
  282. /package/docs/{interactive → v6/interactive}/explore.mdx +0 -0
  283. /package/docs/{interactive → v6/interactive}/run.mdx +0 -0
  284. /package/docs/{interactive → v6/interactive}/save.mdx +0 -0
  285. /package/docs/{overview → v6/overview}/faq.mdx +0 -0
  286. /package/docs/{overview → v6/overview}/performance.mdx +0 -0
  287. /package/docs/{overview → v6/overview}/quickstart.mdx +0 -0
  288. /package/docs/{overview → v6/overview}/what-is-testdriver.mdx +0 -0
  289. /package/docs/{scenarios → v6/scenarios}/ai-chatbot.mdx +0 -0
  290. /package/docs/{scenarios → v6/scenarios}/cookie-banner.mdx +0 -0
  291. /package/docs/{scenarios → v6/scenarios}/file-upload.mdx +0 -0
  292. /package/docs/{scenarios → v6/scenarios}/form-filling.mdx +0 -0
  293. /package/docs/{scenarios → v6/scenarios}/log-in.mdx +0 -0
  294. /package/docs/{scenarios → v6/scenarios}/pdf-generation.mdx +0 -0
  295. /package/docs/{scenarios → v6/scenarios}/spell-check.mdx +0 -0
  296. /package/docs/{security → v6/security}/action.mdx +0 -0
  297. /package/docs/{security → v6/security}/agent.mdx +0 -0
  298. /package/docs/{security → v6/security}/platform.mdx +0 -0
  299. /package/docs/{tutorials → v6/tutorials}/advanced-test.mdx +0 -0
  300. /package/docs/{tutorials → v6/tutorials}/basic-test.mdx +0 -0
@@ -0,0 +1,245 @@
1
+ # TestDriver SDK Test Reporting
2
+
3
+ This guide explains the enhanced test reporting system for the TestDriver SDK acceptance tests.
4
+
5
+ ## Overview
6
+
7
+ The SDK tests use **Vitest** with multiple reporters to provide comprehensive test feedback:
8
+
9
+ 1. **Console Output** - Verbose, detailed logs during test execution
10
+ 2. **JUnit XML** - For CI/CD integration and third-party tools
11
+ 3. **JSON Results** - Machine-readable format for custom reporting
12
+ 4. **HTML Report** - Interactive browser-based test results viewer
13
+ 5. **GitHub Summary** - Markdown tables in GitHub Actions workflow summaries
14
+
15
+ ## Running Tests Locally
16
+
17
+ ### Basic Test Run
18
+
19
+ ```bash
20
+ npm run test:sdk
21
+ ```
22
+
23
+ This runs all SDK acceptance tests with verbose output.
24
+
25
+ ### Watch Mode (for development)
26
+
27
+ ```bash
28
+ npm run test:sdk:watch
29
+ ```
30
+
31
+ Re-runs tests automatically when files change.
32
+
33
+ ### Interactive UI
34
+
35
+ ```bash
36
+ npm run test:sdk:ui
37
+ ```
38
+
39
+ Opens Vitest's web UI for interactive test exploration.
40
+
41
+ ### View Results After Running Tests
42
+
43
+ After running tests, you have several options to view results:
44
+
45
+ #### Terminal Summary
46
+
47
+ ```bash
48
+ npm run test:sdk:results
49
+ ```
50
+
51
+ Displays a formatted summary in your terminal with:
52
+
53
+ - ✅ Passed test count
54
+ - ❌ Failed test count and error details
55
+ - ⏱️ Test duration
56
+ - 📁 File-by-file breakdown
57
+
58
+ #### HTML Report (Best for detailed analysis)
59
+
60
+ ```bash
61
+ npm run test:sdk:report
62
+ ```
63
+
64
+ Opens the interactive HTML report in your browser showing:
65
+
66
+ - Detailed test execution timeline
67
+ - File-by-file results
68
+ - Error stack traces with code context
69
+ - Test duration metrics
70
+
71
+ Or manually open: `test-results/index.html`
72
+
73
+ ## GitHub Actions Reporting
74
+
75
+ When tests run in GitHub Actions, you get enhanced reporting automatically:
76
+
77
+ ### 📊 GitHub Step Summary
78
+
79
+ The workflow generates a comprehensive summary visible in the Actions run:
80
+
81
+ - **Overview Table**: Pass/fail counts, duration, and totals
82
+ - **Failed Tests Section**: Each failure with error messages and stack traces
83
+ - **Passed Tests Section**: List of all passing tests organized by file
84
+
85
+ To view: Go to the Actions tab → Select your workflow run → Check the "Summary" section
86
+
87
+ ### 🧪 Test Summary Action
88
+
89
+ The `test-summary/action` provides:
90
+
91
+ - Test count badges
92
+ - Duration metrics
93
+ - Failure annotations in the Files Changed tab
94
+
95
+ ### 📦 Test Artifacts
96
+
97
+ All test results are uploaded as artifacts (retained for 7 days):
98
+
99
+ - `junit.xml` - JUnit format for third-party tools
100
+ - `results.json` - Machine-readable JSON
101
+ - `index.html` - Interactive HTML report (download and open locally)
102
+
103
+ To download artifacts:
104
+
105
+ 1. Go to the workflow run
106
+ 2. Scroll to "Artifacts" section at the bottom
107
+ 3. Download `test-results.zip`
108
+
109
+ ## Test Output Files
110
+
111
+ All test results are saved to the `test-results/` directory:
112
+
113
+ ```
114
+ test-results/
115
+ ├── junit.xml # JUnit XML format
116
+ ├── results.json # Detailed JSON results
117
+ └── index.html # Interactive HTML report
118
+ ```
119
+
120
+ Add this to your `.gitignore`:
121
+
122
+ ```
123
+ test-results/
124
+ ```
125
+
126
+ ## Reporters Explained
127
+
128
+ ### 1. Verbose Reporter (Console)
129
+
130
+ - Shows full test logs in real-time
131
+ - Includes console.log output from tests
132
+ - Color-coded pass/fail indicators
133
+ - Stack traces for failures
134
+
135
+ ### 2. JUnit Reporter
136
+
137
+ - Industry-standard XML format
138
+ - Compatible with Jenkins, Azure DevOps, etc.
139
+ - Used by `test-summary/action`
140
+
141
+ ### 3. JSON Reporter
142
+
143
+ - Complete test results in JSON format
144
+ - Programmatically parseable
145
+ - Used by the custom results viewer script
146
+
147
+ ### 4. HTML Reporter
148
+
149
+ - Interactive web-based viewer
150
+ - Visual timeline of test execution
151
+ - Filterable and searchable results
152
+ - Best for debugging failures locally
153
+
154
+ ## Customizing Test Output
155
+
156
+ ### Run a Single Test File
157
+
158
+ ```bash
159
+ npx vitest run testdriver/acceptance-sdk/assert.test.mjs
160
+ ```
161
+
162
+ ### Enable Even More Verbose Logging
163
+
164
+ ```bash
165
+ VERBOSE=true LOGGING=true npm run test:sdk
166
+ ```
167
+
168
+ ### Change Parallelism
169
+
170
+ Edit `vitest.config.mjs`:
171
+
172
+ ```javascript
173
+ maxForks: 5, // Run 5 tests in parallel instead of 10
174
+ ```
175
+
176
+ ## Troubleshooting
177
+
178
+ ### "No test results found" error
179
+
180
+ Make sure you've run the tests first:
181
+
182
+ ```bash
183
+ npm run test:sdk
184
+ ```
185
+
186
+ ### HTML report won't open
187
+
188
+ Manually navigate to and open `test-results/index.html` in your browser.
189
+
190
+ ### Tests timeout
191
+
192
+ Increase timeout in `vitest.config.mjs`:
193
+
194
+ ```javascript
195
+ testTimeout: 900000, // 15 minutes
196
+ ```
197
+
198
+ ## Best Practices
199
+
200
+ 1. **Use `test:sdk:results`** for quick terminal summaries
201
+ 2. **Use `test:sdk:report`** for deep debugging of failures
202
+ 3. **Check GitHub Summary** in PR reviews for test status
203
+ 4. **Download artifacts** from GitHub Actions for historical analysis
204
+ 5. **Run `test:sdk:watch`** during development for fast feedback
205
+
206
+ ## Example GitHub Summary Output
207
+
208
+ ```markdown
209
+ # 🧪 TestDriver SDK Test Results
210
+
211
+ ## 📊 Overview
212
+
213
+ | Metric | Count |
214
+ | ----------- | ------- |
215
+ | ✅ Passed | 18 |
216
+ | ❌ Failed | 2 |
217
+ | ⏭️ Skipped | 0 |
218
+ | 📝 Total | 20 |
219
+ | ⏱️ Duration | 145.23s |
220
+
221
+ ## ❌ Failed Tests
222
+
223
+ ### Assert Test > should assert the testdriver login page shows
224
+
225
+ **File:** `testdriver/acceptance-sdk/assert.test.mjs`
226
+
227
+ **Error:**
228
+ ```
229
+
230
+ AssertionError: expected false to be truthy
231
+
232
+ ```
233
+
234
+ ## ✅ Passed Tests
235
+
236
+ ### type.test.mjs
237
+ - ✅ should type text into input field
238
+ - ✅ should clear and retype text
239
+
240
+ ### scroll.test.mjs
241
+ - ✅ should scroll down the page
242
+ - ✅ should scroll to specific element
243
+ ```
244
+
245
+ This summary appears automatically in every GitHub Actions workflow run!
@@ -0,0 +1,26 @@
1
+ /**
2
+ * TestDriver SDK - Assert Test (Vitest)
3
+ * Converted from: testdriver/acceptance/assert.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Assert Test", () => {
10
+ it("should assert the testdriver login page shows", async (context) => {
11
+ const testdriver = TestDriver(context, { headless: true, newSandbox: true });
12
+
13
+ // provision.chrome() automatically calls ready() and starts dashcam
14
+ await testdriver.provision.chrome({
15
+ url: 'http://testdriver-sandbox.vercel.app/login',
16
+ });
17
+
18
+ // Assert the TestDriver.ai Sandbox login page is displayed
19
+ const result = await testdriver.assert(
20
+ "the TestDriver.ai Sandbox login page is displayed",
21
+ );
22
+
23
+ expect(result).toBeTruthy();
24
+ });
25
+ });
26
+
@@ -0,0 +1,56 @@
1
+ /**
2
+ * TestDriver SDK - Auto Cache Key Demo
3
+ *
4
+ * This test demonstrates the auto-generated cache key feature.
5
+ * When no cacheKey is provided, TestDriver will automatically generate
6
+ * one based on the hash of this test file.
7
+ */
8
+
9
+ import { describe, expect, it } from "vitest";
10
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
11
+
12
+ describe("Auto Cache Key Demo", () => {
13
+ it("should use auto-generated cache key based on file hash", async (context) => {
14
+ // NOTE: No cacheKey is provided here!
15
+ // TestDriver will automatically generate one from the hash of this file
16
+ const testdriver = TestDriver(context, {
17
+ headless: true,
18
+ newSandbox: true
19
+ // cacheKey NOT specified - will be auto-generated
20
+ });
21
+
22
+ // The cache key should be auto-generated
23
+ console.log('Auto-generated cache key:', testdriver.options.cacheKey);
24
+ expect(testdriver.options.cacheKey).toBeTruthy();
25
+ expect(testdriver.options.cacheKey).toMatch(/^[0-9a-f]{16}$/); // 16 hex chars
26
+
27
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
28
+
29
+ // First find - will be cached with auto-generated key
30
+ const signInButton1 = await testdriver.find(
31
+ "Sign In, black button below the password field"
32
+ );
33
+
34
+ // Second find - should hit cache because it's the same file (same cache key)
35
+ const signInButton2 = await testdriver.find(
36
+ "Sign In, black button below the password field"
37
+ );
38
+
39
+ expect(signInButton1.found()).toBe(true);
40
+ expect(signInButton2.found()).toBe(true);
41
+ });
42
+
43
+ it("should use same auto-generated cache key for multiple tests in the same file", async (context) => {
44
+ // This test is in the same file, so it should get the same auto-generated cache key
45
+ const testdriver = TestDriver(context, {
46
+ headless: true,
47
+ newSandbox: true
48
+ });
49
+
50
+ console.log('Auto-generated cache key (test 2):', testdriver.options.cacheKey);
51
+ expect(testdriver.options.cacheKey).toBeTruthy();
52
+
53
+ // If you modify this file, the hash (and therefore cache key) will change,
54
+ // invalidating the cache for this test file
55
+ });
56
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Chrome Extension Loading Demo
3
+ * Demonstrates how to load Chrome extensions using Chrome for Testing
4
+ *
5
+ * This test shows how to launch Chrome with a specific extension loaded
6
+ * by using its Chrome Web Store extension ID.
7
+ */
8
+
9
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
10
+ import TestDriver from "../../sdk.js";
11
+ import {
12
+ runPostrun,
13
+ runPrerunChromeExtension
14
+ } from "./setup/lifecycleHelpers.mjs";
15
+
16
+ describe("Chrome Extension Loading", () => {
17
+ let client;
18
+ let dashcamUrl;
19
+
20
+ beforeAll(async () => {
21
+ // Initialize TestDriver client
22
+ client = await TestDriver.create({
23
+ apiKey: process.env.TD_API_KEY,
24
+ apiRoot: process.env.TD_API_ROOT,
25
+ os: "linux",
26
+ verbosity: 1,
27
+ });
28
+
29
+ // Run prerun with uBlock Origin extension loaded
30
+ // Extension ID: cjpalhdlnbpafiamejdnhcphjbkeiagm
31
+ await runPrerunChromeExtension(client, "cjpalhdlnbpafiamejdnhcphjbkeiagm");
32
+ });
33
+
34
+ afterAll(async () => {
35
+ if (client) {
36
+ dashcamUrl = await runPostrun(client);
37
+ await client.cleanup();
38
+ }
39
+ });
40
+
41
+ it("should load Chrome with extension and verify functionality", async () => {
42
+ // Focus Chrome browser
43
+ await client.focusApplication("Google Chrome");
44
+
45
+ // Verify the page loaded
46
+ const pageElement = await client.find("TestDriver.ai Sandbox");
47
+ expect(pageElement.found()).toBe(true);
48
+
49
+ // Test basic interaction to ensure Chrome is working with the extension
50
+ const signInButton = await client.find(
51
+ "Sign In, black button below the password field",
52
+ );
53
+ await signInButton.click();
54
+
55
+ // Verify error message appears
56
+ const result = await client.assert(
57
+ "an error shows that fields are required",
58
+ );
59
+ expect(result).toBeTruthy();
60
+
61
+ console.log("✅ Chrome extension loaded successfully!");
62
+ if (dashcamUrl) {
63
+ console.log("🎥 Dashcam URL:", dashcamUrl);
64
+ }
65
+ });
66
+
67
+ it("should demonstrate extension interaction", async () => {
68
+ // You can add specific tests here to interact with the extension
69
+ // For example, if testing uBlock Origin, you might:
70
+ // 1. Navigate to a page with ads
71
+ // 2. Verify ads are blocked
72
+ // 3. Access the extension's popup or settings
73
+
74
+ await client.focusApplication("Google Chrome");
75
+
76
+ // Example: Navigate to extension management page to verify it's loaded
77
+ await client.exec(
78
+ "sh",
79
+ `xdotool key --clearmodifiers ctrl+shift+e`,
80
+ 5000,
81
+ true
82
+ );
83
+
84
+ // Wait a moment for the extensions page to potentially load
85
+ await new Promise((resolve) => setTimeout(resolve, 2000));
86
+
87
+ console.log("✅ Extension interaction test completed");
88
+ });
89
+ });
@@ -0,0 +1,58 @@
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 "../../src/vitest/hooks.mjs";
8
+
9
+ const isLinux = (process.env.TD_OS || "linux") === "linux";
10
+
11
+ describe("Drag and Drop Test", () => {
12
+ it.skipIf(isLinux)(
13
+ 'should drag "New Text Document" to "Recycle Bin"',
14
+ async (context) => {
15
+ const testdriver = TestDriver(context, { headless: true });
16
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
17
+
18
+ //
19
+ // Show the desktop
20
+ await testdriver.pressKeys(["win", "d"]);
21
+
22
+ // Open the context menu
23
+ await testdriver.pressKeys(["shift", "f10"]);
24
+
25
+ // Hover over "New" in the context menu
26
+ const newOption = await testdriver.find(
27
+ "New, new option in the open context menu on the desktop",
28
+ );
29
+ await newOption.hover();
30
+
31
+ // Click "Text Document" in the context menu
32
+ const textDocOption = await testdriver.find(
33
+ "Text Document, text document option in the new submenu of the desktop context menu",
34
+ );
35
+ await textDocOption.click();
36
+
37
+ // Unfocus the "Text Document" text field
38
+ await testdriver.pressKeys(["esc"]);
39
+
40
+ // Drag the "New Text Document" icon to the "Recycle Bin"
41
+ const textDoc = await testdriver.find(
42
+ "New Text Document, new text document icon in the center of the desktop",
43
+ );
44
+ await textDoc.mouseDown();
45
+
46
+ const recycleBin = await testdriver.find(
47
+ "Recycle Bin, recycle bin icon in the top left corner of the desktop",
48
+ );
49
+ await recycleBin.mouseUp();
50
+
51
+ // Assert "New Text Document" icon is not on the Desktop
52
+ const result = await testdriver.assert(
53
+ 'the "New Text Document" icon is not visible on the Desktop',
54
+ );
55
+ expect(result).toBeTruthy();
56
+ },
57
+ );
58
+ });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * TestDriver SDK - Element Not Found Test
3
+ * Tests that finding a non-existent element returns properly without timing out
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Element Not Found Test", () => {
10
+ it("should handle non-existent element gracefully without timing out", async (context) => {
11
+ const testdriver = TestDriver(context, { headless: true });
12
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
13
+
14
+ //
15
+
16
+ // Try to find an element that definitely doesn't exist
17
+ const element = await testdriver.find(
18
+ "a purple unicorn dancing on the moon",
19
+ );
20
+
21
+ // Should return an element that is not found
22
+ expect(element.found()).toBe(false);
23
+ expect(element.coordinates).toBeNull();
24
+ }, 90000); // 90 second timeout for the test (should complete much faster)
25
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * TestDriver SDK - Exec JS Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-js.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Exec JavaScript Test", () => {
10
+ it("should fetch user data from API and enter email", async (context) => {
11
+ const testdriver = TestDriver(context, { headless: true });
12
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
13
+
14
+ //
15
+ // Execute JavaScript to fetch user data
16
+ const userEmail = await testdriver.exec(
17
+ "js",
18
+ `
19
+ const response = await fetch('https://jsonplaceholder.typicode.com/users');
20
+ const user = await response.json();
21
+ console.log('user', user[0]);
22
+ result = user[0].email;
23
+ `,
24
+ 10000,
25
+ );
26
+
27
+ expect(userEmail).toBeTruthy();
28
+ expect(userEmail).toContain("@");
29
+
30
+ // Enter email in username field
31
+ const usernameField = await testdriver.find(
32
+ "Username, input field for username",
33
+ );
34
+ await usernameField.click();
35
+ await testdriver.type(userEmail);
36
+
37
+ // Assert email is in the field
38
+ const result = await testdriver.assert(
39
+ 'the username field contains "Sincere@april.biz" which is a valid email address',
40
+ );
41
+ expect(result).toBeTruthy();
42
+ });
43
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * TestDriver SDK - Exec Output Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-output.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Exec Output Test", () => {
10
+ it.skipIf(process.env.TD_OS === "linux")(
11
+ "should set date using PowerShell and navigate to calendar",
12
+ async (context) => {
13
+ const testdriver = TestDriver(context, { headless: true });
14
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
15
+
16
+ //
17
+ // Generate date in query string format
18
+ const queryString = await testdriver.exec(
19
+ "pwsh",
20
+ `
21
+ $date = (Get-Date).AddMonths(1)
22
+ Write-Output $date.ToString("yyyy-MM-dd")
23
+ `,
24
+ 10000,
25
+ );
26
+
27
+ // Assert that the date is valid
28
+ const dateValidResult = await testdriver.assert(
29
+ `${queryString} is a valid date`,
30
+ );
31
+ expect(dateValidResult).toBeTruthy();
32
+
33
+ // Generate date in display format
34
+ const expectedDate = await testdriver.exec(
35
+ "pwsh",
36
+ `
37
+ $date = (Get-Date).AddMonths(1)
38
+ Write-Output $date.ToString("ddd MMM d yyyy")
39
+ `,
40
+ 10000,
41
+ );
42
+
43
+ // Navigate to calendar with date parameter
44
+ await testdriver.focusApplication("Google Chrome");
45
+ await testdriver.pressKeys(["ctrl", "l"]);
46
+ await testdriver.type(
47
+ `https://teamup.com/ks48cf2135e7e080bc?view=d&date=${queryString}`,
48
+ );
49
+ await testdriver.pressKeys(["enter"]);
50
+
51
+ // Assert that the expected date shows
52
+ await testdriver.focusApplication("Google Chrome");
53
+ const result = await testdriver.assert(
54
+ `the text ${expectedDate} is visible on screen`,
55
+ );
56
+ expect(result).toBeTruthy();
57
+ },
58
+ );
59
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * TestDriver SDK - Exec Shell Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-shell.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Exec PowerShell Test", () => {
10
+ it.skipIf(process.env.TD_OS === "linux")(
11
+ "should generate random email using PowerShell and enter it",
12
+ async (context) => {
13
+ const testdriver = TestDriver(context, { headless: true });
14
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
15
+
16
+ //
17
+ // Generate random email using PowerShell
18
+ const randomEmail = await testdriver.exec({
19
+ language: "pwsh",
20
+ code: `
21
+ # Random email generator in PowerShell
22
+
23
+ # Arrays of possible names and domains
24
+ $firstNames = @("john", "jane", "alex", "chris", "sara", "mike", "lisa", "david", "emma", "ryan")
25
+ $lastNames = @("smith", "johnson", "williams", "brown", "jones", "garcia", "miller", "davis", "martin", "lee")
26
+ $domains = @("example.com", "testmail.com", "mailinator.com", "demo.org", "company.net")
27
+
28
+ # Random selection
29
+ $first = Get-Random -InputObject $firstNames
30
+ $last = Get-Random -InputObject $lastNames
31
+ $domain = Get-Random -InputObject $domains
32
+ $number = Get-Random -Minimum 1 -Maximum 1000
33
+
34
+ # Generate the email
35
+ $email = "$first.$last$number@$domain".ToLower()
36
+
37
+ # Output
38
+ Write-Output "$email"
39
+ `,
40
+ timeout: 10000,
41
+ });
42
+
43
+ // Enter the email in username field
44
+ const usernameField = await testdriver.find(
45
+ "Username, input field for username",
46
+ );
47
+ await usernameField.click();
48
+ await testdriver.type(randomEmail);
49
+
50
+ // Assert that the username field shows a valid email address
51
+ const result = await testdriver.assert(
52
+ `the username field contains ${randomEmail} which is a valid email address`,
53
+ );
54
+ expect(result).toBeTruthy();
55
+ },
56
+ );
57
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * TestDriver SDK - Focus Window Test (Vitest)
3
+ * Converted from: testdriver/acceptance/focus-window.yaml
4
+ */
5
+
6
+ import { describe, expect, it } from "vitest";
7
+ import { TestDriver } from "../../src/vitest/hooks.mjs";
8
+
9
+ describe("Focus Window Test", () => {
10
+ it.skipIf(process.env.TD_OS === "linux")(
11
+ "should click Microsoft Edge icon and focus Google Chrome",
12
+ async (context) => {
13
+ const testdriver = TestDriver(context, { headless: true });
14
+ await testdriver.provision.chrome({ url: 'http://testdriver-sandbox.vercel.app/login' });
15
+
16
+ //
17
+ // Show desktop
18
+ await testdriver.pressKeys(["winleft", "d"]);
19
+
20
+ // Click on the Microsoft Edge icon
21
+ const edgeIcon = await testdriver.find(
22
+ "a blue and green swirl icon on the taskbar representing Microsoft Edge",
23
+ );
24
+ await edgeIcon.click();
25
+
26
+ // Focus Google Chrome
27
+ await testdriver.focusApplication("Google Chrome");
28
+
29
+ // Assert Chrome is focused (implicit through successful focus)
30
+ const result = await testdriver.assert(
31
+ "Google Chrome is the focused application",
32
+ );
33
+ expect(result).toBeTruthy();
34
+ },
35
+ );
36
+ });