testdriverai 7.0.0 → 7.1.1

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 (324) hide show
  1. package/.env.example +2 -0
  2. package/.github/workflows/linux-tests.yml +28 -0
  3. package/README.md +126 -0
  4. package/agent/index.js +7 -9
  5. package/agent/interface.js +13 -2
  6. package/agent/lib/commands.js +795 -136
  7. package/agent/lib/redraw.js +124 -39
  8. package/agent/lib/sandbox.js +40 -3
  9. package/agent/lib/sdk.js +21 -0
  10. package/agent/lib/valid-version.js +2 -2
  11. package/debugger/index.html +1 -1
  12. package/docs/docs.json +86 -71
  13. package/docs/guide/best-practices-polling.mdx +154 -0
  14. package/docs/v6/getting-started/self-hosting.mdx +3 -2
  15. package/docs/v7/_drafts/agents.mdx +852 -0
  16. package/docs/v7/_drafts/auto-cache-key.mdx +167 -0
  17. package/docs/v7/_drafts/best-practices.mdx +486 -0
  18. package/docs/v7/_drafts/caching-ai.mdx +215 -0
  19. package/docs/v7/_drafts/caching-selectors.mdx +400 -0
  20. package/docs/v7/_drafts/caching.mdx +366 -0
  21. package/docs/v7/_drafts/cli-to-sdk-migration.mdx +425 -0
  22. package/docs/v7/_drafts/core.mdx +459 -0
  23. package/docs/v7/_drafts/dashcam-title-feature.mdx +89 -0
  24. package/docs/v7/_drafts/debugging.mdx +349 -0
  25. package/docs/v7/_drafts/error-handling.mdx +501 -0
  26. package/docs/v7/_drafts/faq.mdx +393 -0
  27. package/docs/v7/_drafts/hooks.mdx +360 -0
  28. package/docs/v7/_drafts/implementation-plan.mdx +994 -0
  29. package/docs/v7/_drafts/init-command.mdx +95 -0
  30. package/docs/v7/_drafts/optimal-sdk-design.mdx +1348 -0
  31. package/docs/v7/_drafts/performance.mdx +517 -0
  32. package/docs/v7/_drafts/presets.mdx +210 -0
  33. package/docs/v7/_drafts/progressive-disclosure.mdx +230 -0
  34. package/docs/v7/_drafts/provision.mdx +266 -0
  35. package/docs/{QUICK_START_TEST_RECORDING.md → v7/_drafts/quick-start-test-recording.mdx} +3 -3
  36. package/docs/v7/_drafts/sdk-v7-complete.mdx +345 -0
  37. package/docs/v7/{guides → _drafts}/self-hosting.mdx +1 -1
  38. package/docs/v7/_drafts/troubleshooting.mdx +526 -0
  39. package/docs/v7/_drafts/vitest-plugin.mdx +477 -0
  40. package/docs/v7/_drafts/vitest.mdx +535 -0
  41. package/docs/v7/api/{ai.mdx → act.mdx} +24 -24
  42. package/docs/v7/api/client.mdx +1 -1
  43. package/docs/v7/api/dashcam.mdx +497 -0
  44. package/docs/v7/api/doubleClick.mdx +102 -0
  45. package/docs/v7/api/elements.mdx +143 -41
  46. package/docs/v7/api/find.mdx +258 -0
  47. package/docs/v7/api/mouseDown.mdx +161 -0
  48. package/docs/v7/api/mouseUp.mdx +164 -0
  49. package/docs/v7/api/rightClick.mdx +123 -0
  50. package/docs/v7/api/type.mdx +51 -7
  51. package/docs/v7/features/ai-native.mdx +427 -0
  52. package/docs/v7/features/easy-to-write.mdx +351 -0
  53. package/docs/v7/features/enterprise.mdx +540 -0
  54. package/docs/v7/features/fast.mdx +424 -0
  55. package/docs/v7/features/observable.mdx +623 -0
  56. package/docs/v7/features/powerful.mdx +531 -0
  57. package/docs/v7/features/scalable.mdx +417 -0
  58. package/docs/v7/features/stable.mdx +514 -0
  59. package/docs/v7/getting-started/configuration.mdx +380 -0
  60. package/docs/v7/getting-started/generating-tests.mdx +525 -0
  61. package/docs/v7/getting-started/installation.mdx +486 -0
  62. package/docs/v7/getting-started/quickstart.mdx +320 -141
  63. package/docs/v7/getting-started/running-and-debugging.mdx +511 -0
  64. package/docs/v7/getting-started/setting-up-in-ci.mdx +612 -0
  65. package/docs/v7/getting-started/writing-tests.mdx +535 -0
  66. package/docs/v7/overview/what-is-testdriver.mdx +398 -0
  67. package/docs/v7/platforms/linux.mdx +308 -0
  68. package/docs/v7/platforms/macos.mdx +433 -0
  69. package/docs/v7/platforms/windows.mdx +430 -0
  70. package/docs/v7/playwright.mdx +3 -3
  71. package/docs/v7/presets/chrome-extension.mdx +223 -0
  72. package/docs/v7/presets/chrome.mdx +303 -0
  73. package/docs/v7/presets/electron.mdx +453 -0
  74. package/docs/v7/presets/vscode.mdx +417 -0
  75. package/docs/v7/presets/webapp.mdx +396 -0
  76. package/examples/run-tests-with-recording.sh +2 -2
  77. package/interfaces/cli/commands/init.js +358 -0
  78. package/interfaces/vitest-plugin.mjs +393 -103
  79. package/lib/core/Dashcam.js +506 -0
  80. package/lib/core/index.d.ts +150 -0
  81. package/lib/core/index.js +12 -0
  82. package/lib/presets/index.mjs +331 -0
  83. package/lib/vitest/hooks.d.ts +119 -0
  84. package/lib/vitest/hooks.mjs +316 -0
  85. package/lib/vitest/setup.mjs +44 -0
  86. package/package.json +13 -3
  87. package/sdk.d.ts +350 -44
  88. package/sdk.js +818 -105
  89. package/{self-hosted.yml → setup/aws/self-hosted.yml} +1 -1
  90. package/test/manual/test-console-logs.test.mjs +42 -0
  91. package/test/manual/test-init.sh +54 -0
  92. package/test/manual/test-provision-auth.mjs +22 -0
  93. package/test/testdriver/assert.test.mjs +41 -0
  94. package/test/testdriver/auto-cache-key-demo.test.mjs +56 -0
  95. package/test/testdriver/chrome-extension.test.mjs +89 -0
  96. package/{testdriver/acceptance-sdk → test/testdriver}/drag-and-drop.test.mjs +7 -19
  97. package/{testdriver/acceptance-sdk → test/testdriver}/element-not-found.test.mjs +6 -19
  98. package/{testdriver/acceptance-sdk → test/testdriver}/exec-js.test.mjs +6 -18
  99. package/{testdriver/acceptance-sdk → test/testdriver}/exec-output.test.mjs +9 -21
  100. package/{testdriver/acceptance-sdk → test/testdriver}/exec-pwsh.test.mjs +14 -26
  101. package/{testdriver/acceptance-sdk → test/testdriver}/focus-window.test.mjs +8 -20
  102. package/{testdriver/acceptance-sdk → test/testdriver}/formatted-logging.test.mjs +5 -20
  103. package/{testdriver/acceptance-sdk → test/testdriver}/hover-image.test.mjs +10 -19
  104. package/{testdriver/acceptance-sdk → test/testdriver}/hover-text-with-description.test.mjs +7 -19
  105. package/{testdriver/acceptance-sdk → test/testdriver}/hover-text.test.mjs +5 -19
  106. package/{testdriver/acceptance-sdk → test/testdriver}/match-image.test.mjs +7 -19
  107. package/{testdriver/acceptance-sdk → test/testdriver}/press-keys.test.mjs +5 -19
  108. package/{testdriver/acceptance-sdk → test/testdriver}/prompt.test.mjs +7 -19
  109. package/{testdriver/acceptance-sdk → test/testdriver}/scroll-keyboard.test.mjs +6 -20
  110. package/{testdriver/acceptance-sdk → test/testdriver}/scroll-until-image.test.mjs +6 -18
  111. package/test/testdriver/scroll-until-text.test.mjs +28 -0
  112. package/{testdriver/acceptance-sdk → test/testdriver}/scroll.test.mjs +12 -21
  113. package/test/testdriver/setup/lifecycleHelpers.mjs +262 -0
  114. package/{testdriver/acceptance-sdk → test/testdriver}/setup/testHelpers.mjs +25 -20
  115. package/test/testdriver/type.test.mjs +45 -0
  116. package/vitest.config.mjs +11 -56
  117. package/.github/dependabot.yml +0 -11
  118. package/.github/workflows/acceptance-linux.yml +0 -75
  119. package/.github/workflows/acceptance-sdk-tests.yml +0 -133
  120. package/.github/workflows/acceptance-tests.yml +0 -130
  121. package/.github/workflows/lint.yml +0 -27
  122. package/.github/workflows/publish-canary.yml +0 -40
  123. package/.github/workflows/publish-latest.yml +0 -61
  124. package/.github/workflows/test-install.yml +0 -29
  125. package/.vscode/extensions.json +0 -3
  126. package/.vscode/launch.json +0 -22
  127. package/.vscode/mcp.json +0 -9
  128. package/.vscode/settings.json +0 -14
  129. package/CODEOWNERS +0 -3
  130. package/MIGRATION.md +0 -389
  131. package/SDK_README.md +0 -1122
  132. package/_testdriver/acceptance/assert.yaml +0 -7
  133. package/_testdriver/acceptance/dashcam.yaml +0 -9
  134. package/_testdriver/acceptance/drag-and-drop.yaml +0 -49
  135. package/_testdriver/acceptance/embed.yaml +0 -9
  136. package/_testdriver/acceptance/exec-js.yaml +0 -29
  137. package/_testdriver/acceptance/exec-output.yaml +0 -43
  138. package/_testdriver/acceptance/exec-shell.yaml +0 -40
  139. package/_testdriver/acceptance/focus-window.yaml +0 -16
  140. package/_testdriver/acceptance/hover-image.yaml +0 -18
  141. package/_testdriver/acceptance/hover-text-with-description.yaml +0 -29
  142. package/_testdriver/acceptance/hover-text.yaml +0 -14
  143. package/_testdriver/acceptance/if-else.yaml +0 -31
  144. package/_testdriver/acceptance/match-image.yaml +0 -15
  145. package/_testdriver/acceptance/press-keys.yaml +0 -35
  146. package/_testdriver/acceptance/prompt.yaml +0 -11
  147. package/_testdriver/acceptance/remember.yaml +0 -27
  148. package/_testdriver/acceptance/screenshots/cart.png +0 -0
  149. package/_testdriver/acceptance/scroll-keyboard.yaml +0 -34
  150. package/_testdriver/acceptance/scroll-until-image.yaml +0 -26
  151. package/_testdriver/acceptance/scroll-until-text.yaml +0 -20
  152. package/_testdriver/acceptance/scroll.yaml +0 -33
  153. package/_testdriver/acceptance/snippets/login.yaml +0 -29
  154. package/_testdriver/acceptance/snippets/match-cart.yaml +0 -8
  155. package/_testdriver/acceptance/type.yaml +0 -29
  156. package/_testdriver/behavior/failure.yaml +0 -7
  157. package/_testdriver/behavior/hover-text.yaml +0 -13
  158. package/_testdriver/behavior/lifecycle/postrun.yaml +0 -10
  159. package/_testdriver/behavior/lifecycle/prerun.yaml +0 -8
  160. package/_testdriver/behavior/lifecycle/provision.yaml +0 -8
  161. package/_testdriver/behavior/secrets.yaml +0 -7
  162. package/_testdriver/edge-cases/dashcam-chrome.yaml +0 -8
  163. package/_testdriver/edge-cases/exec-pwsh-multiline.yaml +0 -10
  164. package/_testdriver/edge-cases/js-exception.yaml +0 -8
  165. package/_testdriver/edge-cases/js-promise.yaml +0 -19
  166. package/_testdriver/edge-cases/lifecycle/postrun.yaml +0 -10
  167. package/_testdriver/edge-cases/prompt-in-middle.yaml +0 -23
  168. package/_testdriver/edge-cases/prompt-nested.yaml +0 -7
  169. package/_testdriver/edge-cases/success-test.yaml +0 -9
  170. package/_testdriver/examples/android/example.yaml +0 -12
  171. package/_testdriver/examples/android/lifecycle/postrun.yaml +0 -11
  172. package/_testdriver/examples/android/lifecycle/provision.yaml +0 -47
  173. package/_testdriver/examples/android/readme.md +0 -7
  174. package/_testdriver/examples/chrome-extension/lifecycle/provision.yaml +0 -74
  175. package/_testdriver/examples/desktop/lifecycle/prerun.yaml +0 -0
  176. package/_testdriver/examples/desktop/lifecycle/provision.yaml +0 -64
  177. package/_testdriver/examples/vscode-extension/lifecycle/provision.yaml +0 -73
  178. package/_testdriver/examples/web/lifecycle/postrun.yaml +0 -7
  179. package/_testdriver/examples/web/lifecycle/prerun.yaml +0 -22
  180. package/_testdriver/lifecycle/postrun.yaml +0 -8
  181. package/_testdriver/lifecycle/prerun.yaml +0 -15
  182. package/_testdriver/lifecycle/provision.yaml +0 -25
  183. package/debug-screenshot-1763401388589.png +0 -0
  184. package/mcp-server/AI_GUIDELINES.md +0 -57
  185. package/scripts/view-test-results.mjs +0 -96
  186. package/styles/.vale-config/2-MDX.ini +0 -5
  187. package/styles/Microsoft/AMPM.yml +0 -9
  188. package/styles/Microsoft/Accessibility.yml +0 -30
  189. package/styles/Microsoft/Acronyms.yml +0 -64
  190. package/styles/Microsoft/Adverbs.yml +0 -272
  191. package/styles/Microsoft/Auto.yml +0 -11
  192. package/styles/Microsoft/Avoid.yml +0 -14
  193. package/styles/Microsoft/Contractions.yml +0 -50
  194. package/styles/Microsoft/Dashes.yml +0 -13
  195. package/styles/Microsoft/DateFormat.yml +0 -8
  196. package/styles/Microsoft/DateNumbers.yml +0 -40
  197. package/styles/Microsoft/DateOrder.yml +0 -8
  198. package/styles/Microsoft/Ellipses.yml +0 -9
  199. package/styles/Microsoft/FirstPerson.yml +0 -16
  200. package/styles/Microsoft/Foreign.yml +0 -13
  201. package/styles/Microsoft/Gender.yml +0 -8
  202. package/styles/Microsoft/GenderBias.yml +0 -42
  203. package/styles/Microsoft/GeneralURL.yml +0 -11
  204. package/styles/Microsoft/HeadingAcronyms.yml +0 -7
  205. package/styles/Microsoft/HeadingColons.yml +0 -8
  206. package/styles/Microsoft/HeadingPunctuation.yml +0 -13
  207. package/styles/Microsoft/Headings.yml +0 -28
  208. package/styles/Microsoft/Hyphens.yml +0 -14
  209. package/styles/Microsoft/Negative.yml +0 -13
  210. package/styles/Microsoft/Ordinal.yml +0 -13
  211. package/styles/Microsoft/OxfordComma.yml +0 -8
  212. package/styles/Microsoft/Passive.yml +0 -183
  213. package/styles/Microsoft/Percentages.yml +0 -7
  214. package/styles/Microsoft/Plurals.yml +0 -7
  215. package/styles/Microsoft/Quotes.yml +0 -7
  216. package/styles/Microsoft/RangeTime.yml +0 -13
  217. package/styles/Microsoft/Semicolon.yml +0 -8
  218. package/styles/Microsoft/SentenceLength.yml +0 -6
  219. package/styles/Microsoft/Spacing.yml +0 -8
  220. package/styles/Microsoft/Suspended.yml +0 -7
  221. package/styles/Microsoft/Terms.yml +0 -42
  222. package/styles/Microsoft/URLFormat.yml +0 -9
  223. package/styles/Microsoft/Units.yml +0 -16
  224. package/styles/Microsoft/Vocab.yml +0 -25
  225. package/styles/Microsoft/We.yml +0 -11
  226. package/styles/Microsoft/Wordiness.yml +0 -127
  227. package/styles/Microsoft/meta.json +0 -4
  228. package/styles/alex/Ablist.yml +0 -274
  229. package/styles/alex/Condescending.yml +0 -16
  230. package/styles/alex/Gendered.yml +0 -110
  231. package/styles/alex/LGBTQ.yml +0 -55
  232. package/styles/alex/OCD.yml +0 -10
  233. package/styles/alex/Press.yml +0 -12
  234. package/styles/alex/ProfanityLikely.yml +0 -1289
  235. package/styles/alex/ProfanityMaybe.yml +0 -282
  236. package/styles/alex/ProfanityUnlikely.yml +0 -251
  237. package/styles/alex/README.md +0 -27
  238. package/styles/alex/Race.yml +0 -85
  239. package/styles/alex/Suicide.yml +0 -26
  240. package/styles/alex/meta.json +0 -4
  241. package/styles/config/vocabularies/Docs/accept.txt +0 -47
  242. package/styles/config/vocabularies/Docs/reject.txt +0 -4
  243. package/styles/proselint/Airlinese.yml +0 -8
  244. package/styles/proselint/AnimalLabels.yml +0 -48
  245. package/styles/proselint/Annotations.yml +0 -9
  246. package/styles/proselint/Apologizing.yml +0 -8
  247. package/styles/proselint/Archaisms.yml +0 -52
  248. package/styles/proselint/But.yml +0 -8
  249. package/styles/proselint/Cliches.yml +0 -782
  250. package/styles/proselint/CorporateSpeak.yml +0 -30
  251. package/styles/proselint/Currency.yml +0 -5
  252. package/styles/proselint/Cursing.yml +0 -15
  253. package/styles/proselint/DateCase.yml +0 -7
  254. package/styles/proselint/DateMidnight.yml +0 -7
  255. package/styles/proselint/DateRedundancy.yml +0 -10
  256. package/styles/proselint/DateSpacing.yml +0 -7
  257. package/styles/proselint/DenizenLabels.yml +0 -52
  258. package/styles/proselint/Diacritical.yml +0 -95
  259. package/styles/proselint/GenderBias.yml +0 -45
  260. package/styles/proselint/GroupTerms.yml +0 -39
  261. package/styles/proselint/Hedging.yml +0 -8
  262. package/styles/proselint/Hyperbole.yml +0 -6
  263. package/styles/proselint/Jargon.yml +0 -11
  264. package/styles/proselint/LGBTOffensive.yml +0 -13
  265. package/styles/proselint/LGBTTerms.yml +0 -15
  266. package/styles/proselint/Malapropisms.yml +0 -8
  267. package/styles/proselint/Needless.yml +0 -358
  268. package/styles/proselint/Nonwords.yml +0 -38
  269. package/styles/proselint/Oxymorons.yml +0 -22
  270. package/styles/proselint/P-Value.yml +0 -6
  271. package/styles/proselint/RASSyndrome.yml +0 -30
  272. package/styles/proselint/README.md +0 -12
  273. package/styles/proselint/Skunked.yml +0 -13
  274. package/styles/proselint/Spelling.yml +0 -17
  275. package/styles/proselint/Typography.yml +0 -11
  276. package/styles/proselint/Uncomparables.yml +0 -50
  277. package/styles/proselint/Very.yml +0 -6
  278. package/styles/proselint/meta.json +0 -15
  279. package/styles/write-good/Cliches.yml +0 -702
  280. package/styles/write-good/E-Prime.yml +0 -32
  281. package/styles/write-good/Illusions.yml +0 -11
  282. package/styles/write-good/Passive.yml +0 -183
  283. package/styles/write-good/README.md +0 -27
  284. package/styles/write-good/So.yml +0 -5
  285. package/styles/write-good/ThereIs.yml +0 -6
  286. package/styles/write-good/TooWordy.yml +0 -221
  287. package/styles/write-good/Weasel.yml +0 -29
  288. package/styles/write-good/meta.json +0 -4
  289. package/test/mcp-example-test.yaml +0 -27
  290. package/test/test_parser.js +0 -47
  291. package/testdriver/acceptance-sdk/QUICK_REFERENCE.md +0 -61
  292. package/testdriver/acceptance-sdk/README.md +0 -128
  293. package/testdriver/acceptance-sdk/TEST_REPORTING.md +0 -245
  294. package/testdriver/acceptance-sdk/assert.test.mjs +0 -44
  295. package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +0 -42
  296. package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
  297. package/testdriver/acceptance-sdk/type-checking-demo.js +0 -49
  298. package/testdriver/acceptance-sdk/type.test.mjs +0 -84
  299. package/vale.ini +0 -18
  300. package/vitest.config.example.js +0 -19
  301. package/vitest.config.mjs.bak +0 -44
  302. /package/docs/{ARCHITECTURE.md → v7/_drafts/architecture.mdx} +0 -0
  303. /package/docs/{AWESOME_LOGS_QUICK_REF.md → v7/_drafts/awesome-logs-quick-ref.mdx} +0 -0
  304. /package/{CONTRIBUTING.md → docs/v7/_drafts/contributing.mdx} +0 -0
  305. /package/docs/v7/{guides → _drafts}/migration.mdx +0 -0
  306. /package/{PLUGIN_MIGRATION.md → docs/v7/_drafts/plugin-migration.mdx} +0 -0
  307. /package/{PROMPT_CACHE.md → docs/v7/_drafts/prompt-cache.mdx} +0 -0
  308. /package/docs/{SDK_AWESOME_LOGS.md → v7/_drafts/sdk-awesome-logs.mdx} +0 -0
  309. /package/docs/{sdk-browser-rendering.md → v7/_drafts/sdk-browser-rendering.mdx} +0 -0
  310. /package/{SDK_LOGGING.md → docs/v7/_drafts/sdk-logging.mdx} +0 -0
  311. /package/{SDK_MIGRATION.md → docs/v7/_drafts/sdk-migration.mdx} +0 -0
  312. /package/docs/{TEST_RECORDING.md → v7/_drafts/test-recording.mdx} +0 -0
  313. /package/docs/v7/{README.md → overview/readme.mdx} +0 -0
  314. /package/{debug-locate-response.js → test/manual/debug-locate-response.js} +0 -0
  315. /package/{test-find-api.js → test/manual/test-find-api.js} +0 -0
  316. /package/{test-prompt-cache.js → test/manual/test-prompt-cache.js} +0 -0
  317. /package/{test-sandbox-render.js → test/manual/test-sandbox-render.js} +0 -0
  318. /package/{test-sdk-methods.js → test/manual/test-sdk-methods.js} +0 -0
  319. /package/{test-sdk-refactor.js → test/manual/test-sdk-refactor.js} +0 -0
  320. /package/{test-stack-trace.mjs → test/manual/test-stack-trace.mjs} +0 -0
  321. /package/{verify-element-api.js → test/manual/verify-element-api.js} +0 -0
  322. /package/{verify-types.js → test/manual/verify-types.js} +0 -0
  323. /package/{testdriver/acceptance-sdk → test/testdriver}/setup/globalTeardown.mjs +0 -0
  324. /package/{testdriver/acceptance-sdk → test/testdriver}/setup/vitestSetup.mjs +0 -0
