@testdriverai/mcp 7.10.0-canary.0 → 7.10.1-test

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 (196) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/agent/index.js +116 -71
  3. package/agent/interface.js +13 -1
  4. package/agent/lib/commands.js +35 -15
  5. package/agent/lib/provision-commands.js +92 -11
  6. package/agent/lib/sandbox.js +263 -30
  7. package/agent/lib/sdk.js +16 -12
  8. package/agent/lib/system.js +107 -31
  9. package/ai/.claude-plugin/plugin.json +89 -4
  10. package/ai/agents/testdriver.md +4 -8
  11. package/ai/skills/testdriver-assert/SKILL.md +0 -1
  12. package/ai/skills/testdriver-aws-setup/SKILL.md +1 -1
  13. package/ai/skills/testdriver-caching/SKILL.md +13 -6
  14. package/ai/skills/testdriver-ci-cd/SKILL.md +57 -14
  15. package/ai/skills/testdriver-client/SKILL.md +10 -6
  16. package/ai/skills/testdriver-customizing-devices/SKILL.md +7 -5
  17. package/ai/skills/testdriver-dashcam/SKILL.md +36 -3
  18. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +28 -4
  19. package/ai/skills/testdriver-device-config/SKILL.md +5 -5
  20. package/ai/skills/testdriver-find/SKILL.md +50 -11
  21. package/ai/skills/testdriver-generating-tests/SKILL.md +163 -8
  22. package/ai/skills/testdriver-hosted/SKILL.md +1 -1
  23. package/ai/skills/testdriver-machine-setup/SKILL.md +331 -0
  24. package/ai/skills/testdriver-making-assertions/SKILL.md +78 -2
  25. package/ai/skills/testdriver-mcp-workflow/SKILL.md +2 -2
  26. package/ai/skills/testdriver-parse/SKILL.md +1 -1
  27. package/ai/skills/testdriver-performing-actions/SKILL.md +97 -3
  28. package/ai/skills/testdriver-provision/SKILL.md +0 -20
  29. package/ai/skills/testdriver-quickstart/SKILL.md +299 -21
  30. package/ai/skills/testdriver-reusable-code/SKILL.md +3 -3
  31. package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
  32. package/ai/skills/testdriver-screenshot/SKILL.md +5 -5
  33. package/ai/skills/testdriver-scroll/SKILL.md +30 -160
  34. package/ai/skills/testdriver-test-writer/SKILL.md +3 -5
  35. package/ai/skills/testdriver-testdriver/SKILL.md +3 -7
  36. package/ai/skills/testdriver-wait/SKILL.md +1 -1
  37. package/{docs/v7/ai.mdx → ai/skills/testdriver:ai/SKILL.md} +3 -4
  38. package/ai/skills/testdriver:assert/SKILL.md +315 -0
  39. package/ai/skills/testdriver:aws-setup/SKILL.md +448 -0
  40. package/ai/skills/testdriver:cache/SKILL.md +221 -0
  41. package/ai/skills/testdriver:caching/SKILL.md +124 -0
  42. package/ai/skills/testdriver:captcha/SKILL.md +158 -0
  43. package/ai/skills/testdriver:ci-cd/SKILL.md +659 -0
  44. package/ai/skills/testdriver:click/SKILL.md +286 -0
  45. package/ai/skills/testdriver:client/SKILL.md +477 -0
  46. package/ai/skills/testdriver:customizing-devices/SKILL.md +319 -0
  47. package/ai/skills/testdriver:dashcam/SKILL.md +451 -0
  48. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +415 -0
  49. package/{docs/v7/device-config.mdx → ai/skills/testdriver:device-config/SKILL.md} +8 -8
  50. package/ai/skills/testdriver:double-click/SKILL.md +102 -0
  51. package/ai/skills/testdriver:elements/SKILL.md +605 -0
  52. package/ai/skills/testdriver:enterprise/SKILL.md +7 -0
  53. package/ai/skills/testdriver:errors/SKILL.md +246 -0
  54. package/ai/skills/testdriver:events/SKILL.md +356 -0
  55. package/ai/skills/testdriver:exec/SKILL.md +317 -0
  56. package/ai/skills/testdriver:find/SKILL.md +860 -0
  57. package/ai/skills/testdriver:focus-application/SKILL.md +293 -0
  58. package/ai/skills/testdriver:generating-tests/SKILL.md +25 -0
  59. package/ai/skills/testdriver:hosted/SKILL.md +156 -0
  60. package/ai/skills/testdriver:hover/SKILL.md +278 -0
  61. package/{docs/v7/locating-elements.mdx → ai/skills/testdriver:locating-elements/SKILL.md} +3 -3
  62. package/ai/skills/testdriver:making-assertions/SKILL.md +32 -0
  63. package/ai/skills/testdriver:mcp/SKILL.md +7 -0
  64. package/ai/skills/testdriver:mouse-down/SKILL.md +161 -0
  65. package/ai/skills/testdriver:mouse-up/SKILL.md +164 -0
  66. package/ai/skills/testdriver:parse/SKILL.md +236 -0
  67. package/ai/skills/testdriver:performing-actions/SKILL.md +53 -0
  68. package/ai/skills/testdriver:press-keys/SKILL.md +348 -0
  69. package/ai/skills/testdriver:provision/SKILL.md +331 -0
  70. package/ai/skills/testdriver:quickstart/SKILL.md +172 -0
  71. package/ai/skills/testdriver:redraw/SKILL.md +214 -0
  72. package/ai/skills/testdriver:reusable-code/SKILL.md +249 -0
  73. package/ai/skills/testdriver:right-click/SKILL.md +123 -0
  74. package/{docs/v7/running-tests.mdx → ai/skills/testdriver:running-tests/SKILL.md} +4 -4
  75. package/ai/skills/testdriver:screenshot/SKILL.md +248 -0
  76. package/ai/skills/testdriver:screenshots/SKILL.md +184 -0
  77. package/ai/skills/testdriver:scroll/SKILL.md +205 -0
  78. package/ai/skills/testdriver:secrets/SKILL.md +115 -0
  79. package/ai/skills/testdriver:self-hosted/SKILL.md +147 -0
  80. package/ai/skills/testdriver:test-results-json/SKILL.md +257 -0
  81. package/ai/skills/testdriver:testdriver/SKILL.md +624 -0
  82. package/ai/skills/testdriver:type/SKILL.md +357 -0
  83. package/ai/skills/testdriver:variables/SKILL.md +111 -0
  84. package/ai/skills/testdriver:wait/SKILL.md +50 -0
  85. package/{docs/v7/waiting-for-elements.mdx → ai/skills/testdriver:waiting-for-elements/SKILL.md} +3 -3
  86. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +54 -0
  87. package/debugger/index.html +12 -0
  88. package/docs/_data/examples-manifest.json +54 -46
  89. package/docs/_data/examples-manifest.schema.json +12 -2
  90. package/docs/_scripts/extract-example-urls.js +21 -3
  91. package/docs/_scripts/generate-examples.js +64 -16
  92. package/docs/changelog.mdx +29 -2
  93. package/docs/claude-mcp-plugin.mdx +65 -18
  94. package/docs/docs.json +16 -33
  95. package/docs/snippets/tests/scroll-yaml.mdx +2 -2
  96. package/docs/v6/commands/scroll-until-image.mdx +1 -1
  97. package/docs/v6/commands/scroll-until-text.mdx +2 -2
  98. package/docs/v6/commands/scroll.mdx +2 -2
  99. package/docs/v7/_drafts/agents.mdx +0 -4
  100. package/docs/v7/_drafts/best-practices.mdx +0 -12
  101. package/docs/v7/_drafts/commands/scroll-until-image.mdx +1 -1
  102. package/docs/v7/_drafts/commands/scroll-until-text.mdx +2 -2
  103. package/docs/v7/_drafts/commands/scroll.mdx +1 -1
  104. package/docs/v7/_drafts/configuration.mdx +0 -12
  105. package/docs/v7/_drafts/faq.mdx +2 -10
  106. package/docs/v7/_drafts/readme.mdx +0 -1
  107. package/docs/v7/_drafts/troubleshooting.mdx +1 -4
  108. package/docs/v7/assert.mdx +0 -1
  109. package/docs/v7/aws-setup.mdx +1 -1
  110. package/docs/v7/caching.mdx +14 -10
  111. package/docs/v7/ci-cd.mdx +98 -14
  112. package/docs/v7/client.mdx +10 -6
  113. package/docs/v7/copilot/auto-healing.mdx +167 -18
  114. package/docs/v7/copilot/running-tests.mdx +915 -54
  115. package/docs/v7/customizing-devices.mdx +7 -5
  116. package/docs/v7/dashcam.mdx +36 -3
  117. package/docs/v7/debugging-with-screenshots.mdx +31 -7
  118. package/docs/v7/examples/ai.mdx +13 -8
  119. package/docs/v7/examples/assert.mdx +1 -1
  120. package/docs/v7/examples/chrome-extension.mdx +30 -13
  121. package/docs/v7/examples/element-not-found.mdx +1 -1
  122. package/docs/v7/examples/findall-coffee-icons.mdx +3 -2
  123. package/docs/v7/examples/formatted-logging.mdx +74 -0
  124. package/docs/v7/examples/hover-image.mdx +1 -1
  125. package/docs/v7/examples/hover-text-with-description.mdx +2 -2
  126. package/docs/v7/examples/hover-text.mdx +1 -1
  127. package/docs/v7/examples/installer.mdx +1 -1
  128. package/docs/v7/examples/launch-vscode-linux.mdx +27 -27
  129. package/docs/v7/examples/match-image.mdx +1 -1
  130. package/docs/v7/examples/parse.mdx +3 -2
  131. package/docs/v7/examples/press-keys.mdx +2 -2
  132. package/docs/v7/examples/scroll-keyboard.mdx +2 -2
  133. package/docs/v7/examples/scroll-until-text.mdx +1 -1
  134. package/docs/v7/examples/scroll.mdx +1 -1
  135. package/docs/v7/examples/type.mdx +1 -1
  136. package/docs/v7/find.mdx +50 -11
  137. package/docs/v7/generating-tests.mdx +166 -10
  138. package/docs/v7/hosted.mdx +1 -1
  139. package/docs/v7/making-assertions.mdx +81 -4
  140. package/docs/v7/parse.mdx +1 -1
  141. package/docs/v7/performing-actions.mdx +100 -5
  142. package/docs/v7/provision.mdx +0 -20
  143. package/docs/v7/quickstart.mdx +299 -21
  144. package/docs/v7/reusable-code.mdx +3 -3
  145. package/docs/v7/screenshot.mdx +5 -5
  146. package/docs/v7/scroll.mdx +30 -160
  147. package/docs/v7/wait.mdx +1 -1
  148. package/examples/chrome-extension.test.mjs +29 -12
  149. package/examples/config.mjs +1 -1
  150. package/examples/launch-vscode-linux.test.mjs +25 -25
  151. package/interfaces/cli/commands/init.js +84 -2
  152. package/interfaces/vitest-plugin.mjs +51 -61
  153. package/lib/core/Dashcam.js +43 -2
  154. package/lib/core/index.d.ts +13 -1
  155. package/lib/github-comment.mjs +11 -5
  156. package/lib/init-project.js +98 -44
  157. package/lib/install-clients.js +470 -0
  158. package/lib/provision.js +749 -0
  159. package/lib/resolve-channel.js +2 -2
  160. package/lib/sentry.js +15 -2
  161. package/lib/vitest/hooks.mjs +44 -34
  162. package/mcp-server/README.md +32 -0
  163. package/mcp-server/dist/core/actions.d.ts +176 -0
  164. package/mcp-server/dist/core/actions.js +753 -0
  165. package/mcp-server/dist/env-utils.d.ts +45 -0
  166. package/mcp-server/dist/env-utils.js +63 -0
  167. package/mcp-server/dist/provision-types.d.ts +6 -2
  168. package/mcp-server/dist/provision-types.js +3 -1
  169. package/mcp-server/dist/server.mjs +449 -751
  170. package/mcp-server/package-lock.json +384 -1
  171. package/mcp-server/package.json +5 -2
  172. package/mcp-server/src/core/actions.ts +912 -0
  173. package/mcp-server/src/env-utils.test.ts +82 -0
  174. package/mcp-server/src/env-utils.ts +77 -0
  175. package/mcp-server/src/provision-types.ts +4 -1
  176. package/mcp-server/src/server.ts +533 -954
  177. package/mcp-server/tsconfig.json +1 -1
  178. package/mcp-server/vitest.config.ts +7 -0
  179. package/package.json +15 -3
  180. package/sdk.d.ts +11 -9
  181. package/sdk.js +116 -746
  182. package/setup/aws/spawn-runner.sh +24 -3
  183. package/docs/v7/_drafts/caching-ai.mdx +0 -215
  184. package/docs/v7/_drafts/caching.mdx +0 -366
  185. package/docs/v7/_drafts/prompt-cache.mdx +0 -200
  186. package/docs/v7/copilot/creating-tests.mdx +0 -156
  187. package/docs/v7/copilot/github.mdx +0 -143
  188. package/docs/v7/copilot/setup.mdx +0 -143
  189. package/docs/v7/examples/exec-output.mdx +0 -84
  190. package/docs/v7/examples/exec-pwsh.mdx +0 -82
  191. package/docs/v7/examples/focus-window.mdx +0 -61
  192. package/docs/v7/examples/scroll-until-image.mdx +0 -82
  193. package/docs/v7/examples/windows-installer.mdx +0 -95
  194. package/examples/formatted-logging.test.mjs +0 -27
  195. package/examples/match-image.test.mjs +0 -55
  196. package/manual/exec-stream-logs.test.mjs +0 -25
