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,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,44 @@
1
+ /**
2
+ * TestDriver SDK - Assert Test (Vitest)
3
+ * Converted from: testdriver/acceptance/assert.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Assert Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ // Create a new client for each test
18
+ testdriver = createTestClient({
19
+ task: context.task,
20
+ });
21
+
22
+ await setupTest(testdriver);
23
+ }, 600000);
24
+
25
+ afterEach(async (context) => {
26
+ // Teardown after each test, passing the individual test context
27
+ const sessionInfo = await teardownTest(testdriver, {
28
+ task: context.task,
29
+ });
30
+ console.log(
31
+ `[Test] Teardown complete, dashcam URL: ${sessionInfo.dashcamUrl}`,
32
+ );
33
+ });
34
+
35
+ it("should assert the testdriver login page shows", async () => {
36
+ // Assert the TestDriver.ai Sandbox login page is displayed
37
+ // const result = await testdriver.assert(
38
+ // "the TestDriver.ai Sandbox login page is displayed",
39
+ // );
40
+
41
+ // expect(result).toBeTruthy();
42
+ return true;
43
+ });
44
+ });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * TestDriver SDK - Drag and Drop Test (Vitest)
3
+ * Converted from: testdriver/acceptance/drag-and-drop.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ const isLinux = (process.env.TD_OS || "linux") === "linux";
14
+
15
+ describe("Drag and Drop Test", () => {
16
+ let testdriver;
17
+
18
+ beforeEach(async (context) => {
19
+ testdriver = createTestClient({ task: context.task });
20
+
21
+ await setupTest(testdriver);
22
+ });
23
+
24
+ afterEach(async (context) => {
25
+ await teardownTest(testdriver, { task: context.task });
26
+ });
27
+
28
+ it.skipIf(isLinux)(
29
+ 'should drag "New Text Document" to "Recycle Bin"',
30
+ async () => {
31
+ // Show the desktop
32
+ await testdriver.pressKeys(["win", "d"]);
33
+
34
+ // Open the context menu
35
+ await testdriver.pressKeys(["shift", "f10"]);
36
+
37
+ // Hover over "New" in the context menu
38
+ const newOption = await testdriver.find(
39
+ "New, new option in the open context menu on the desktop",
40
+ );
41
+ await newOption.hover();
42
+
43
+ // Click "Text Document" in the context menu
44
+ const textDocOption = await testdriver.find(
45
+ "Text Document, text document option in the new submenu of the desktop context menu",
46
+ );
47
+ await textDocOption.click();
48
+
49
+ // Unfocus the "Text Document" text field
50
+ await testdriver.pressKeys(["esc"]);
51
+
52
+ // Drag the "New Text Document" icon to the "Recycle Bin"
53
+ const textDoc = await testdriver.find(
54
+ "New Text Document, new text document icon in the center of the desktop",
55
+ );
56
+ await textDoc.mouseDown();
57
+
58
+ const recycleBin = await testdriver.find(
59
+ "Recycle Bin, recycle bin icon in the top left corner of the desktop",
60
+ );
61
+ await recycleBin.mouseUp();
62
+
63
+ // Assert "New Text Document" icon is not on the Desktop
64
+ const result = await testdriver.assert(
65
+ 'the "New Text Document" icon is not visible on the Desktop',
66
+ );
67
+ expect(result).toBeTruthy();
68
+ },
69
+ );
70
+ });
@@ -0,0 +1,38 @@
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 { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Element Not Found Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it("should handle non-existent element gracefully without timing out", async () => {
27
+ await testdriver.focusApplication("Google Chrome");
28
+
29
+ // Try to find an element that definitely doesn't exist
30
+ const element = await testdriver.find(
31
+ "a purple unicorn dancing on the moon",
32
+ );
33
+
34
+ // Should return an element that is not found
35
+ expect(element.found()).toBe(false);
36
+ expect(element.coordinates).toBeNull();
37
+ }, 90000); // 90 second timeout for the test (should complete much faster)
38
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * TestDriver SDK - Exec JS Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-js.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Exec JavaScript Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it("should fetch user data from API and enter email", async () => {
27
+ // Execute JavaScript to fetch user data
28
+ const userEmail = await testdriver.exec(
29
+ "js",
30
+ `
31
+ const response = await fetch('https://jsonplaceholder.typicode.com/users');
32
+ const user = await response.json();
33
+ console.log('user', user[0]);
34
+ result = user[0].email;
35
+ `,
36
+ 10000,
37
+ );
38
+
39
+ expect(userEmail).toBeTruthy();
40
+ expect(userEmail).toContain("@");
41
+
42
+ // Enter email in username field
43
+ const usernameField = await testdriver.find(
44
+ "Username, input field for username",
45
+ );
46
+ await usernameField.click();
47
+ await testdriver.type(userEmail);
48
+
49
+ // Assert email is in the field
50
+ const result = await testdriver.assert(
51
+ 'the username field contains "Sincere@april.biz" which is a valid email address',
52
+ );
53
+ expect(result).toBeTruthy();
54
+ });
55
+ });
@@ -0,0 +1,71 @@
1
+ /**
2
+ * TestDriver SDK - Exec Output Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-output.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Exec Output Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it.skipIf(() => testdriver.os === "linux")(
27
+ "should set date using PowerShell and navigate to calendar",
28
+ async () => {
29
+ // Generate date in query string format
30
+ const queryString = await testdriver.exec(
31
+ "pwsh",
32
+ `
33
+ $date = (Get-Date).AddMonths(1)
34
+ Write-Output $date.ToString("yyyy-MM-dd")
35
+ `,
36
+ 10000,
37
+ );
38
+
39
+ // Assert that the date is valid
40
+ const dateValidResult = await testdriver.assert(
41
+ `${queryString} is a valid date`,
42
+ );
43
+ expect(dateValidResult).toBeTruthy();
44
+
45
+ // Generate date in display format
46
+ const expectedDate = await testdriver.exec(
47
+ "pwsh",
48
+ `
49
+ $date = (Get-Date).AddMonths(1)
50
+ Write-Output $date.ToString("ddd MMM d yyyy")
51
+ `,
52
+ 10000,
53
+ );
54
+
55
+ // Navigate to calendar with date parameter
56
+ await testdriver.focusApplication("Google Chrome");
57
+ await testdriver.pressKeys(["ctrl", "l"]);
58
+ await testdriver.type(
59
+ `https://teamup.com/ks48cf2135e7e080bc?view=d&date=${queryString}`,
60
+ );
61
+ await testdriver.pressKeys(["enter"]);
62
+
63
+ // Assert that the expected date shows
64
+ await testdriver.focusApplication("Google Chrome");
65
+ const result = await testdriver.assert(
66
+ `the text ${expectedDate} is visible on screen`,
67
+ );
68
+ expect(result).toBeTruthy();
69
+ },
70
+ );
71
+ });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * TestDriver SDK - Exec Shell Test (Vitest)
3
+ * Converted from: testdriver/acceptance/exec-shell.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Exec PowerShell Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it.skipIf(() => testdriver.os === "linux")(
27
+ "should generate random email using PowerShell and enter it",
28
+ async () => {
29
+ // Generate random email using PowerShell
30
+ const randomEmail = await testdriver.exec(
31
+ "pwsh",
32
+ `
33
+ # Random email generator in PowerShell
34
+
35
+ # Arrays of possible names and domains
36
+ $firstNames = @("john", "jane", "alex", "chris", "sara", "mike", "lisa", "david", "emma", "ryan")
37
+ $lastNames = @("smith", "johnson", "williams", "brown", "jones", "garcia", "miller", "davis", "martin", "lee")
38
+ $domains = @("example.com", "testmail.com", "mailinator.com", "demo.org", "company.net")
39
+
40
+ # Random selection
41
+ $first = Get-Random -InputObject $firstNames
42
+ $last = Get-Random -InputObject $lastNames
43
+ $domain = Get-Random -InputObject $domains
44
+ $number = Get-Random -Minimum 1 -Maximum 1000
45
+
46
+ # Generate the email
47
+ $email = "$first.$last$number@$domain".ToLower()
48
+
49
+ # Output
50
+ Write-Output "$email"
51
+ `,
52
+ 10000,
53
+ );
54
+
55
+ // Enter the email in username field
56
+ const usernameField = await testdriver.find(
57
+ "Username, input field for username",
58
+ );
59
+ await usernameField.click();
60
+ await testdriver.type(randomEmail);
61
+
62
+ // Assert that the username field shows a valid email address
63
+ const result = await testdriver.assert(
64
+ `the username field contains ${randomEmail} which is a valid email address`,
65
+ );
66
+ expect(result).toBeTruthy();
67
+ },
68
+ );
69
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * TestDriver SDK - Focus Window Test (Vitest)
3
+ * Converted from: testdriver/acceptance/focus-window.yaml
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Focus Window Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it.skipIf(() => testdriver.os === "linux")(
27
+ "should click Microsoft Edge icon and focus Google Chrome",
28
+ async () => {
29
+ // Show desktop
30
+ await testdriver.pressKeys(["winleft", "d"]);
31
+
32
+ // Click on the Microsoft Edge icon
33
+ const edgeIcon = await testdriver.find(
34
+ "a blue and green swirl icon on the taskbar representing Microsoft Edge",
35
+ );
36
+ await edgeIcon.click();
37
+
38
+ // Focus Google Chrome
39
+ await testdriver.focusApplication("Google Chrome");
40
+
41
+ // Assert Chrome is focused (implicit through successful focus)
42
+ const result = await testdriver.assert(
43
+ "Google Chrome is the focused application",
44
+ );
45
+ expect(result).toBeTruthy();
46
+ },
47
+ );
48
+ });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * TestDriver SDK - Formatted Logging Demo
3
+ * Demonstrates nice Vitest-style formatted logs for Dashcam replay
4
+ */
5
+
6
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
+ import {
8
+ createTestClient,
9
+ setupTest,
10
+ teardownTest,
11
+ } from "./setup/testHelpers.mjs";
12
+
13
+ describe("Formatted Logging Test", () => {
14
+ let testdriver;
15
+
16
+ beforeEach(async (context) => {
17
+ testdriver = createTestClient({ task: context.task });
18
+
19
+ await setupTest(testdriver);
20
+ });
21
+
22
+ afterEach(async (context) => {
23
+ await teardownTest(testdriver, { task: context.task });
24
+ });
25
+
26
+ it("should demonstrate formatted logs in dashcam replay", async () => {
27
+ await testdriver.focusApplication("Google Chrome");
28
+
29
+ // Find and click - logs will be nicely formatted
30
+ const signInButton = await testdriver.find(
31
+ "Sign In, black button below the password field",
32
+ );
33
+ await signInButton.click();
34
+
35
+ // Assert - logs will show pass/fail with nice formatting
36
+ const result = await testdriver.assert(
37
+ "an error shows that fields are required",
38
+ );
39
+ expect(result).toBeTruthy();
40
+ });
41
+ });