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,266 @@
1
+ # Provision API
2
+
3
+ The `provision()` function is the easiest way to set up TestDriver for common applications. It automatically handles TestDriver initialization, application launching, and Dashcam recording.
4
+
5
+ ## Quick Start
6
+
7
+ ```javascript
8
+ import { test } from 'vitest';
9
+ import { provision } from 'testdriverai/presets';
10
+
11
+ test('my test', async (context) => {
12
+ const { testdriver } = await provision('chrome', {
13
+ url: 'https://example.com'
14
+ }, context);
15
+
16
+ await testdriver.find('Login button').click();
17
+ });
18
+ ```
19
+
20
+ ## API
21
+
22
+ ```typescript
23
+ provision(appType, options, context)
24
+ ```
25
+
26
+ **Parameters:**
27
+ - `appType` - Application type: `'chrome'`, `'vscode'`, `'electron'`, or `'webapp'`
28
+ - `options` - Configuration options (varies by app type)
29
+ - `context` - Vitest test context (from your test function parameter)
30
+
31
+ **Returns:**
32
+ - `testdriver` - TestDriver instance ready to use
33
+ - `dashcam` - Dashcam instance (if enabled)
34
+ - Additional app-specific properties (like `vscode`, `app`)
35
+
36
+ ## Application Types
37
+
38
+ ### Chrome Browser
39
+
40
+ ```javascript
41
+ const { testdriver } = await provision('chrome', {
42
+ url: 'https://myapp.com',
43
+ maximized: true, // Start maximized (default: true)
44
+ guest: true, // Use guest mode (default: true)
45
+ dashcam: true, // Enable Dashcam (default: true)
46
+ os: 'linux' // Target OS (default: 'linux')
47
+ }, context);
48
+
49
+ await testdriver.find('username').type('user@example.com');
50
+ await testdriver.find('Login').click();
51
+ ```
52
+
53
+ **Options:**
54
+ - `url` - URL to navigate to (default: 'http://testdriver-sandbox.vercel.app/')
55
+ - `maximized` - Start browser maximized (default: `true`)
56
+ - `guest` - Use guest/incognito mode (default: `true`)
57
+ - `dashcam` - Enable Dashcam recording (default: `true`)
58
+ - `os` - Target OS: `'linux'`, `'mac'`, or `'windows'` (default: `'linux'`)
59
+
60
+ **Returns:**
61
+ - `testdriver` - TestDriver instance
62
+ - `dashcam` - Dashcam instance (if enabled)
63
+
64
+ ### VS Code
65
+
66
+ ```javascript
67
+ const { testdriver, vscode } = await provision('vscode', {
68
+ workspace: '/path/to/project',
69
+ extensions: ['ms-python.python'],
70
+ dashcam: true,
71
+ os: 'linux'
72
+ }, context);
73
+
74
+ await vscode.find('File menu').click();
75
+ await vscode.find('New File').click();
76
+ ```
77
+
78
+ **Options:**
79
+ - `workspace` - Workspace/folder path to open (optional)
80
+ - `extensions` - Array of extension IDs to install (optional)
81
+ - `dashcam` - Enable Dashcam recording (default: `true`)
82
+ - `os` - Target OS (default: `'linux'`)
83
+
84
+ **Returns:**
85
+ - `testdriver` - TestDriver instance
86
+ - `vscode` - Alias for testdriver (semantic clarity)
87
+ - `dashcam` - Dashcam instance (if enabled)
88
+
89
+ ### Electron
90
+
91
+ ```javascript
92
+ const { testdriver, app } = await provision('electron', {
93
+ appPath: '/path/to/app',
94
+ args: ['--enable-logging'],
95
+ dashcam: true,
96
+ os: 'linux'
97
+ }, context);
98
+
99
+ await app.find('main window').click();
100
+ ```
101
+
102
+ **Options:**
103
+ - `appPath` - Path to Electron application (required)
104
+ - `args` - Additional command-line arguments (optional)
105
+ - `dashcam` - Enable Dashcam recording (default: `true`)
106
+ - `os` - Target OS (default: `'linux'`)
107
+
108
+ **Returns:**
109
+ - `testdriver` - TestDriver instance
110
+ - `app` - Alias for testdriver (semantic clarity)
111
+ - `dashcam` - Dashcam instance (if enabled)
112
+
113
+ ### Web App
114
+
115
+ Generic wrapper for web applications (currently uses Chrome):
116
+
117
+ ```javascript
118
+ const { testdriver } = await provision('webapp', {
119
+ url: 'https://example.com',
120
+ browser: 'chrome' // Only 'chrome' supported currently
121
+ }, context);
122
+ ```
123
+
124
+ ## Complete Example
125
+
126
+ ```javascript
127
+ import { describe, it, expect } from 'vitest';
128
+ import { provision } from 'testdriverai/presets';
129
+
130
+ describe('Login Flow', () => {
131
+ it('should login successfully', async (context) => {
132
+ // Provision Chrome with your app
133
+ const { testdriver, dashcam } = await provision('chrome', {
134
+ url: 'https://myapp.com/login',
135
+ maximized: true
136
+ }, context);
137
+
138
+ // Interact with the application
139
+ await testdriver.find('email input').type('user@example.com');
140
+ await testdriver.find('password input').type('password123');
141
+ await testdriver.find('Login button').click();
142
+
143
+ // Verify results
144
+ const result = await testdriver.assert('Welcome message is visible');
145
+ expect(result).toBeTruthy();
146
+
147
+ // Dashcam automatically stops and saves replay at test end
148
+ // No cleanup needed - handled automatically!
149
+ });
150
+ });
151
+ ```
152
+
153
+ ## How It Works
154
+
155
+ When you call `provision()`:
156
+
157
+ 1. **Creates TestDriver client** - Initializes and connects to sandbox
158
+ 2. **Sets up Dashcam** - Authenticates and starts recording (if enabled)
159
+ 3. **Launches application** - Opens the specified app with your configuration
160
+ 4. **Focuses window** - Ensures the app is ready for interaction
161
+ 5. **Returns ready-to-use instances** - Everything is set up and ready
162
+
163
+ At test end:
164
+ - Dashcam automatically stops and saves replay URL
165
+ - TestDriver automatically disconnects
166
+ - All cleanup is handled for you
167
+
168
+ ## Automatic Lifecycle
169
+
170
+ The `provision()` function uses Vitest hooks under the hood to manage the entire lifecycle:
171
+
172
+ ```javascript
173
+ // ✅ This:
174
+ const { testdriver } = await provision('chrome', { url }, context);
175
+
176
+ // Is equivalent to manually doing:
177
+ const client = new TestDriver(apiKey, { os: 'linux' });
178
+ await client.auth();
179
+ await client.connect();
180
+
181
+ const dashcam = new Dashcam(client);
182
+ await dashcam.auth();
183
+ await dashcam.start();
184
+
185
+ await client.exec('sh', 'google-chrome --start-maximized --guest "https://example.com" &', 30000);
186
+ await client.focusApplication('Google Chrome');
187
+
188
+ // ... your test code ...
189
+
190
+ await dashcam.stop();
191
+ await client.disconnect();
192
+ ```
193
+
194
+ That's **15+ lines of boilerplate** reduced to **1 line**!
195
+
196
+ ## TypeScript Support
197
+
198
+ Full TypeScript definitions included:
199
+
200
+ ```typescript
201
+ import { provision } from 'testdriverai/presets';
202
+
203
+ test('typed test', async (context) => {
204
+ const { testdriver } = await provision('chrome', {
205
+ url: 'https://example.com',
206
+ maximized: true,
207
+ os: 'linux' // ✅ Type-safe: only 'linux' | 'mac' | 'windows'
208
+ }, context);
209
+
210
+ // ✅ Full autocomplete for testdriver methods
211
+ await testdriver.find('button').click();
212
+ });
213
+ ```
214
+
215
+ ## Direct Preset Functions
216
+
217
+ You can also use the individual preset functions directly:
218
+
219
+ ```javascript
220
+ import { chrome, vscode, electron } from 'testdriverai/presets';
221
+
222
+ // Same as provision('chrome', options, context)
223
+ const { testdriver } = await chrome(context, {
224
+ url: 'https://example.com'
225
+ });
226
+
227
+ // Same as provision('vscode', options, context)
228
+ const { vscode } = await vscode(context, {
229
+ workspace: '/path/to/project'
230
+ });
231
+ ```
232
+
233
+ These are available for when you prefer explicit function names.
234
+
235
+ ## Best Practices
236
+
237
+ 1. **Always pass context** - Required for automatic cleanup
238
+ 2. **Enable dashcam** - Great for debugging test failures
239
+ 3. **Use descriptive variables** - `testdriver`, `vscode`, `app` based on what you're testing
240
+ 4. **Leverage TypeScript** - Get autocomplete and type safety
241
+ 5. **Keep URLs in config** - Use environment variables for different environments
242
+
243
+ ## Error Handling
244
+
245
+ ```javascript
246
+ test('handles errors gracefully', async (context) => {
247
+ try {
248
+ const { testdriver } = await provision('chrome', {
249
+ url: 'https://example.com'
250
+ }, context);
251
+
252
+ await testdriver.find('button').click();
253
+ } catch (error) {
254
+ // Cleanup still happens automatically
255
+ console.error('Test failed:', error);
256
+ throw error; // Re-throw to mark test as failed
257
+ }
258
+ });
259
+ ```
260
+
261
+ ## See Also
262
+
263
+ - [Hooks API](./HOOKS.md) - For more control over lifecycle
264
+ - [Core Classes](./CORE.md) - For full manual control
265
+ - [Migration Guide](../MIGRATION.md) - Upgrading from v6
266
+ - [Examples](../../testdriver/acceptance-sdk/presets-example.test.mjs) - Working examples
package/eslint.config.js CHANGED
@@ -35,9 +35,27 @@ module.exports = [
35
35
  },