@@ -0,0 +1,517 @@
1
+ ---
2
+ title: "Performance Optimization"
3
+ description: "Speed up your TestDriver tests"
4
+ icon: "gauge"
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ TestDriver tests run in cloud sandboxes, which adds latency. This guide shows you how to minimize overhead and maximize test speed.
10
+
11
+ ## Baseline Performance
12
+
13
+ Typical test execution:
14
+
15
+ | Phase | Time | What's Happening |
16
+ |-------|------|------------------|
17
+ | Sandbox startup | 20-60s | First test creates VM |
18
+ | Sandbox reuse | 0s | Subsequent tests reuse VM |
19
+ | Page load | 1-5s | Browser navigates to URL |
20
+ | Element finding | 0.5-3s | AI locates element |
21
+ | Element finding (cached) | 0.1-0.5s | Cache hit |
22
+ | Command execution | 0.1-1s | Click, type, etc. |
23
+ | AI command | 2-5s | Natural language parsing |
24
+ | AI command (cached) | 0.1-0.5s | Cache hit |
25
+
26
+ **First test**: 60-90s
27
+ **Subsequent tests**: 5-30s
28
+ **Optimized tests**: 2-10s
29
+
30
+ ## Optimization Strategies
31
+
32
+ ### 1. Reuse Sandboxes
33
+
34
+ The biggest performance win is reusing sandboxes across tests.
35
+
36
+ #### ❌ Slow - Create new sandbox per test
37
+
38
+ ```javascript
39
+ test('test 1', async () => {
40
+ const testdriver = await TestDriver.create({
41
+ apiKey: process.env.TD_API_KEY
42
+ });
43
+ // Test logic
44
+ await testdriver.cleanup();
45
+ });
46
+
47
+ test('test 2', async () => {
48
+ const testdriver = await TestDriver.create({
49
+ apiKey: process.env.TD_API_KEY
50
+ });
51
+ // Test logic
52
+ await testdriver.cleanup();
53
+ });
54
+ ```
55
+
56
+ **Time**: 60s + 60s = 120s
57
+
58
+ #### ✅ Fast - Reuse sandbox with context
59
+
60
+ ```javascript
61
+ import { chrome } from '../setup/lifecycleHelpers.mjs';
62
+
63
+ test('test 1', async (context) => {
64
+ const { testdriver } = await chrome(context, { url: 'https://app.com' });
65
+ // Test logic
66
+ });
67
+
68
+ test('test 2', async (context) => {
69
+ const { testdriver } = await chrome(context, { url: 'https://app.com' });
70
+ // Test logic
71
+ });
72
+ ```
73
+
74
+ **Time**: 60s + 5s = 65s (54% faster)
75
+
76
+ ### 2. Enable Caching
77
+
78
+ TestDriver has two cache layers:
79
+
80
+ #### AI Prompt Cache
81
+
82
+ Caches AI-generated commands locally:
83
+
84
+ ```yaml
85
+ # testdriver.yaml
86
+ cache:
87
+ ai: true # Enable prompt caching
88
+ ```
89
+
90
+ **Impact**: 2-5s → 0.1-0.5s per AI command
91
+
92
+ #### Selector Cache
93
+
94
+ Caches element locations on server:
95
+
96
+ ```yaml
97
+ # testdriver.yaml
98
+ cache:
99
+ selectors: true
100
+ selectorThreshold: 0.95 # 95% similarity required
101
+ ```
102
+
103
+ **Impact**: 0.5-3s → 0.1-0.5s per element find
104
+
105
+ **Combined**: Tests run 3-5x faster on subsequent runs.
106
+
107
+ ### 3. Parallel Test Execution
108
+
109
+ Run multiple tests simultaneously:
110
+
111
+ ```javascript
112
+ // vitest.config.mjs
113
+ export default defineConfig({
114
+ test: {
115
+ maxConcurrency: 5, // Run 5 tests at once
116
+ fileParallelism: true
117
+ }
118
+ });
119
+ ```
120
+
121
+ **Impact**: 5 tests in 300s → 5 tests in 90s (70% faster)
122
+
123
+ **Tradeoffs**:
124
+ - Uses more test minutes
125
+ - May hit API rate limits
126
+ - Requires adequate plan limits
127
+
128
+ ### 4. Reduce AI Commands
129
+
130
+ AI commands are slower than direct commands.
131
+
132
+ #### ❌ Slow - AI for everything
133
+
134
+ ```javascript
135
+ await testdriver.ai('click the login button');
136
+ await testdriver.ai('type email@example.com');
137
+ await testdriver.ai('type mypassword');
138
+ await testdriver.ai('press enter');
139
+ ```
140
+
141
+ **Time**: ~15s
142
+
143
+ #### ✅ Fast - AI only for finding
144
+
145
+ ```javascript
146
+ await testdriver.find('email field').then(el => el.click());
147
+ await testdriver.type('email@example.com');
148
+
149
+ await testdriver.find('password field').then(el => el.click());
150
+ await testdriver.type('mypassword');
151
+
152
+ await testdriver.find('login button').then(el => el.click());
153
+ ```
154
+
155
+ **Time**: ~5s (66% faster)
156
+
157
+ ### 5. Batch Operations
158
+
159
+ Minimize round trips to sandbox:
160
+
161
+ #### ❌ Slow - Sequential operations
162
+
163
+ ```javascript
164
+ await testdriver.find('first name').then(el => el.click());
165
+ await testdriver.type('John');
166
+
167
+ await testdriver.find('last name').then(el => el.click());
168
+ await testdriver.type('Doe');
169
+
170
+ await testdriver.find('email').then(el => el.click());
171
+ await testdriver.type('john@example.com');
172
+ ```
173
+
174
+ **Time**: 6 round trips
175
+
176
+ #### ✅ Fast - Batch with keyboard navigation
177
+
178
+ ```javascript
179
+ await testdriver.find('first name').then(el => el.click());
180
+ await testdriver.type('John');
181
+
182
+ await testdriver.pressKeys(['tab']);
183
+ await testdriver.type('Doe');
184
+
185
+ await testdriver.pressKeys(['tab']);
186
+ await testdriver.type('john@example.com');
187
+ ```
188
+
189
+ **Time**: 4 round trips (33% faster)
190
+
191
+ ### 6. Smart Waiting
192
+
193
+ Avoid unnecessary delays:
194
+
195
+ #### ❌ Slow - Fixed delays
196
+
197
+ ```javascript
198
+ await testdriver.find('button').then(el => el.click());
199
+ await new Promise(r => setTimeout(r, 5000)); // Always wait 5s
200
+ await testdriver.find('success message');
201
+ ```
202
+
203
+ #### ✅ Fast - Poll until found
204
+
205
+ ```javascript
206
+ await testdriver.find('button').then(el => el.click());
207
+
208
+ // Poll for success message
209
+ let element;
210
+ for (let i = 0; i < 30; i++) {
211
+ element = await testdriver.find('success message');
212
+ if (element.found()) break;
213
+ await new Promise(r => setTimeout(r, 500));
214
+ }
215
+ ```
216
+
217
+ #### ✅ Better - Use assertions
218
+
219
+ ```javascript
220
+ await testdriver.find('button').then(el => el.click());
221
+ await testdriver.assert('success message appeared'); // Waits intelligently
222
+ ```
223
+
224
+ ### 7. Optimize Element Descriptions
225
+
226
+ More specific = faster finding:
227
+
228
+ #### ❌ Slow - Vague description
229
+
230
+ ```javascript
231
+ await testdriver.find('button'); // Many buttons to check
232
+ ```
233
+
234
+ **Time**: 2-3s (checks all buttons)
235
+
236
+ #### ✅ Fast - Specific description
237
+
238
+ ```javascript
239
+ await testdriver.find('blue submit button at bottom right');
240
+ ```
241
+
242
+ **Time**: 0.5-1s (narrows search area)
243
+
244
+ ### 8. Preload Resources
245
+
246
+ Speed up page load:
247
+
248
+ #### ❌ Slow - Load on demand
249
+
250
+ ```javascript
251
+ test('test 1', async (context) => {
252
+ const { testdriver } = await chrome(context, { url: 'https://app.com' });
253
+ // First test loads everything
254
+ });
255
+ ```
256
+
257
+ #### ✅ Fast - Preload in beforeAll
258
+
259
+ ```javascript
260
+ import { beforeAll, test } from 'vitest';
261
+
262
+ beforeAll(async (context) => {
263
+ const { testdriver } = await chrome(context, { url: 'https://app.com' });
264
+ // Preload app, login, navigate to test area
265
+ await testdriver.find('email').then(el => el.click());
266
+ await testdriver.type(process.env.TEST_EMAIL);
267
+ await testdriver.find('password').then(el => el.click());
268
+ await testdriver.type(process.env.TEST_PASSWORD);
269
+ await testdriver.find('login').then(el => el.click());
270
+ }, 120000);
271
+ ```
272
+
273
+ ### 9. Clean Cache Strategically
274
+
275
+ Don't clear cache unnecessarily:
276
+
277
+ #### ❌ Slow - Clear cache every run
278
+
279
+ ```bash
280
+ # package.json
281
+ {
282
+ "scripts": {
283
+ "test": "rm -rf .testdriver/.cache && vitest"
284
+ }
285
+ }
286
+ ```
287
+
288
+ #### ✅ Fast - Clear cache when needed
289
+
290
+ ```bash
291
+ # Only clear when UI changes
292
+ npm run test:clean # Separate script
293
+
294
+ # Normal runs use cache
295
+ npm test
296
+ ```
297
+
298
+ ### 10. Monitor Performance
299
+
300
+ Track test execution time:
301
+
302
+ ```javascript
303
+ import { test } from 'vitest';
304
+
305
+ test('slow test detector', async (context) => {
306
+ const start = Date.now();
307
+
308
+ // Test logic
309
+ const { testdriver } = await chrome(context, { url });
310
+ await testdriver.find('button').then(el => el.click());
311
+
312
+ const duration = Date.now() - start;
313
+ console.log(`Test took ${duration}ms`);
314
+
315
+ if (duration > 30000) {
316
+ console.warn('⚠️ Test exceeded 30s threshold');
317
+ }
318
+ });
319
+ ```
320
+
321
+ ## Configuration Tuning
322
+
323
+ ### Timeout Settings
324
+
325
+ Balance reliability vs speed:
326
+
327
+ ```javascript
328
+ // vitest.config.mjs
329
+ export default defineConfig({
330
+ test: {
331
+ testTimeout: 60000, // Default: 60s
332
+ hookTimeout: 30000 // Setup/teardown: 30s
333
+ }
334
+ });
335
+ ```
336
+
337
+ For fast, stable tests:
338
+ ```javascript
339
+ testTimeout: 30000 // 30s
340
+ ```
341
+
342
+ For slower, complex tests:
343
+ ```javascript
344
+ testTimeout: 120000 // 2 minutes
345
+ ```
346
+
347
+ ### Verbosity Level
348
+
349
+ Lower verbosity = less overhead:
350
+
351
+ ```javascript
352
+ const testdriver = await TestDriver.create({
353
+ apiKey: process.env.TD_API_KEY,
354
+ verbosity: 0 // 0=silent, 1=normal, 2=debug
355
+ });
356
+ ```
357
+
358
+ **Impact**: Small (~100ms per test), but adds up.
359
+
360
+ ### Resolution
361
+
362
+ Lower resolution = faster screenshots:
363
+
364
+ ```javascript
365
+ const testdriver = await TestDriver.create({
366
+ apiKey: process.env.TD_API_KEY,
367
+ resolution: '1280x720' // Default: 1920x1080
368
+ });
369
+ ```
370
+
371
+ **Impact**: 10-20% faster element finding.
372
+
373
+ ## Advanced Techniques
374
+
375
+ ### Connection Pooling
376
+
377
+ Reuse connections across test suites:
378
+
379
+ ```javascript
380
+ // setup/pool.mjs
381
+ const clients = new Map();
382
+
383
+ export async function getClient(context) {
384
+ const key = `${context.task.file.name}`;
385
+
386
+ if (!clients.has(key)) {
387
+ clients.set(key, await TestDriver.create({
388
+ apiKey: process.env.TD_API_KEY
389
+ }));
390
+ }
391
+
392
+ return clients.get(key);
393
+ }
394
+
395
+ export async function cleanup() {
396
+ for (const client of clients.values()) {
397
+ await client.cleanup();
398
+ }
399
+ clients.clear();
400
+ }
401
+ ```
402
+
403
+ ### Lazy Loading
404
+
405
+ Only load what you need:
406
+
407
+ ```javascript
408
+ // ❌ Load everything upfront
409
+ import { chrome, firefox, electron } from './setup/lifecycleHelpers.mjs';
410
+
411
+ // ✅ Import only what you use
412
+ import { chrome } from './setup/lifecycleHelpers.mjs';
413
+ ```
414
+
415
+ ### Snapshot Testing
416
+
417
+ Compare screenshots instead of re-running:
418
+
419
+ ```javascript
420
+ test('visual regression', async (context) => {
421
+ const { testdriver } = await chrome(context, { url });
422
+
423
+ const element = await testdriver.find('hero section');
424
+
425
+ // First run: saves screenshot
426
+ // Subsequent runs: compares screenshot
427
+ expect(element.screenshot).toMatchImageSnapshot();
428
+ });
429
+ ```
430
+
431
+ ## Profiling
432
+
433
+ ### Find Slow Tests
434
+
435
+ ```bash
436
+ # Run with timing report
437
+ npm test -- --reporter=verbose
438
+
439
+ # Output shows duration per test
440
+ ✓ fast test (1.2s)
441
+ ✓ medium test (5.4s)
442
+ ✗ slow test (45.2s)
443
+ ```
444
+
445
+ ### Measure Operations
446
+
447
+ ```javascript
448
+ async function timedOperation(name, fn) {
449
+ const start = Date.now();
450
+ const result = await fn();
451
+ console.log(`${name}: ${Date.now() - start}ms`);
452
+ return result;
453
+ }
454
+
455
+ test('profiled test', async (context) => {
456
+ const { testdriver } = await timedOperation('Setup', async () => {
457
+ return await chrome(context, { url });
458
+ });
459
+
460
+ await timedOperation('Find button', async () => {
461
+ return await testdriver.find('button');
462
+ });
463
+
464
+ await timedOperation('Click button', async () => {
465
+ const el = await testdriver.find('button');
466
+ return await el.click();
467
+ });
468
+ });
469
+ ```
470
+
471
+ ### Identify Bottlenecks
472
+
473
+ Common slow operations:
474
+
475
+ 1. **Sandbox creation** (20-60s) - Reuse sandboxes
476
+ 2. **Page navigation** (1-5s) - Minimize navigation
477
+ 3. **AI commands** (2-5s) - Use direct commands
478
+ 4. **Element finding** (0.5-3s) - Enable caching
479
+ 5. **Fixed delays** (varies) - Replace with smart waiting
480
+
481
+ ## Production Checklist
482
+
483
+ - [ ] Reuse sandboxes via context
484
+ - [ ] Enable AI and selector caching
485
+ - [ ] Use parallel execution (maxConcurrency: 5)
486
+ - [ ] Minimize AI commands
487
+ - [ ] Batch operations
488
+ - [ ] Use smart waiting (assertions)
489
+ - [ ] Specific element descriptions
490
+ - [ ] Appropriate timeout settings
491
+ - [ ] Monitor test duration
492
+ - [ ] Profile slow tests
493
+
494
+ Expected performance:
495
+ - **First run**: 60-90s for suite
496
+ - **Cached runs**: 10-30s for suite
497
+ - **Per test**: 2-10s (cached)
498
+
499
+ ## See Also
500
+
501
+ <CardGroup cols={2}>
502
+ <Card title="Caching (AI)" icon="brain" href="/v7/guides/caching-ai">
503
+ AI prompt caching
504
+ </Card>
505
+
506
+ <Card title="Caching (Selectors)" icon="bullseye" href="/v7/guides/caching-selectors">
507
+ Selector caching
508
+ </Card>
509
+
510
+ <Card title="Best Practices" icon="star" href="/v7/guides/best-practices">
511
+ Testing patterns
512
+ </Card>
513
+
514
+ <Card title="CI/CD Integration" icon="arrows-spin" href="/v7/guides/ci-cd">
515
+ Optimize CI pipelines
516
+ </Card>
517
+ </CardGroup>
@@ -0,0 +1,210 @@
1
+ # TestDriver Presets
2
+
3
+ Presets provide pre-configured setups for common applications, reducing boilerplate and making your tests easier to write.
4
+
5
+ ## Available Presets
6
+
7
+ ### chromePreset
8
+
9
+ Automatically sets up Chrome browser with TestDriver and Dashcam.
10
+
11
+ ```javascript
12
+ import { test } from 'vitest';
13
+ import { chromePreset } from 'testdriverai/presets';
14
+
15
+ test('my test', async (context) => {
16
+ const { client } = await chromePreset(context, {
17
+ url: 'https://myapp.com/login'
18
+ });
19
+
20
+ await client.find('email input').type('user@example.com');
21
+ await client.find('Login button').click();
22
+ });
23
+ ```
24
+
25
+ **Options:**
26
+ - `url` - URL to navigate to (default: 'http://testdriver-sandbox.vercel.app/')
27
+ - `os` - Target OS: 'linux', 'mac', 'windows' (default: 'linux')
28
+ - `dashcam` - Enable Dashcam recording (default: true)
29
+ - `maximized` - Start maximized (default: true)
30
+ - `guest` - Use guest mode (default: true)
31
+
32
+ **Returns:**
33
+ - `client` - TestDriver instance
34
+ - `dashcam` - Dashcam instance (if enabled)
35
+
36
+ ### vscodePreset
37
+
38
+ Automatically sets up VS Code with TestDriver and Dashcam.
39
+
40
+ ```javascript
41
+ import { vscodePreset } from 'testdriverai/presets';
42
+
43
+ test('extension test', async (context) => {
44
+ const { vscode } = await vscodePreset(context, {
45
+ workspace: '/tmp/test-project',
46
+ extensions: ['ms-python.python']
47
+ });
48
+
49
+ await vscode.find('File menu').click();
50
+ await vscode.find('New File').click();
51
+ });
52
+ ```
53
+
54
+ **Options:**
55
+ - `workspace` - Workspace/folder to open
56
+ - `os` - Target OS (default: 'linux')
57
+ - `dashcam` - Enable Dashcam recording (default: true)
58
+ - `extensions` - Array of extension IDs to install
59
+
60
+ **Returns:**
61
+ - `client` - TestDriver instance
62
+ - `vscode` - Alias for client
63
+ - `dashcam` - Dashcam instance (if enabled)
64
+
65
+ ### electronPreset
66
+
67
+ Automatically sets up an Electron application.
68
+
69
+ ```javascript
70
+ import { electronPreset } from 'testdriverai/presets';
71
+
72
+ test('electron app test', async (context) => {
73
+ const { app } = await electronPreset(context, {
74
+ appPath: '/path/to/electron/app',
75
+ args: ['--enable-logging']
76
+ });
77
+
78
+ await app.find('main window').click();
79
+ });
80
+ ```
81
+
82
+ **Options:**
83
+ - `appPath` - Path to Electron app (required)
84
+ - `os` - Target OS (default: 'linux')
85
+ - `dashcam` - Enable Dashcam recording (default: true)
86
+ - `args` - Additional electron arguments
87
+
88
+ **Returns:**
89
+ - `client` - TestDriver instance
90
+ - `app` - Alias for client
91
+ - `dashcam` - Dashcam instance (if enabled)
92
+
93
+ ### webAppPreset
94
+
95
+ Generic web application preset (currently uses Chrome).
96
+
97
+ ```javascript
98
+ import { webAppPreset } from 'testdriverai/presets';
99
+
100
+ test('web app test', async (context) => {
101
+ const { client } = await webAppPreset(context, {
102
+ url: 'https://example.com',
103
+ browser: 'chrome' // Only Chrome supported currently
104
+ });
105
+
106
+ await client.find('login form').click();
107
+ });
108
+ ```
109
+
110
+ ## Creating Custom Presets
111
+
112
+ Use `createPreset` to build your own presets:
113
+
114
+ ```javascript
115
+ import { createPreset } from 'testdriverai/presets';
116
+
117
+ const firefoxPreset = createPreset({
118
+ name: 'Firefox Browser',
119
+ defaults: { os: 'linux', dashcam: true },
120
+ async setup(context, client, dashcam, options) {
121
+ const { url } = options;
122
+
123
+ // Launch Firefox
124
+ await client.exec('sh', `firefox "${url}" >/dev/null 2>&1 &`, 30000);
125
+ await client.focusApplication('Firefox');
126
+
127
+ return {
128
+ // client is already included automatically
129
+ };
130
+ },
131
+ });
132
+
133
+ // Use your custom preset
134
+ test('my test', async (context) => {
135
+ const { client } = await firefoxPreset(context, {
136
+ url: 'https://example.com',
137
+ });
138
+
139
+ await client.find('page content').click();
140
+ });
141
+ ```
142
+
143
+ ### createPreset API
144
+
145
+ ```javascript
146
+ createPreset({
147
+ name: string, // Preset name (for errors)
148
+ defaults: object, // Default options
149
+ setup: async function // Setup function
150
+ })
151
+ ```
152
+
153
+ The `setup` function receives:
154
+ - `context` - Vitest test context
155
+ - `client` - TestDriver instance (already connected)
156
+ - `dashcam` - Dashcam instance (if enabled)
157
+ - `options` - Merged defaults + user options
158
+
159
+ The `setup` function should return an object with any custom properties. The returned object will automatically include `client` and `dashcam`.
160
+
161
+ ## How Presets Work
162
+
163
+ Presets automatically:
164
+
165
+ 1. **Create TestDriver client** - Uses `useTestDriver` hook
166
+ 2. **Connect to sandbox** - Authenticates and connects
167
+ 3. **Set up Dashcam** - If enabled (default: true)
168
+ 4. **Configure application** - Launch and focus the app
169
+ 5. **Handle cleanup** - Automatic disconnect and dashcam stop
170
+
171
+ All lifecycle is managed automatically via Vitest hooks.
172
+
173
+ ## Progressive Disclosure
174
+
175
+ Presets fit into the progressive disclosure pattern:
176
+
177
+ ### Beginner (Presets)
178
+ ```javascript
179
+ const { client } = await chromePreset(context, { url: 'https://example.com' });
180
+ ```
181
+ Everything automatic - just pass URL and start testing.
182
+
183
+ ### Intermediate (Hooks)
184
+ ```javascript
185
+ const client = useTestDriver(context, { os: 'linux' });
186
+ const dashcam = useDashcam(context, client, { autoStart: true });
187
+ // Custom setup code
188
+ ```
189
+ More control over lifecycle, still automatic cleanup.
190
+
191
+ ### Advanced (Direct)
192
+ ```javascript
193
+ const client = new TestDriver(apiKey, { os: 'linux' });
194
+ await client.auth();
195
+ await client.connect();
196
+ // Full manual control
197
+ ```
198
+ Complete control, manual everything.
199
+
200
+ ## Best Practices
201
+
202
+ 1. **Use presets for common scenarios** - Chrome, VS Code, Electron
203
+ 2. **Create custom presets for your apps** - Encapsulate setup logic
204
+ 3. **Enable dashcam by default** - Great for debugging failures
205
+ 4. **Keep presets focused** - One app/scenario per preset
206
+ 5. **Use descriptive variable names** - `client`, `vscode`, `app` based on what you're testing
207
+
208
+ ## Examples
209
+
210
+ See `testdriver/acceptance-sdk/presets-example.test.mjs` for working examples.