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,150 @@
1
+ /**
2
+ * Utility Functions for TestDriver Vitest Plugin
3
+ *
4
+ * General-purpose utilities for testing with TestDriver.
5
+ *
6
+ * @example
7
+ * import { retryAsync, setupEventLogging } from 'testdriverai/vitest';
8
+ */
9
+
10
+ /**
11
+ * Set up detailed event logging for debugging
12
+ * @param {TestDriver} client - TestDriver client
13
+ */
14
+ export function setupEventLogging(client) {
15
+ const emitter = client.getEmitter();
16
+
17
+ // Log all events
18
+ emitter.on("**", function (data) {
19
+ const event = this.event;
20
+ if (event.startsWith("log:debug")) return; // Skip debug logs
21
+ console.log(`[EVENT] ${event}`, data || "");
22
+ });
23
+
24
+ // Log command lifecycle
25
+ emitter.on("command:start", (data) => {
26
+ console.log("🚀 Command started:", data);
27
+ });
28
+
29
+ emitter.on("command:success", (data) => {
30
+ console.log("✅ Command succeeded:", data);
31
+ });
32
+
33
+ emitter.on("command:error", (data) => {
34
+ console.error("❌ Command error:", data);
35
+ });
36
+
37
+ // Log sandbox events
38
+ emitter.on("sandbox:connected", () => {
39
+ console.log("🔌 Sandbox connected");
40
+ });
41
+
42
+ emitter.on("sandbox:authenticated", () => {
43
+ console.log("🔐 Sandbox authenticated");
44
+ });
45
+
46
+ emitter.on("sandbox:error", (error) => {
47
+ console.error("⚠️ Sandbox error:", error);
48
+ });
49
+
50
+ // Log SDK API calls
51
+ emitter.on("sdk:request", (data) => {
52
+ console.log("📤 SDK Request:", data);
53
+ });
54
+
55
+ emitter.on("sdk:response", (data) => {
56
+ console.log("📥 SDK Response:", data);
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Retry an async function with configurable attempts and delay
62
+ * @param {Function} fn - Async function to retry
63
+ * @param {number} retries - Number of retries (default: 3)
64
+ * @param {number} delay - Delay between retries in ms (default: 1000)
65
+ * @returns {Promise} Result of successful execution
66
+ * @throws {Error} Last error if all retries fail
67
+ *
68
+ * @example
69
+ * const result = await retryAsync(
70
+ * () => testdriver.find("Flaky Element"),
71
+ * 5,
72
+ * 2000
73
+ * );
74
+ */
75
+ export async function retryAsync(fn, retries = 3, delay = 1000) {
76
+ let lastError;
77
+
78
+ for (let i = 0; i < retries; i++) {
79
+ try {
80
+ return await fn();
81
+ } catch (error) {
82
+ lastError = error;
83
+ if (i < retries - 1) {
84
+ await new Promise((resolve) => setTimeout(resolve, delay));
85
+ }
86
+ }
87
+ }
88
+
89
+ throw lastError;
90
+ }
91
+
92
+ /**
93
+ * Wait for a condition to be true
94
+ * @param {Function} condition - Function that returns boolean or Promise<boolean>
95
+ * @param {object} options - Wait options
96
+ * @param {number} options.timeout - Maximum time to wait in ms (default: 30000)
97
+ * @param {number} options.interval - Poll interval in ms (default: 500)
98
+ * @param {string} options.message - Error message if timeout (default: "Condition not met")
99
+ * @returns {Promise<boolean>} True if condition met
100
+ * @throws {Error} If timeout reached
101
+ *
102
+ * @example
103
+ * await waitFor(() => element.exists(), { timeout: 10000 });
104
+ */
105
+ export async function waitFor(condition, options = {}) {
106
+ const {
107
+ timeout = 30000,
108
+ interval = 500,
109
+ message = "Condition not met within timeout"
110
+ } = options;
111
+
112
+ const startTime = Date.now();
113
+
114
+ while (Date.now() - startTime < timeout) {
115
+ try {
116
+ const result = await condition();
117
+ if (result) {
118
+ return true;
119
+ }
120
+ } catch (error) {
121
+ // Condition threw, keep polling
122
+ }
123
+ await new Promise(resolve => setTimeout(resolve, interval));
124
+ }
125
+
126
+ throw new Error(`${message} (timeout: ${timeout}ms)`);
127
+ }
128
+
129
+ /**
130
+ * Sleep for a specified duration
131
+ * @param {number} ms - Milliseconds to sleep
132
+ * @returns {Promise<void>}
133
+ *
134
+ * @example
135
+ * await sleep(1000); // Wait 1 second
136
+ */
137
+ export function sleep(ms) {
138
+ return new Promise(resolve => setTimeout(resolve, ms));
139
+ }
140
+
141
+ /**
142
+ * Generate a unique test ID
143
+ * @param {string} prefix - Optional prefix for the ID
144
+ * @returns {string} Unique ID
145
+ */
146
+ export function generateTestId(prefix = "test") {
147
+ const timestamp = Date.now().toString(36);
148
+ const random = Math.random().toString(36).substring(2, 8);
149
+ return `${prefix}-${timestamp}-${random}`;
150
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Dashcam Class - Unit Tests
3
+ * Tests for the new Dashcam class
4
+ */
5
+
6
+ const { Dashcam } = require('../src/core');
7
+
8
+ // Mock TestDriver client
9
+ class MockTestDriver {
10
+ constructor(os = 'linux') {
11
+ this.os = os;
12
+ this.commands = [];
13
+ }
14
+
15
+ async exec(shell, command, timeout, silent) {
16
+ this.commands.push({ shell, command, timeout, silent });
17
+
18
+ // Mock responses
19
+ if (command.includes('npm prefix -g')) {
20
+ return this.os === 'windows'
21
+ ? 'C:\\Users\\testdriver\\AppData\\Roaming\\npm'
22
+ : '/usr/local';
23
+ }
24
+
25
+ if (command.includes('stop')) {
26
+ return 'Recording stopped\nReplay URL: https://app.testdriver.ai/replay/abc123?share=xyz';
27
+ }
28
+
29
+ return 'OK';
30
+ }
31
+
32
+ wait(ms) {
33
+ return new Promise(resolve => setTimeout(resolve, ms));
34
+ }
35
+ }
36
+
37
+ async function testDashcamCreation() {
38
+ console.log('🧪 Test: Dashcam creation');
39
+
40
+ const client = new MockTestDriver();
41
+ const dashcam = new Dashcam(client);
42
+
43
+ console.assert(dashcam.client === client, 'Client should be stored');
44
+ console.assert(dashcam.recording === false, 'Should not be recording initially');
45
+ console.assert(dashcam._authenticated === false, 'Should not be authenticated initially');
46
+
47
+ console.log('✅ Dashcam creation test passed');
48
+ }
49
+
50
+ async function testDashcamWithOptions() {
51
+ console.log('\n🧪 Test: Dashcam with options');
52
+
53
+ const client = new MockTestDriver();
54
+ const dashcam = new Dashcam(client, {
55
+ apiKey: 'custom-key',
56
+ autoStart: true,
57
+ logs: [
58
+ { type: 'file', path: '/tmp/test.log', name: 'Test Log' }
59
+ ]
60
+ });
61
+
62
+ console.assert(dashcam.apiKey === 'custom-key', 'Custom API key should be used');
63
+ console.assert(dashcam.autoStart === true, 'Auto start should be enabled');
64
+ console.assert(dashcam.logs.length === 1, 'Logs should be stored');
65
+
66
+ console.log('✅ Dashcam options test passed');
67
+ }
68
+
69
+ async function testErrorOnMissingClient() {
70
+ console.log('\n🧪 Test: Error when client missing');
71
+
72
+ try {
73
+ new Dashcam();
74
+ console.error('❌ Should have thrown error');
75
+ process.exit(1);
76
+ } catch (error) {
77
+ console.assert(
78
+ error.message.includes('TestDriver client'),
79
+ 'Error message should mention TestDriver client'
80
+ );
81
+ }
82
+
83
+ console.log('✅ Missing client error test passed');
84
+ }
85
+
86
+ async function testStopReturnsUrl() {
87
+ console.log('\n🧪 Test: Stop returns URL');
88
+
89
+ const client = new MockTestDriver();
90
+ const dashcam = new Dashcam(client);
91
+
92
+ dashcam.recording = true; // Simulate recording state
93
+ const url = await dashcam.stop();
94
+
95
+ console.assert(url !== null, 'URL should be returned');
96
+ console.assert(url.includes('replay'), 'URL should contain replay');
97
+ console.assert(dashcam.recording === false, 'Should stop recording');
98
+
99
+ console.log('✅ Stop returns URL test passed');
100
+ console.log(' URL:', url);
101
+ }
102
+
103
+ async function testIsRecording() {
104
+ console.log('\n🧪 Test: isRecording method');
105
+
106
+ const client = new MockTestDriver();
107
+ const dashcam = new Dashcam(client);
108
+
109
+ let recording = await dashcam.isRecording();
110
+ console.assert(recording === false, 'Should not be recording initially');
111
+
112
+ dashcam.recording = true;
113
+ recording = await dashcam.isRecording();
114
+ console.assert(recording === true, 'Should return recording state');
115
+
116
+ console.log('✅ isRecording test passed');
117
+ }
118
+
119
+ async function runAllTests() {
120
+ console.log('🚀 Running Dashcam class tests...\n');
121
+
122
+ try {
123
+ await testDashcamCreation();
124
+ await testDashcamWithOptions();
125
+ await testErrorOnMissingClient();
126
+ await testStopReturnsUrl();
127
+ await testIsRecording();
128
+
129
+ console.log('\n✅ All tests passed!');
130
+ } catch (error) {
131
+ console.error('\n❌ Test failed:', error.message);
132
+ console.error(error.stack);
133
+ process.exit(1);
134
+ }
135
+ }
136
+
137
+ runAllTests();
@@ -0,0 +1,27 @@
1
+ name: MCP Example Test
2
+ description: Test created using TestDriver MCP to navigate example.com
3
+
4
+ steps:
5
+ # Open Chrome browser and navigate to example.com
6
+ - exec:
7
+ code: Start-Process chrome "https://example.com"
8
+ language: pwsh
9
+ timeout: 5000
10
+
11
+ # Wait for the page to load
12
+ - wait-for-text:
13
+ text: Example Domain
14
+ timeout: 10000
15
+
16
+ # Assert that the Example Domain heading is visible
17
+ - assert:
18
+ expect: The text "Example Domain" is visible on the page
19
+
20
+ # Click on the "Learn more" link
21
+ - hover-text:
22
+ text: Learn more
23
+ action: click
24
+
25
+ # Wait for navigation to complete
26
+ - wait:
27
+ timeout: 2000
@@ -0,0 +1,61 @@
1
+ # SDK Test Reporting - Quick Reference
2
+
3
+ ## 🚀 Commands
4
+
5
+ ```bash
6
+ # Run all tests
7
+ npm run test:sdk
8
+
9
+ # View terminal summary
10
+ npm run test:sdk:results
11
+
12
+ # Open HTML report
13
+ npm run test:sdk:report
14
+
15
+ # Watch mode (dev)
16
+ npm run test:sdk:watch
17
+
18
+ # Interactive UI
19
+ npm run test:sdk:ui
20
+ ```
21
+
22
+ ## 📊 What You Get
23
+
24
+ ### Locally
25
+
26
+ 1. **Console**: Verbose logs with full test output
27
+ 2. **Terminal Summary**: `npm run test:sdk:results` - Quick pass/fail counts
28
+ 3. **HTML Report**: `npm run test:sdk:report` - Interactive browser viewer
29
+
30
+ ### GitHub Actions
31
+
32
+ 1. **Step Summary**: Markdown tables in workflow summary page
33
+ 2. **Test Summary Action**: Badge counts and annotations
34
+ 3. **Artifacts**: Download junit.xml, results.json, and index.html
35
+
36
+ ## 📁 Output Files
37
+
38
+ ```
39
+ test-results/
40
+ ├── junit.xml # For CI/CD tools
41
+ ├── results.json # Machine-readable
42
+ └── index.html # Interactive report
43
+ ```
44
+
45
+ ## ⚡ Quick Tips
46
+
47
+ - **Debugging failures?** → `npm run test:sdk:report` (HTML has best error context)
48
+ - **Quick status check?** → `npm run test:sdk:results` (terminal summary)
49
+ - **PR review?** → Check GitHub Actions summary tab
50
+ - **Need history?** → Download artifacts from GitHub Actions runs
51
+
52
+ ## 🔍 GitHub Summary Preview
53
+
54
+ Every test run creates a summary with:
55
+
56
+ - ✅ Pass/fail counts table
57
+ - ❌ Failed test details with errors
58
+ - ✅ List of all passing tests
59
+ - ⏱️ Duration metrics
60
+
61
+ Find it: Actions → Your workflow run → Summary tab
@@ -0,0 +1,128 @@
1
+ # TestDriver SDK Acceptance Tests
2
+
3
+ This directory contains acceptance tests for the TestDriver SDK using Vitest.
4
+
5
+ ## Running Tests
6
+
7
+ ### Run All Tests (Cross-Platform)
8
+
9
+ ```bash
10
+ npm run test:sdk
11
+ ```
12
+
13
+ ### Run Platform-Specific Tests
14
+
15
+ Use the `TEST_PLATFORM` environment variable to run tests for a specific platform:
16
+
17
+ ```bash
18
+ # Run Windows-only tests
19
+ npm run test:sdk:windows
20
+
21
+ # Run macOS-only tests
22
+ npm run test:sdk:mac
23
+
24
+ # Run Linux-only tests
25
+ npm run test:sdk:linux
26
+ ```
27
+
28
+ Or set the environment variable directly:
29
+
30
+ ```bash
31
+ TEST_PLATFORM=windows npm run test:sdk
32
+ TEST_PLATFORM=mac npm run test:sdk
33
+ ```
34
+
35
+ ## Test Organization
36
+
37
+ ### Cross-Platform Tests
38
+
39
+ Tests without a platform suffix run on all platforms:
40
+
41
+ - `hover-text.test.mjs` - Runs everywhere
42
+ - `scroll.test.mjs` - Runs everywhere
43
+ - `screenshot.test.mjs` - Runs everywhere
44
+
45
+ ### Platform-Specific Tests
46
+
47
+ Platform-specific tests use naming conventions:
48
+
49
+ - `*.windows.test.mjs` - Windows-only tests (e.g., `exec-pwsh.windows.test.mjs`)
50
+ - `*.mac.test.mjs` - macOS-only tests
51
+ - `*.linux.test.mjs` - Linux-only tests
52
+
53
+ ### Conditional Test Skipping
54
+
55
+ Some tests use `skipIf` to conditionally skip based on the platform:
56
+
57
+ ```javascript
58
+ it.skipIf(() => testdriver.os === "linux")(
59
+ "should run on Windows/Mac",
60
+ async () => {
61
+ // This test will be skipped on Linux
62
+ },
63
+ );
64
+ ```
65
+
66
+ ## Environment Variables
67
+
68
+ - `TEST_PLATFORM` - Filter tests by platform (`windows`, `mac`, `linux`)
69
+ - `TD_OS` - Override the sandbox OS (defaults to `linux`)
70
+ - `TD_API_KEY` - Your TestDriver API key (required)
71
+ - `TD_API_ROOT` - API endpoint (optional)
72
+ - `DEBUG_ENV` - Show environment variable loading (optional)
73
+ - `DEBUG_EVENTS` - Enable detailed event logging (optional)
74
+
75
+ ## Examples
76
+
77
+ ```bash
78
+ # Run only Windows tests on a Windows sandbox
79
+ TEST_PLATFORM=windows npm run test:sdk
80
+
81
+ # Run all tests but use a Windows sandbox
82
+ TD_OS=windows npm run test:sdk
83
+
84
+ # Run with debugging enabled
85
+ DEBUG_ENV=true DEBUG_EVENTS=true npm run test:sdk
86
+
87
+ # Watch mode for development
88
+ npm run test:sdk:watch
89
+
90
+ # Generate coverage report
91
+ npm run test:sdk:coverage
92
+ ```
93
+
94
+ ## Test Structure
95
+
96
+ Each test follows this pattern:
97
+
98
+ ```javascript
99
+ import { afterEach, beforeEach, describe, it } from "vitest";
100
+ import {
101
+ createTestClient,
102
+ setupTest,
103
+ teardownTest,
104
+ } from "./setup/testHelpers.mjs";
105
+
106
+ describe("My Test", () => {
107
+ let testdriver;
108
+
109
+ beforeEach(async () => {
110
+ testdriver = createTestClient();
111
+ await setupTest(testdriver);
112
+ });
113
+
114
+ afterEach(async () => {
115
+ await teardownTest(testdriver);
116
+ });
117
+
118
+ it("should do something", async () => {
119
+ // Your test logic
120
+ });
121
+ });
122
+ ```
123
+
124
+ ## See Also
125
+
126
+ - [SDK README](../../SDK_README.md) - Full SDK documentation
127
+ - [Quick Reference](./QUICK_REFERENCE.md) - SDK method quick reference
128
+ - [Test Reporting](./TEST_REPORTING.md) - Test recording and reporting docs