36
36
  },
37
37
  },
38
+ {
39
+ // Config for ES Module files (.mjs) - used in SDK tests
40
+ files: ["**/*.mjs"],
41
+ languageOptions: {
42
+ sourceType: "module",
43
+ ecmaVersion: 2022,
44
+ globals: {
45
+ ...globals.node,
46
+ },
47
+ },
48
+ },
38
49
  {
39
50
  // this needs to be it's own object for some reason
40
51
  // https://github.com/eslint/eslint/issues/17400
41
- ignores: ["agent/lib/subimage/**", "node_modules/**", ".git"],
52
+ ignores: [
53
+ "agent/lib/subimage/**",
54
+ "node_modules/**",
55
+ ".git",
56
+ "test-results/**",
57
+ "examples/test-recording-example.test.js",
58
+ "vitest.config.example.js",
59
+ ],
42
60
  },
43
61
  ];
@@ -37,12 +37,14 @@ class BaseCommand extends Command {
37
37
  }
38
38
 
39
39
  sendToSandbox(message) {
40
+ if (!message) return;
41
+
40
42
  // ensure message is a string
41
43
  if (typeof message !== "string") {
42
44
  message = JSON.stringify(message);
43
45
  }
46
+
44
47
  this.agent.sandbox.send({
45
- os: "linux",
46
48
  type: "output",
47
49
  output: Buffer.from(message).toString("base64"),
48
50
  });
@@ -95,7 +97,7 @@ class BaseCommand extends Command {
95
97
  });