@@ -145,17 +145,38 @@ done
145
145
  echo "Installing runner..."
146
146
 
147
147
  # Determine environment and version
148
- TD_CHANNEL="${TD_CHANNEL:-stable}"
149
148
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
150
- SDK_PKG_JSON="${SCRIPT_DIR}/../../../sdk/package.json"
149
+ # SDK package.json — works both from monorepo (sdk/setup/aws/) and npm install (setup/aws/)
150
+ SDK_PKG_JSON="${SCRIPT_DIR}/../../package.json"
151
151
  RUNNER_DIR="${SCRIPT_DIR}/../../../runner"
152
152
 
153
+ # Derive channel from TD_CHANNEL env, or from the SDK version's prerelease tag
154
+ # (mirrors sdk/lib/resolve-channel.js logic)
155
+ if [ -z "${TD_CHANNEL:-}" ]; then
156
+ if [ -f "$SDK_PKG_JSON" ]; then
157
+ SDK_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
158
+ # Extract prerelease tag: "7.6.0-canary.5" → "canary", "7.6.0" → ""
159
+ PRE_TAG=$(echo "$SDK_VERSION" | sed -n 's/^[0-9]*\.[0-9]*\.[0-9]*-\([a-z]*\).*/\1/p')
160
+ if [ -n "$PRE_TAG" ] && echo "$PRE_TAG" | grep -qE '^(dev|test|canary|stable)$'; then
161
+ TD_CHANNEL="$PRE_TAG"
162
+ echo "Channel derived from SDK version ($SDK_VERSION): $TD_CHANNEL"
163
+ else
164
+ TD_CHANNEL="stable"
165
+ echo "SDK version $SDK_VERSION has no prerelease tag, defaulting to: $TD_CHANNEL"
166
+ fi
167
+ else
168
+ TD_CHANNEL="stable"
169
+ echo "SDK package.json not found, defaulting channel to: $TD_CHANNEL"
170
+ fi
171
+ fi
172
+ echo "Using channel: $TD_CHANNEL"
173
+
153
174
  if [ -f "$SDK_PKG_JSON" ]; then
