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,215 @@
1
+ ---
2
+ title: "AI Prompt Caching"
3
+ sidebarTitle: "AI Caching"
4
+ description: "How TestDriver caches AI-generated YAML commands for faster tests"
5
+ icon: "bolt"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ The Prompt Cache stores AI-generated YAML commands locally, so repeated `.ai()` calls with the same prompt skip the AI entirely.
11
+
12
+ This provides:
13
+ - ⚡ **Instant execution** - No AI call needed
14
+ - 💰 **Cost savings** - Reduces API usage
15
+ - 🔌 **Offline testing** - Works without network
16
+ - 🎯 **Deterministic** - Same prompt = same commands
17
+
18
+ ## How It Works
19
+
20
+ <Steps>
21
+ <Step title="First Call">
22
+ ```javascript
23
+ await testdriver.ai('click the submit button');
24
+ ```
25
+
26
+ - Sends prompt + screenshot to AI
27
+ - Receives YAML commands
28
+ - Saves to `.testdriver/.cache/{prompt-hash}.yaml`
29
+ </Step>
30
+
31
+ <Step title="Subsequent Calls">
32
+ ```javascript
33
+ await testdriver.ai('click the submit button');
34
+ ```
35
+
36
+ - Checks cache first
37
+ - Finds matching cached YAML
38
+ - Uses cached commands (no AI call)
39
+ - Shows `(using cached response)` in output
40
+ </Step>
41
+ </Steps>
42
+
43
+ ## Cache Location
44
+
45
+ Cached prompts are stored locally in your project:
46
+
47
+ ```
48
+ .testdriver/
49
+ .cache/
50
+ click-the-submit-button-a1b2c3d4.yaml
51
+ find-login-form-e5f6a7b8.yaml
52
+ verify-dashboard-c9d0e1f2.yaml
53
+ ```
54
+
55
+ Files are named using:
56
+ - Sanitized prompt (first 50 chars, alphanumeric)
57
+ - MD5 hash of full prompt for uniqueness
58
+
59
+ ## Cache Matching
60
+
61
+ The prompt cache uses **exact text matching**:
62
+ - Case-insensitive comparison
63
+ - Whitespace trimmed
64
+ - No screenshot comparison
65
+
66
+ ```javascript
67
+ // These all match the same cache entry:
68
+ await testdriver.ai('click the submit button');
69
+ await testdriver.ai('CLICK THE SUBMIT BUTTON');
70
+ await testdriver.ai(' click the submit button ');
71
+
72
+ // This creates a new cache entry:
73
+ await testdriver.ai('click the submit btn'); // Different text
74
+ ```
75
+
76
+ ## Disabling Prompt Cache
77
+
78
+ Bypass the cache for a specific call:
79
+
80
+ ```javascript
81
+ // Force fresh AI call, bypass cache
82
+ await testdriver.ai('click the submit button', false);
83
+
84
+ // These use cache (default)
85
+ await testdriver.ai('click the submit button');
86
+ await testdriver.ai('click the submit button', true);
87
+ ```
88
+
89
+ ## Clearing Prompt Cache
90
+
91
+ Clear all cached prompts:
92
+
93
+ ```bash
94
+ rm -rf .testdriver/.cache/*.yaml
95
+ ```
96
+
97
+ Or programmatically:
98
+
99
+ ```javascript
100
+ const promptCache = require('testdriverai/agent/lib/cache.js');
101
+ promptCache.clearCache();
102
+ ```
103
+
104
+ ## Usage Examples
105
+
106
+ ### Basic Caching
107
+
108
+ ```javascript
109
+ import { test } from 'vitest';
110
+ import { chrome } from 'testdriverai/presets';
111
+
112
+ test('login flow', async (context) => {
113
+ const { testdriver } = await chrome(context, {
114
+ url: 'https://myapp.com/login'
115
+ });
116
+
117
+ // First call: AI generates commands, saves to cache
118
+ await testdriver.ai('click the login button');
119
+
120
+ // Run test again - uses cache (instant)
121
+ // Look for: "(using cached response)" in output
122
+ });
123
+ ```
124
+
125
+ ### Bypassing Cache
126
+
127
+ ```javascript
128
+ test('always fresh', async (context) => {
129
+ const { testdriver } = await chrome(context, { url });
130
+
131
+ // Always get fresh AI response
132
+ await testdriver.ai('analyze the current state', false);
133
+ });
134
+ ```
135
+
136
+ ## Best Practices
137
+
138
+ ### 1. Use Consistent Prompts
139
+
140
+ ```javascript
141
+ // ✅ Good - consistent prompt
142
+ await testdriver.ai('fill out the login form');
143
+ await testdriver.ai('fill out the login form'); // Cache hit
144
+
145
+ // ❌ Bad - different prompts
146
+ await testdriver.ai('fill out the login form');
147
+ await testdriver.ai('complete the login form'); // Cache miss
148
+ ```
149
+
150
+ ### 2. Clear Cache When Test Logic Changes
151
+
152
+ If you update your test prompts, clear the cache:
153
+
154
+ ```bash
155
+ rm -rf .testdriver/.cache/*.yaml
156
+ ```
157
+
158
+ ### 3. Don't Commit Cache to Git
159
+
160
+ Add to `.gitignore`:
161
+
162
+ ```gitignore
163
+ .testdriver/.cache/
164
+ ```
165
+
166
+ ### 4. Version Control Consideration
167
+
168
+ While you _can_ commit cached prompts for team consistency, it's generally not recommended because:
169
+ - AI responses may improve over time
170
+ - Different team members may need different cached results
171
+ - Cache files can become stale
172
+
173
+ ## Cache Storage Details
174
+
175
+ | Property | Value |
176
+ |----------|-------|
177
+ | Location | Local (`.testdriver/.cache/`) |
178
+ | Persistence | Until manually cleared |
179
+ | Scope | Per-project |
180
+ | Matching | Exact prompt text (case-insensitive) |
181
+ | Expiration | Never |
182
+
183
+ ## Troubleshooting
184
+
185
+ ### Cache Not Working
186
+
187
+ Check:
188
+ 1. Prompts match exactly (case-insensitive)
189
+ 2. `.testdriver/.cache/` directory exists and is writable
190
+ 3. `TD_NO_PROMPT_CACHE` environment variable is not set
191
+
192
+ ### Stale Cache Data
193
+
194
+ If AI responses seem outdated:
195
+
196
+ ```bash
197
+ # Clear all cached prompts
198
+ rm -rf .testdriver/.cache/*.yaml
199
+ ```
200
+
201
+ Or clear specific prompts:
202
+
203
+ ```bash
204
+ # Find cache files
205
+ ls -la .testdriver/.cache/
206
+
207
+ # Delete specific cache file
208
+ rm .testdriver/.cache/click-the-submit-button-*.yaml
209
+ ```
210
+
211
+ ## See Also
212
+
213
+ - [Selector Caching](/v7/guides/caching-selectors) - Cache element locations
214
+ - [`.ai()` Method](/v7/api/ai) - AI command generation
215
+ - [Vitest Integration](/v7/guides/vitest) - Testing with TestDriver
@@ -0,0 +1,400 @@
1
+ ---
2
+ title: "Selector Caching"
3
+ sidebarTitle: "Selector Caching"
4
+ description: "How TestDriver caches element locations for faster tests"
5
+ icon: "crosshairs"
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ The Selector Cache stores element locations on the server, so `.find()` calls can skip the AI vision analysis.
11
+
12
+ **Important:** Selector caching is **disabled by default** as of v7.1. You must provide a `cacheKey` to enable caching.
13
+
14
+ This provides:
15
+ - ⚡ **Up to 10x faster** - Skip AI vision analysis
16
+ - 💰 **Lower AI costs** - Fewer vision API calls
17
+ - 🎯 **Consistent results** - Same UI = same coordinates
18
+ - 📊 **Metrics tracking** - See cache hit rates in console
19
+
20
+ ## Enabling the Cache
21
+
22
+ ### Auto-Generated Cache Keys (Recommended)
23
+
24
+ TestDriver automatically generates cache keys based on your test file:
25
+
26
+ ```javascript
27
+ // Cache automatically enabled - uses file hash as cache key
28
+ const button = await testdriver.find('submit button');
29
+ // Cache key: "a1b2c3d4e5f6..." (first 16 chars of file SHA-256)
30
+ ```
31
+
32
+ **Benefits:**
33
+ - ✅ **Per-file isolation** - Each test file has its own cache
34
+ - ✅ **Auto-invalidation** - Cache updates when test code changes
35
+ - ✅ **Zero configuration** - Works out of the box
36
+ - ✅ **Safe** - No cross-test pollution
37
+
38
+ ### Custom Cache Keys
39
+
40
+ Provide your own cache key for more control:
41
+
42
+ ```javascript
43
+ // Custom cache key
44
+ const button = await testdriver.find('submit button', {
45
+ cacheKey: 'my-test-key'
46
+ });
47
+
48
+ // Share cache across tests
49
+ const button = await testdriver.find('submit button', {
50
+ cacheKey: 'shared-submit-button'
51
+ });
52
+ ```
53
+
54
+ ### Global Cache Key
55
+
56
+ Enable caching for all finds in your test:
57
+
58
+ ```javascript
59
+ const client = new TestDriver(apiKey, {
60
+ cacheKey: 'my-global-key' // All finds will use this cache
61
+ });
62
+
63
+ // Now all finds are cached
64
+ await testdriver.find('button 1'); // Uses 'my-global-key'
65
+ await testdriver.find('button 2'); // Uses 'my-global-key'
66
+ ```
67
+
68
+ ### Disable Auto-Cache
69
+
70
+ If you don't want automatic caching:
71
+
72
+ ```javascript
73
+ // Disable cache for this find
74
+ await testdriver.find('button', { cacheThreshold: -1 });
75
+
76
+ // Or use a threshold of -1 globally
77
+ const client = new TestDriver(apiKey, {
78
+ cacheThreshold: { find: -1, findAll: -1 }
79
+ });
80
+ ```
81
+
82
+ ## How It Works
83
+
84
+ ```mermaid
85
+ sequenceDiagram
86
+ participant Test as Your Test
87
+ participant SDK as TestDriver SDK
88
+ participant API as TestDriver API
89
+ participant AI as Claude Vision
90
+ participant Cache as Selector Cache DB
91
+
92
+ Test->>SDK: testdriver.find('submit button')
93
+ SDK->>API: POST /locate (screenshot + prompt)
94
+
95
+ API->>Cache: Check for matching cache entry
96
+
97
+ alt Cache Hit (95%+ similar screenshot)
98
+ Cache-->>API: Return cached coordinates
99
+ API-->>SDK: {x, y, cacheHit: true}
100
+ SDK-->>Test: Element found (instant)
101
+ else Cache Miss
102
+ API->>AI: Analyze screenshot
103
+ AI-->>API: Element coordinates
104
+ API->>Cache: Save new cache entry
105
+ API-->>SDK: {x, y, cacheHit: false}
106
+ SDK-->>Test: Element found
107
+ end
108
+ ```
109
+
110
+ ## Cache Matching Strategy
111
+
112
+ The selector cache uses a three-tier matching system:
113
+
114
+ 1. **Exact Hash Match** (Fastest)
115
+ - Perceptual hash comparison
116
+ - Same screenshot = instant match
117
+ - 0% difference threshold
118
+
119
+ 2. **Pixel Diff Match** (Fast)
120
+ - 80%+ perceptual hash similarity
121
+ - Pixel-by-pixel comparison
122
+ - Default 5% difference threshold (95% similarity)
123
+ - Configurable per call
124
+
125
+ 3. **Template Match** (Fallback)
126
+ - Edge detection + template matching
127
+ - Finds visually similar UI elements
128
+ - 75%+ confidence threshold
129
+
130
+ ## Controlling Cache Threshold
131
+
132
+ Adjust similarity threshold when cache is enabled:
133
+
134
+ ```javascript
135
+ // Default: 95% similarity (5% difference allowed)
136
+ await testdriver.find('submit button', { cacheKey: 'test-1' });
137
+
138
+ // Stricter: 99% similarity (1% difference allowed)
139
+ await testdriver.find('submit button', {
140
+ cacheKey: 'test-1',
141
+ cacheThreshold: 0.01
142
+ });
143
+
144
+ // More lenient: 90% similarity (10% difference allowed)
145
+ await testdriver.find('submit button', {
146
+ cacheKey: 'test-1',
147
+ cacheThreshold: 0.10
148
+ });
149
+
150
+ // Disable cache: force fresh AI analysis
151
+ await testdriver.find('submit button', { cacheThreshold: -1 });
152
+ ```
153
+
154
+ <Note>
155
+ `cacheThreshold` only works when caching is enabled via `cacheKey` or global config.
156
+ </Note>
157
+
158
+ ## Cache Filtering
159
+
160
+ The selector cache automatically filters by:
161
+
162
+ - **Prompt** - Exact text match (case-insensitive)
163
+ - **Team** - Your team ID
164
+ - **OS** - Operating system (if specified)
165
+ - **Resolution** - Screen resolution (if specified)
166
+ - **Time Window** - Last 7 days by default
167
+
168
+ ## Viewing Cache Entries
169
+
170
+ View all cached selectors at [console.testdriver.ai](https://console.testdriver.ai)
171
+
172
+ The console shows:
173
+ - Cached screenshots with green circles on found elements
174
+ - Original prompts
175
+ - Hit count (how many times cache was used)
176
+ - Similarity scores
177
+ - Cache age and last accessed time
178
+
179
+ ## Cache Statistics
180
+
181
+ Each cache entry tracks:
182
+
183
+ - **Hit Count** - Number of times cache was used
184
+ - **Last Hit** - When cache was last accessed
185
+ - **Similarity** - Percentage match to original
186
+ - **Created At** - When entry was created
187
+ - **Element Type** - button, input, link, etc.
188
+ - **Element Bounds** - Bounding box coordinates
189
+
190
+ ## Usage Examples
191
+
192
+ ### Basic Selector Caching
193
+
194
+ ```javascript
195
+ import { test } from 'vitest';
196
+ import { chrome } from 'testdriverai/presets';
197
+
198
+ test('find element', async (context) => {
199
+ const { testdriver } = await chrome(context, {
200
+ url: 'https://example.com'
201
+ });
202
+
203
+ // Auto-cache enabled (uses file hash as cache key)
204
+ // First call: AI vision analysis, saves to cache
205
+ const button = await testdriver.find('More information link');
206
+ console.log('Cache hit:', button.cacheHit); // false (first run)
207
+
208
+ // Second call: uses cache (instant)
209
+ const button2 = await testdriver.find('More information link');
210
+ console.log('Cache hit:', button2.cacheHit); // true (cache hit)
211
+
212
+ // Custom cache key
213
+ const button3 = await testdriver.find('submit button', {
214
+ cacheKey: 'my-button'
215
+ });
216
+ });
217
+ ```
218
+
219
+ ### Dynamic Threshold Example
220
+
221
+ ```javascript
222
+ test('strict vs lenient matching', async (context) => {
223
+ const { testdriver } = await chrome(context, { url });
224
+
225
+ // Strict: 99% similarity required (auto-cache key)
226
+ const elem1 = await testdriver.find('button', { cacheThreshold: 0.01 });
227
+
228
+ // Lenient: 90% similarity acceptable
229
+ const elem2 = await testdriver.find('button', { cacheThreshold: 0.10 });
230
+
231
+ // Bypass cache entirely (no cacheKey needed)
232
+ const elem3 = await testdriver.find('button', { cacheThreshold: -1 });
233
+
234
+ // Custom cache key with threshold
235
+ const elem4 = await testdriver.find('button', {
236
+ cacheKey: 'my-button',
237
+ cacheThreshold: 0.05
238
+ });
239
+ });
240
+ ```
241
+
242
+ ### Checking Cache Hits
243
+
244
+ ```javascript
245
+ test('monitor cache performance', async (context) => {
246
+ const { testdriver } = await chrome(context, { url });
247
+
248
+ // Auto-cache enabled
249
+ const element = await testdriver.find('submit button');
250
+
251
+ if (element.cacheHit) {
252
+ console.log('✅ Cache hit - instant response');
253
+ console.log('Cache strategy:', element.cacheStrategy);
254
+ console.log('Cache age:', element.cacheCreatedAt);
255
+ } else {
256
+ console.log('⏱️ Cache miss - AI analysis performed');
257
+ console.log('New cache entry created');
258
+ }
259
+
260
+ // Check similarity score
261
+ if (element.similarity) {
262
+ console.log(`Similarity: ${(element.similarity * 100).toFixed(1)}%`);
263
+ }
264
+ });
265
+ ```
266
+
267
+ ## Best Practices
268
+
269
+ ### 1. Use Appropriate Thresholds
270
+
271
+ ```javascript
272
+ // Stable UI: strict threshold (auto-cache)
273
+ await testdriver.find('logo', { cacheThreshold: 0.01 });
274
+
275
+ // Dynamic UI: lenient threshold
276
+ await testdriver.find('news feed item', { cacheThreshold: 0.10 });
277
+
278
+ // Always fresh: disable cache
279
+ await testdriver.find('timestamp', { cacheThreshold: -1 });
280
+ ```
281
+
282
+ ### 2. Choose Cache Key Strategy
283
+
284
+ ```javascript
285
+ // Auto-cache (recommended) - per-file isolation
286
+ await testdriver.find('button');
287
+
288
+ // Custom key - share across tests
289
+ await testdriver.find('button', { cacheKey: 'global-submit' });
290
+
291
+ // Global key - all finds in test
292
+ const testdriver = new TestDriver(apiKey, {
293
+ cacheKey: 'test-suite-1'
294
+ });
295
+ ```
296
+
297
+ Check [console.testdriver.ai](https://console.testdriver.ai) regularly to:
298
+ - See cache hit rates
299
+ - Identify frequently used selectors
300
+ - Remove stale cache entries
301
+ - Optimize threshold settings
302
+
303
+ ### 3. Clear Cache When UI Changes
304
+
305
+ If your UI changes significantly, delete cache entries through the console dashboard.
306
+
307
+ ### 4. Use Consistent Prompts
308
+
309
+ ```javascript
310
+ // ✅ Good - consistent prompt
311
+ await testdriver.find('submit button');
312
+ await testdriver.find('submit button'); // Cache hit
313
+
314
+ // ❌ Bad - different prompts
315
+ await testdriver.find('submit button');
316
+ await testdriver.find('the submit button'); // Cache miss
317
+ ```
318
+
319
+ ## Cache Storage Details
320
+
321
+ | Property | Value |
322
+ |----------|-------|
323
+ | Location | Server (MongoDB + S3) |
324
+ | Persistence | 7 days default |
325
+ | Scope | Per-team |
326
+ | Matching | Screenshot similarity + prompt |
327
+ | Expiration | 7-day rolling window |
328
+
329
+ ## Troubleshooting
330
+
331
+ ### Cache Not Working
332
+
333
+ Check:
334
+ 1. Threshold isn't too strict (try 0.10 for 90% similarity)
335
+ 2. Screenshot hasn't changed significantly
336
+ 3. OS/resolution matches cached entry
337
+ 4. Cache entry isn't older than 7 days
338
+ 5. Prompt matches exactly (case-insensitive)
339
+
340
+ ### Low Cache Hit Rate
341
+
342
+ If you're seeing low cache hit rates:
343
+
344
+ 1. **Increase threshold** - Try 0.10 (90% similarity) for dynamic UIs
345
+ 2. **Stabilize UI** - Minimize animations, random data, timestamps
346
+ 3. **Use consistent prompts** - Same wording every time
347
+ 4. **Check console** - View similarity scores in dashboard
348
+
349
+ ### Stale Cache Data
350
+
351
+ Delete selector cache entries at [console.testdriver.ai](https://console.testdriver.ai)
352
+
353
+ - Find the cached entry by prompt or screenshot
354
+ - Click delete to remove stale entries
355
+ - Run test again to create fresh cache
356
+
357
+ ### Cache Misses on Identical UI
358
+
359
+ If cache misses occur on seemingly identical screens:
360
+
361
+ 1. **Check resolution** - Cache is resolution-specific
362
+ 2. **Check OS** - Cache is platform-specific
363
+ 3. **Check pixel differences** - Even 1px changes can cause misses with strict thresholds
364
+ 4. **Increase threshold** - Allow more similarity variance
365
+
366
+ ## Advanced Configuration
367
+
368
+ ### Environment Variables
369
+
370
+ ```bash
371
+ # Disable selector cache entirely
372
+ TD_NO_SELECTOR_CACHE=1
373
+
374
+ # Set default threshold globally
375
+ TD_DEFAULT_THRESHOLD=0.10
376
+ ```
377
+
378
+ ### Per-Test Configuration
379
+
380
+ ```javascript
381
+ test('custom cache settings', async (context) => {
382
+ const { testdriver } = await chrome(context, {
383
+ url,
384
+ cacheDefaults: {
385
+ threshold: 0.10, // 90% similarity
386
+ enabled: true
387
+ }
388
+ });
389
+
390
+ // Uses custom defaults
391
+ await testdriver.find('button');
392
+ });
393
+ ```
394
+
395
+ ## See Also
396
+
397
+ - [AI Prompt Caching](/v7/guides/caching-ai) - Cache AI-generated YAML
398
+ - [Console Dashboard](https://console.testdriver.ai) - View and manage selector cache
399
+ - [`.find()` Method](/v7/api/find) - Element location
400
+ - [Vitest Integration](/v7/guides/vitest) - Testing with TestDriver