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,535 @@
1
+ ---
2
+ title: "Using TestDriver with Vitest"
3
+ sidebarTitle: "Vitest Integration"
4
+ description: "Complete guide to integrating TestDriver with Vitest"
5
+ icon: "flask-vial"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ TestDriver integrates seamlessly with Vitest, providing three levels of API complexity to match your needs. From simple preset functions to full manual control, choose the approach that works best for your project.
11
+
12
+ ## Quick Start
13
+
14
+ ### 1. Install TestDriver
15
+
16
+ ```bash
17
+ npm install --save-dev testdriverai
18
+ ```
19
+
20
+ ### 2. Create Vitest Config
21
+
22
+ ```javascript vitest.config.mjs
23
+ import { defineConfig } from 'vitest/config';
24
+
25
+ export default defineConfig({
26
+ test: {
27
+ // Optional: Configure test timeout
28
+ testTimeout: 120000,
29
+ hookTimeout: 120000,
30
+ },
31
+ });
32
+ ```
33
+
34
+ ### 3. Write Your First Test
35
+
36
+ ```javascript example.test.js
37
+ import { test } from 'vitest';
38
+ import { chrome } from 'testdriverai/presets';
39
+
40
+ test('my first test', async (context) => {
41
+ const { testdriver } = await chrome(context, {
42
+ url: 'https://example.com'
43
+ });
44
+
45
+ await testdriver.find('More information link').click();
46
+ await testdriver.assert('IANA information page is visible');
47
+ });
48
+ ```
49
+
50
+ ### 4. Run Your Tests
51
+
52
+ ```bash
53
+ npx vitest
54
+ ```
55
+
56
+ That's it! TestDriver automatically handles all setup and teardown.
57
+
58
+ ## Three Levels of Integration
59
+
60
+ <CardGroup cols={3}>
61
+ <Card title="Provision API" icon="rocket" href="/v7/progressive-apis/PROVISION">
62
+ **Easiest** - One-line setup
63
+ ```javascript
64
+ const { testdriver } = await provision('chrome', { url }, context);
65
+ ```
66
+ </Card>
67
+
68
+ <Card title="Hooks API" icon="link" href="/v7/progressive-apis/HOOKS">
69
+ **Flexible** - More control
70
+ ```javascript
71
+ const client = useTestDriver(context);
72
+ const dashcam = useDashcam(context, client);
73
+ ```
74
+ </Card>
75
+
76
+ <Card title="Core Classes" icon="code" href="/v7/progressive-apis/CORE">
77
+ **Full Control** - Manual everything
78
+ ```javascript
79
+ const client = new TestDriver(apiKey);
80
+ await client.connect();
81
+ ```
82
+ </Card>
83
+ </CardGroup>
84
+
85
+ ## Complete Examples
86
+
87
+ ### Web Application Testing
88
+
89
+ ```javascript login.test.js
90
+ import { describe, test, expect } from 'vitest';
91
+ import { chrome } from 'testdriverai/presets';
92
+
93
+ describe('User Login', () => {
94
+ test('successful login flow', async (context) => {
95
+ const { testdriver, dashcam } = await chrome(context, {
96
+ url: 'https://myapp.com/login',
97
+ maximized: true
98
+ });
99
+
100
+ // Fill login form
101
+ await testdriver.find('email input').type('user@example.com');
102
+ await testdriver.find('password input').type('password123');
103
+ await testdriver.find('Login button').click();
104
+
105
+ // Verify dashboard loads
106
+ const result = await testdriver.assert('Welcome message is visible');
107
+ expect(result).toBeTruthy();
108
+
109
+ // Dashcam automatically saves replay URL
110
+ console.log('Replay:', dashcam.url);
111
+ });
112
+
113
+ test('invalid credentials error', async (context) => {
114
+ const { testdriver } = await chrome(context, {
115
+ url: 'https://myapp.com/login'
116
+ });
117
+
118
+ await testdriver.find('email input').type('wrong@example.com');
119
+ await testdriver.find('password input').type('wrongpass');
120
+ await testdriver.find('Login button').click();
121
+
122
+ await testdriver.assert('Invalid credentials error appears');
123
+ });
124
+ });
125
+ ```
126
+
127
+ ### VS Code Extension Testing
128
+
129
+ ```javascript extension.test.js
130
+ import { test } from 'vitest';
131
+ import { vscode } from 'testdriverai/presets';
132
+
133
+ test('create new python file', async (context) => {
134
+ const { vscode } = await vscode(context, {
135
+ workspace: '/tmp/test-project',
136
+ extensions: ['ms-python.python']
137
+ });
138
+
139
+ // Open command palette
140
+ await vscode.pressKeys(['cmd', 'shift', 'p']);
141
+
142
+ // Create new Python file
143
+ await vscode.type('Python: Create New File');
144
+ await vscode.pressKeys(['enter']);
145
+
146
+ // Verify file created
147
+ await vscode.assert('Untitled Python file is open');
148
+ });
149
+ ```
150
+
151
+ ### Electron App Testing
152
+
153
+ ```javascript electron-app.test.js
154
+ import { test } from 'vitest';
155
+ import { electron } from 'testdriverai/presets';
156
+
157
+ test('file menu operations', async (context) => {
158
+ const { app } = await electron(context, {
159
+ appPath: './dist/my-app',
160
+ args: ['--enable-logging']
161
+ });
162
+
163
+ await app.find('File menu').click();
164
+ await app.find('New Document').click();
165
+
166
+ await app.assert('New document window opens');
167
+ });
168
+ ```
169
+
170
+ ### Using Multiple Presets
171
+
172
+ ```javascript multi-app.test.js
173
+ import { test } from 'vitest';
174
+ import { chrome, vscode } from 'testdriverai/presets';
175
+
176
+ test('test chrome and vscode together', async (context) => {
177
+ // Both share the same Vitest context for cleanup
178
+ const browser = await chrome(context, {
179
+ url: 'https://example.com'
180
+ });
181
+
182
+ const editor = await vscode(context, {
183
+ workspace: '/tmp/project'
184
+ });
185
+
186
+ // Use both in the same test
187
+ await browser.testdriver.find('link').click();
188
+ await editor.vscode.find('File').click();
189
+ });
190
+ ```
191
+
192
+ ## Test Lifecycle
193
+
194
+ TestDriver automatically manages the entire test lifecycle:
195
+
196
+ ```javascript
197
+ test('lifecycle example', async (context) => {
198
+ // 1. Setup happens automatically when you call preset
199
+ const { testdriver, dashcam } = await chrome(context, { url });
200
+
201
+ // 2. Your test code runs
202
+ await testdriver.find('button').click();
203
+
204
+ // 3. Teardown happens automatically after test completes
205
+ // - Dashcam stops and saves replay URL
206
+ // - TestDriver disconnects from sandbox
207
+ // - All resources are cleaned up
208
+ });
209
+ ```
210
+
211
+ ### Automatic Cleanup
212
+
213
+ Even if your test fails or throws an error, cleanup still happens:
214
+
215
+ ```javascript
216
+ test('error handling', async (context) => {
217
+ const { testdriver } = await chrome(context, { url });
218
+
219
+ try {
220
+ await testdriver.find('non-existent element').click();
221
+ } catch (error) {
222
+ // Cleanup STILL happens automatically via Vitest hooks
223
+ console.error('Test failed:', error);
224
+ throw error;
225
+ }
226
+ // No need for finally block or manual cleanup
227
+ });
228
+ ```
229
+
230
+ ## Configuration
231
+
232
+ ### Environment Variables
233
+
234
+ Create a `.env` file in your project root:
235
+
236
+ ```bash .env
237
+ TD_API_KEY=your-api-key-here
238
+ TD_API_ROOT=https://testdriver-api.onrender.com
239
+ ```
240
+
241
+ TestDriver automatically reads these when initializing.
242
+
243
+ ### Vitest Config Options
244
+
245
+ ```javascript vitest.config.mjs
246
+ import { defineConfig } from 'vitest/config';
247
+
248
+ export default defineConfig({
249
+ test: {
250
+ // Recommended: Increase timeouts for UI testing
251
+ testTimeout: 120000, // 2 minutes per test
252
+ hookTimeout: 120000, // 2 minutes for setup/teardown
253
+
254
+ // Optional: Run tests sequentially for resource-intensive tests
255
+ threads: false,
256
+
257
+ // Optional: Limit concurrent tests
258
+ maxConcurrency: 3,
259
+
260
+ // Optional: Enable file watching
261
+ watch: false,
262
+ },
263
+ });
264
+ ```
265
+
266
+ ### Per-Test Configuration
267
+
268
+ Override defaults for specific tests:
269
+
270
+ ```javascript
271
+ test('long running test', async (context) => {
272
+ const { testdriver } = await chrome(context, {
273
+ url: 'https://slow-app.com',
274
+ dashcam: false, // Disable recording for faster execution
275
+ maximized: false,
276
+ });
277
+
278
+ // Your test code
279
+ }, { timeout: 180000 }); // 3-minute timeout for this test only
280
+ ```
281
+
282
+ ## Running Tests
283
+
284
+ ### Basic Commands
285
+
286
+ ```bash
287
+ # Run all tests
288
+ npx vitest
289
+
290
+ # Run specific file
291
+ npx vitest login.test.js
292
+
293
+ # Run in watch mode
294
+ npx vitest --watch
295
+
296
+ # Run with coverage
297
+ npx vitest --coverage
298
+
299
+ # Run tests matching pattern
300
+ npx vitest --grep "login"
301
+ ```
302
+
303
+ ### CI/CD Integration
304
+
305
+ ```yaml .github/workflows/test.yml
306
+ name: TestDriver Tests
307
+
308
+ on: [push, pull_request]
309
+
310
+ jobs:
311
+ test:
312
+ runs-on: ubuntu-latest
313
+ steps:
314
+ - uses: actions/checkout@v3
315
+
316
+ - name: Setup Node.js
317
+ uses: actions/setup-node@v3
318
+ with:
319
+ node-version: '18'
320
+
321
+ - name: Install dependencies
322
+ run: npm install
323
+
324
+ - name: Run tests
325
+ env:
326
+ TD_API_KEY: ${{ secrets.TD_API_KEY }}
327
+ run: npx vitest --run
328
+ ```
329
+
330
+ ## Advanced Patterns
331
+
332
+ ### Shared Setup with beforeEach
333
+
334
+ ```javascript
335
+ import { describe, test, beforeEach } from 'vitest';
336
+ import { chrome } from 'testdriverai/presets';
337
+
338
+ describe('Dashboard Tests', () => {
339
+ let testdriver;
340
+
341
+ beforeEach(async (context) => {
342
+ // Setup runs before each test
343
+ const result = await chrome(context, {
344
+ url: 'https://myapp.com'
345
+ });
346
+ testdriver = result.testdriver;
347
+
348
+ // Shared login
349
+ await testdriver.find('email').type('user@example.com');
350
+ await testdriver.find('password').type('password');
351
+ await testdriver.find('Login').click();
352
+ });
353
+
354
+ test('view profile', async () => {
355
+ await testdriver.find('Profile link').click();
356
+ await testdriver.assert('Profile page loads');
357
+ });
358
+
359
+ test('view settings', async () => {
360
+ await testdriver.find('Settings link').click();
361
+ await testdriver.assert('Settings page loads');
362
+ });
363
+ });
364
+ ```
365
+
366
+ ### Parameterized Tests
367
+
368
+ ```javascript
369
+ import { test } from 'vitest';
370
+ import { chrome } from 'testdriverai/presets';
371
+
372
+ const testCases = [
373
+ { browser: 'chrome', os: 'linux' },
374
+ { browser: 'chrome', os: 'windows' },
375
+ { browser: 'chrome', os: 'mac' },
376
+ ];
377
+
378
+ testCases.forEach(({ browser, os }) => {
379
+ test(`login on ${os}`, async (context) => {
380
+ const { testdriver } = await chrome(context, {
381
+ url: 'https://myapp.com',
382
+ os
383
+ });
384
+
385
+ await testdriver.find('Login').click();
386
+ await testdriver.assert('Login successful');
387
+ });
388
+ });
389
+ ```
390
+
391
+ ### Custom Helpers
392
+
393
+ ```javascript helpers.js
394
+ import { chrome } from 'testdriverai/presets';
395
+
396
+ export async function loginAsUser(context, email, password) {
397
+ const { testdriver } = await chrome(context, {
398
+ url: 'https://myapp.com/login'
399
+ });
400
+
401
+ await testdriver.find('email input').type(email);
402
+ await testdriver.find('password input').type(password);
403
+ await testdriver.find('Login button').click();
404
+
405
+ return testdriver;
406
+ }
407
+ ```
408
+
409
+ ```javascript test.js
410
+ import { test } from 'vitest';
411
+ import { loginAsUser } from './helpers.js';
412
+
413
+ test('logged in user can view dashboard', async (context) => {
414
+ const testdriver = await loginAsUser(context, 'user@example.com', 'pass123');
415
+
416
+ await testdriver.find('Dashboard link').click();
417
+ await testdriver.assert('Dashboard is visible');
418
+ });
419
+ ```
420
+
421
+ ## Best Practices
422
+
423
+ ### 1. Use Descriptive Test Names
424
+
425
+ ```javascript
426
+ // ✅ Good
427
+ test('user can login with valid credentials and view dashboard', async (context) => {
428
+
429
+ // ❌ Bad
430
+ test('test1', async (context) => {
431
+ ```
432
+
433
+ ### 2. Enable Dashcam for Debugging
434
+
435
+ ```javascript
436
+ test('complex interaction', async (context) => {
437
+ const { testdriver, dashcam } = await chrome(context, {
438
+ url: 'https://myapp.com',
439
+ dashcam: true // Always enable for debugging
440
+ });
441
+
442
+ // If test fails, check dashcam.url for replay
443
+ });
444
+ ```
445
+
446
+ ### 3. Use Assertions Liberally
447
+
448
+ ```javascript
449
+ test('multi-step flow', async (context) => {
450
+ const { testdriver } = await chrome(context, { url });
451
+
452
+ await testdriver.find('Step 1').click();
453
+ await testdriver.assert('Step 1 completed'); // Verify each step
454
+
455
+ await testdriver.find('Step 2').click();
456
+ await testdriver.assert('Step 2 completed');
457
+ });
458
+ ```
459
+
460
+ ### 4. Keep Tests Focused
461
+
462
+ ```javascript
463
+ // ✅ Good - One test per scenario
464
+ test('user can login', async (context) => { /* ... */ });
465
+ test('user can logout', async (context) => { /* ... */ });
466
+
467
+ // ❌ Bad - Testing too many things
468
+ test('user can login and logout and change settings and...', async (context) => { /* ... */ });
469
+ ```
470
+
471
+ ### 5. Use Environment Variables for Secrets
472
+
473
+ ```javascript
474
+ // ✅ Good
475
+ await testdriver.find('password').type(process.env.TEST_PASSWORD);
476
+
477
+ // ❌ Bad
478
+ await testdriver.find('password').type('hardcoded-password');
479
+ ```
480
+
481
+ ## Troubleshooting
482
+
483
+ ### Tests Timeout
484
+
485
+ Increase timeout in vitest.config.mjs:
486
+
487
+ ```javascript
488
+ export default defineConfig({
489
+ test: {
490
+ testTimeout: 180000, // 3 minutes
491
+ },
492
+ });
493
+ ```
494
+
495
+ ### Cleanup Not Working
496
+
497
+ Make sure you're passing the `context` parameter:
498
+
499
+ ```javascript
500
+ // ✅ Correct
501
+ test('my test', async (context) => {
502
+ await chrome(context, { url });
503
+ });
504
+
505
+ // ❌ Wrong - cleanup won't work
506
+ test('my test', async () => {
507
+ await chrome({}, { url });
508
+ });
509
+ ```
510
+
511
+ ### Dashcam URL Not Available
512
+
513
+ Ensure Dashcam is enabled and check for errors:
514
+
515
+ ```javascript
516
+ const { testdriver, dashcam } = await chrome(context, {
517
+ url: 'https://example.com',
518
+ dashcam: true
519
+ });
520
+
521
+ if (dashcam) {
522
+ console.log('Replay URL:', dashcam.url);
523
+ } else {
524
+ console.error('Dashcam not initialized');
525
+ }
526
+ ```
527
+
528
+ ## See Also
529
+
530
+ - [Provision API](/v7/progressive-apis/PROVISION) - One-line setup for common apps
531
+ - [Hooks API](/v7/progressive-apis/HOOKS) - Flexible lifecycle control
532
+ - [Chrome Preset](/v7/presets/chrome) - Browser testing
533
+ - [VS Code Preset](/v7/presets/vscode) - Extension testing
534
+ - [Electron Preset](/v7/presets/electron) - Desktop app testing
535
+ - [Vitest Plugin](/v7/guides/vitest-plugin) - Test recording and reporting