96
98
 
97
99
  // Handle sandbox connection with pattern matching for subsequent events
98
- this.agent.emitter.on("sandbox:connected", () => {
100
+ this.agent.emitter.once("sandbox:connected", () => {
99
101
  isConnected = true;
100
102
  // Once sandbox is connected, send all log and error events to sandbox
101
103
  this.agent.emitter.on("log:*", (message) => {
@@ -145,8 +147,12 @@ class BaseCommand extends Command {
145
147
  console.log(`Live test execution: `);
146
148
  if (this.agent.config.CI) {
147
149
  let u = new URL(url);
148
- u = JSON.parse(u.searchParams.get("data"));
149
- console.log(`${u.url}&view_only=true`);
150
+ try {
151
+ u = JSON.parse(u.searchParams.get("data"));
152
+ console.log(`${u.url}&view_only=true`);
153
+ } catch {
154
+ console.log(url);
155
+ }
150
156
  } else {
151
157
  console.log(url);
152
158
  await openBrowser(url);
@@ -21,6 +21,8 @@ class CustomTransport extends Transport {
21
21
  this.sandbox = require("../agent/lib/sandbox");
22
22
  }
23
23
 
24
+ console.log("CustomTransport log message:", message);
25
+
24
26
  if (this.sandbox && this.sandbox.instanceSocketConnected) {
25
27
  if (typeof message === "object") {
26
28
  console.log(chalk.cyan("protecting against base64 error"));
@@ -29,7 +31,6 @@ class CustomTransport extends Transport {
29
31
  }
30
32
 
31
33
  this.sandbox.send({
32
- os: "linux",
33
34
  type: "output",
34
35
  output: Buffer.from(message).toString("base64"),
35
36
  });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Shared Test State Module
3
+ *
4
+ * This module uses Node.js module caching to share state between
5
+ * the reporter process and worker processes in Vitest.
6
+ *
7
+ * Since Node.js caches modules, all imports of this file will
8
+ * receive the same state object instance.
9
+ */
10
+
11
+ // Shared state object that persists across all imports
12
+ const sharedState = {
13
+ testRun: null,
14
+ testRunId: null,
15
+ token: null,
16
+ apiKey: null,
17
+ apiRoot: null,
18
+ startTime: null,
19
+ };
20
+
21
+ /**
22
+ * Set the test run information
23
+ */
24
+ export function setTestRunInfo(info) {
25
+ console.log("[SharedState] Setting test run info:", {
26
+ testRunId: info.testRunId,
27
+ hasToken: !!info.token,
28
+ hasTestRun: !!info.testRun,
29
+ });
30
+
31
+ if (info.testRun) sharedState.testRun = info.testRun;
32
+ if (info.testRunId) sharedState.testRunId = info.testRunId;
33
+ if (info.token) sharedState.token = info.token;
34
+ if (info.apiKey) sharedState.apiKey = info.apiKey;
35
+ if (info.apiRoot) sharedState.apiRoot = info.apiRoot;
36
+ if (info.startTime) sharedState.startTime = info.startTime;
37
+ }
38
+
39
+ /**
40
+ * Get the test run information
41
+ */
42
+ export function getTestRunInfo() {
43
+ return {
44
+ testRun: sharedState.testRun,
45
+ testRunId: sharedState.testRunId,
46
+ token: sharedState.token,
47
+ apiKey: sharedState.apiKey,
48
+ apiRoot: sharedState.apiRoot,
49
+ startTime: sharedState.startTime,
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Clear the test run information
55
+ */
56
+ export function clearTestRunInfo() {
57
+ console.log("[SharedState] Clearing test run info");
58
+ sharedState.testRun = null;
59
+ sharedState.testRunId = null;
60
+ sharedState.token = null;
61
+ sharedState.startTime = null;
62
+ }
63
+
64
+ /**
65
+ * Direct access to state (for debugging)
66
+ */
67
+ export function getState() {
68
+ return sharedState;
69
+ }