154
175
  RUNNER_VERSION=$(jq -r '.version' "$SDK_PKG_JSON")
155
176
  echo "Runner version from SDK: $RUNNER_VERSION"
156
177
  else
157
178
  RUNNER_VERSION="$TD_CHANNEL"
158
- echo "SDK package.json not found, using env tag: $RUNNER_VERSION"
179
+ echo "SDK package.json not found, using channel as runner version: $RUNNER_VERSION"
159
180
  fi
160
181
 
161
182
  if [ "$TD_CHANNEL" = "dev" ]; then
@@ -1,215 +0,0 @@
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
@@ -1,366 +0,0 @@
1
- ---
2
- title: "Caching Prompts"
3
- sidebarTitle: "Caching Prompts"
4
- description: "How TestDriver caches AI responses and element locations for faster tests"
5
- icon: "bolt"
6
- ---
7
-
8
- ## Overview
9
-
10
- TestDriver uses two types of caching to dramatically speed up your tests and reduce AI costs:
11
-
12
- 1. **Prompt Cache** - Caches AI-generated commands (`.ai()` responses)
13
- 2. **Selector Cache** - Caches element locations (`.find()` results)
14
-
15
- Both caches are enabled by default and work automatically.
16
-
17
- ## Prompt Cache
18
-
19
- The Prompt Cache stores AI-generated YAML commands locally, so repeated `.ai()` calls with the same prompt skip the AI entirely.
20
-
21
- ### How It Works
22
-
23
- <Steps>
24
- <Step title="First Call">
25
- ```javascript
26
- await testdriver.ai('click the submit button');
27
- ```
28
-
29
- - Sends prompt + screenshot to AI
30
- - Receives YAML commands
31
- - Saves to `.testdriver/.cache/{prompt-hash}.yaml`
32
- </Step>
33
-
34
- <Step title="Subsequent Calls">
35
- ```javascript
36
- await testdriver.ai('click the submit button');
37
- ```
38
-
39
- - Checks cache first
40
- - Finds matching cached YAML
41
- - Uses cached commands (no AI call)
42
- - Shows `(using cached response)` in output
43
- </Step>
44
- </Steps>
45
-
46
- ### Cache Location
47
-
48
- Cached prompts are stored locally:
49
-
50
- ```
51
- .testdriver/
52
- .cache/
53
- click-the-submit-button-a1b2c3d4.yaml
54
- find-login-form-e5f6a7b8.yaml
55
- verify-dashboard-c9d0e1f2.yaml
56
- ```
57
-
58
- Files are named using:
59
- - Sanitized prompt (first 50 chars, alphanumeric)
60
- - MD5 hash of full prompt for uniqueness
61
-
62
- ### Disabling Prompt Cache
63
-
64
- Bypass the cache for a specific call:
65
-
66
- ```javascript
67
- // Force fresh AI call, bypass cache
68
- await testdriver.ai('click the submit button', false);
69
-
70
- // These use cache (default)
71
- await testdriver.ai('click the submit button');
72
- await testdriver.ai('click the submit button', true);
73
- ```
74
-
75
- ### Clearing Prompt Cache
76
-
77
- Clear all cached prompts:
78
-
79
- ```bash
80
- rm -rf .testdriver/.cache/*.yaml
81
- ```
82
-
83
- Or programmatically:
84
-
85
- ```javascript
86
- const promptCache = require('testdriverai/agent/lib/cache.js');
87
- promptCache.clearCache();
88
- ```
89
-
90
- ### Benefits
91
-
92
- - ⚡ **Instant execution** - No AI call needed
93
- - 💰 **Cost savings** - Reduces API usage
94
- - 🔌 **Offline testing** - Works without network
95
- - 🎯 **Deterministic** - Same prompt = same commands
96
-
97
- ## Selector Cache
98
-
99
- The Selector Cache stores element locations on the server, so `.find()` calls can skip the AI vision analysis.
100
-
101
- ### How It Works
102
-
103
- ```mermaid
104
- sequenceDiagram
105
- participant Test as Your Test
106
- participant SDK as TestDriver SDK
107
- participant API as TestDriver API
108
- participant AI as Claude Vision
109
- participant Cache as Selector Cache DB
110
-
111
- Test->>SDK: testdriver.find('submit button')
112
- SDK->>API: POST /locate (screenshot + prompt)
113
-
114
- API->>Cache: Check for matching cache entry
115
-
116
- alt Cache Hit (95%+ similar screenshot)
117
- Cache-->>API: Return cached coordinates
118
- API-->>SDK: {x, y, cacheHit: true}
119
- SDK-->>Test: Element found (instant)
120
- else Cache Miss
121
- API->>AI: Analyze screenshot
122
- AI-->>API: Element coordinates
123
- API->>Cache: Save new cache entry
124
- API-->>SDK: {x, y, cacheHit: false}
125
- SDK-->>Test: Element found
126
- end
127
- ```
128
-
129
- ### Cache Matching Strategy
130
-
131
- The selector cache uses a three-tier matching system:
132
-
133
- 1. **Exact Hash Match** (Fastest)
134
- - Perceptual hash comparison
135
- - Same screenshot = instant match
136
- - 0% difference threshold
137
-
138
- 2. **Pixel Diff Match** (Fast)
139
- - 80%+ perceptual hash similarity
140
- - Pixel-by-pixel comparison
141
- - Default 5% difference threshold (95% similarity)
142
- - Configurable per call
143
-
144
- 3. **Template Match** (Fallback)
145
- - Edge detection + template matching
146
- - Finds visually similar UI elements
147
- - 75%+ confidence threshold
148
-
149
- ### Viewing Cache Entries
150
-
151
- View all cached selectors at [console.testdriver.ai](https://console.testdriver.ai)
152
-
153
- The console shows:
154
- - Cached screenshots with green circles on found elements
155
- - Original prompts
156
- - Hit count (how many times cache was used)
157
- - Similarity scores
158
- - Cache age and last accessed time
159
-
160
- ### Controlling Cache Threshold
161
-
162
- Adjust similarity threshold per call:
163
-
164
- ```javascript
165
- // Default: 95% similarity (5% difference allowed)
166
- await testdriver.find('submit button');
167
-
168
- // Stricter: 99% similarity (1% difference allowed)
169
- await testdriver.find('submit button', { threshold: 0.01 });
170
-
171
- // More lenient: 90% similarity (10% difference allowed)
172
- await testdriver.find('submit button', { threshold: 0.10 });
173
-
174
- // Disable cache: force fresh AI analysis
175
- await testdriver.find('submit button', { threshold: -1 });
176
- ```
177
-
178
- ### Cache Filtering
179
-
180
- The selector cache automatically filters by:
181
-
182
- - **Prompt** - Exact text match (case-insensitive)
183
- - **Team** - Your team ID
184
- - **OS** - Operating system (if specified)
185
- - **Resolution** - Screen resolution (if specified)
186
- - **Time Window** - Last 7 days by default
187
-
188
- ### Cache Statistics
189
-
190
- Each cache entry tracks:
191
-
192
- - **Hit Count** - Number of times cache was used
193
- - **Last Hit** - When cache was last accessed
194
- - **Similarity** - Percentage match to original
195
- - **Created At** - When entry was created
196
- - **Element Type** - button, input, link, etc.
197
- - **Element Bounds** - Bounding box coordinates
198
-
199
- ### Benefits
200
-
201
- - ⚡ **Up to 10x faster** - Skip AI vision analysis
202
- - 💰 **Lower AI costs** - Fewer vision API calls
203
- - 🎯 **Consistent results** - Same UI = same coordinates
204
- - 📊 **Metrics tracking** - See cache hit rates in console
205
-
206
- ## Cache Behavior Examples
207
-
208
- ### Prompt Cache Example
209
-
210
- ```javascript
211
- import { test } from 'vitest';
212
- import { chrome } from 'testdriverai/presets';
213
-
214
- test('login flow', async (context) => {
215
- const { testdriver } = await chrome(context, {
216
- url: 'https://myapp.com/login'
217
- });
218
-
219
- // First call: AI generates commands, saves to cache
220
- await testdriver.ai('click the login button');
221
-
222
- // Run test again - uses cache (instant)
223
- // Look for: "(using cached response)" in output
224
- });
225
- ```
226
-
227
- ### Selector Cache Example
228
-
229
- ```javascript
230
- import { test } from 'vitest';
231
- import { chrome } from 'testdriverai/presets';
232
-
233
- test('find element', async (context) => {
234
- const { testdriver } = await chrome(context, {
235
- url: 'https://example.com'
236
- });
237
-
238
- // First call: AI vision analysis, saves to cache
239
- const button = await testdriver.find('More information link');
240
- console.log('Cache hit:', button.cacheHit); // false
241
-
242
- // Second call: uses cache (instant)
243
- const button2 = await testdriver.find('More information link');
244
- console.log('Cache hit:', button2.cacheHit); // true
245
- });
246
- ```
247
-
248
- ### Dynamic Threshold Example
249
-
250
- ```javascript
251
- test('strict vs lenient matching', async (context) => {
252
- const { testdriver } = await chrome(context, { url });
253
-
254
- // Strict: 99% similarity required
255
- const elem1 = await testdriver.find('button', { threshold: 0.01 });
256
-
257
- // Lenient: 90% similarity acceptable
258
- const elem2 = await testdriver.find('button', { threshold: 0.10 });
259
-
260
- // Bypass cache entirely
261
- const elem3 = await testdriver.find('button', { threshold: -1 });
262
- });
263
- ```
264
-
265
- ## Best Practices
266
-
267
- ### 1. Use Consistent Prompts
268
-
269
- ```javascript
270
- // ✅ Good - consistent prompt
271
- await testdriver.find('submit button');
272
- await testdriver.find('submit button'); // Cache hit
273
-
274
- // ❌ Bad - different prompts
275
- await testdriver.find('submit button');
276
- await testdriver.find('the submit button'); // Cache miss
277
- ```
278
-
279
- ### 2. Clear Cache When UI Changes
280
-
281
- If your UI changes significantly, clear the cache:
282
-
283
- ```bash
284
- # Clear prompt cache
285
- rm -rf .testdriver/.cache/*.yaml
286
-
287
- # Clear selector cache
288
- # Use console.testdriver.ai to delete entries
289
- ```
290
-
291
- ### 3. Use Appropriate Thresholds
292
-
293
- ```javascript
294
- // Stable UI: strict threshold
295
- await testdriver.find('logo', { threshold: 0.01 });
296
-
297
- // Dynamic UI: lenient threshold
298
- await testdriver.find('news feed item', { threshold: 0.10 });
299
-
300
- // Always fresh: disable cache
301
- await testdriver.find('timestamp', { threshold: -1 });
302
- ```
303
-
304
- ### 4. Monitor Cache Performance
305
-
306
- Check [console.testdriver.ai](https://console.testdriver.ai) regularly to:
307
- - See cache hit rates
308
- - Identify frequently used selectors
309
- - Remove stale cache entries
310
- - Optimize threshold settings
311
-
312
- ## Cache Storage
313
-
314
- | Cache Type | Location | Persistence |
315
- |------------|----------|-------------|
316
- | Prompt Cache | Local (`.testdriver/.cache/`) | Until manually cleared |
317
- | Selector Cache | Server (MongoDB + S3) | 7 days default |
318
-
319
- ## Important Notes
320
-
321
- ### Prompt Cache
322
-
323
- - Cache keys are **prompt text only** (no screenshot comparison)
324
- - Case-insensitive, trimmed matching
325
- - Safe to commit to version control (but not recommended)
326
- - Never expires automatically
327
-
328
- ### Selector Cache
329
-
330
- - Cache matches by **screenshot similarity** + prompt
331
- - Platform-specific (OS, resolution)
332
- - Team-scoped (your cache entries only)
333
- - 7-day rolling window by default
334
-
335
- ## Troubleshooting
336
-
337
- ### Prompt Cache Not Working
338
-
339
- Check:
340
- 1. Prompts match exactly (case-insensitive)
341
- 2. `.testdriver/.cache/` directory exists and is writable
342
- 3. `TD_NO_PROMPT_CACHE` environment variable is not set
343
-
344
- ### Selector Cache Not Working
345
-
346
- Check:
347
- 1. Threshold isn't too strict (try 0.10 for 90% similarity)
348
- 2. Screenshot hasn't changed significantly
349
- 3. OS/resolution matches cached entry
350
- 4. Cache entry isn't older than 7 days
351
-
352
- ### Stale Cache Data
353
-
354
- Clear prompt cache:
355
- ```bash
356
- rm -rf .testdriver/.cache/*.yaml
357
- ```
358
-
359
- Delete selector cache entries at [console.testdriver.ai](https://console.testdriver.ai)
360
-
361
- ## See Also
362
-
363
- - [Console Dashboard](https://console.testdriver.ai) - View and manage selector cache
364
- - [`.ai()` Method](/v7/api/ai) - AI command generation
365
- - [`.find()` Method](/v7/api/find) - Element location
366
- - [Vitest Integration](/v7/guides/vitest) - Testing with TestDriver