testdriverai 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +550 -0
- package/CODEOWNERS +0 -1
- package/README.md +126 -0
- package/agent/index.js +43 -18
- package/agent/lib/commands.js +794 -135
- package/agent/lib/redraw.js +124 -39
- package/agent/lib/sandbox.js +10 -1
- package/agent/lib/sdk.js +21 -0
- package/docs/MIGRATION.md +425 -0
- package/docs/PRESETS.md +210 -0
- package/docs/docs.json +91 -37
- package/docs/guide/best-practices-polling.mdx +154 -0
- package/docs/v7/api/dashcam.mdx +497 -0
- package/docs/v7/api/doubleClick.mdx +102 -0
- package/docs/v7/api/mouseDown.mdx +161 -0
- package/docs/v7/api/mouseUp.mdx +164 -0
- package/docs/v7/api/rightClick.mdx +123 -0
- package/docs/v7/getting-started/configuration.mdx +380 -0
- package/docs/v7/getting-started/quickstart.mdx +273 -140
- package/docs/v7/guides/best-practices.mdx +486 -0
- package/docs/v7/guides/caching-ai.mdx +215 -0
- package/docs/v7/guides/caching-selectors.mdx +292 -0
- package/docs/v7/guides/caching.mdx +366 -0
- package/docs/v7/guides/ci-cd/azure.mdx +587 -0
- package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
- package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
- package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
- package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
- package/docs/v7/guides/ci-cd/travis.mdx +438 -0
- package/docs/v7/guides/debugging.mdx +349 -0
- package/docs/v7/guides/faq.mdx +393 -0
- package/docs/v7/guides/performance.mdx +517 -0
- package/docs/v7/guides/troubleshooting.mdx +526 -0
- package/docs/v7/guides/vitest-plugin.mdx +477 -0
- package/docs/v7/guides/vitest.mdx +535 -0
- package/docs/v7/platforms/linux.mdx +308 -0
- package/docs/v7/platforms/macos.mdx +433 -0
- package/docs/v7/platforms/windows.mdx +430 -0
- package/docs/v7/presets/chrome-extension.mdx +223 -0
- package/docs/v7/presets/chrome.mdx +287 -0
- package/docs/v7/presets/electron.mdx +435 -0
- package/docs/v7/presets/vscode.mdx +398 -0
- package/docs/v7/presets/webapp.mdx +396 -0
- package/docs/v7/progressive-apis/CORE.md +459 -0
- package/docs/v7/progressive-apis/HOOKS.md +360 -0
- package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
- package/docs/v7/progressive-apis/PROVISION.md +266 -0
- package/interfaces/vitest-plugin.mjs +186 -100
- package/package.json +12 -1
- package/sdk.d.ts +335 -42
- package/sdk.js +756 -95
- package/src/core/Dashcam.js +469 -0
- package/src/core/index.d.ts +150 -0
- package/src/core/index.js +12 -0
- package/src/presets/index.mjs +331 -0
- package/src/vitest/extended.mjs +108 -0
- package/src/vitest/hooks.d.ts +119 -0
- package/src/vitest/hooks.mjs +298 -0
- package/src/vitest/index.mjs +64 -0
- package/src/vitest/lifecycle.mjs +277 -0
- package/src/vitest/utils.mjs +150 -0
- package/test/dashcam.test.js +137 -0
- package/testdriver/acceptance-sdk/assert.test.mjs +13 -31
- package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
- package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
- package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +7 -19
- package/testdriver/acceptance-sdk/element-not-found.test.mjs +6 -19
- package/testdriver/acceptance-sdk/exec-js.test.mjs +6 -18
- package/testdriver/acceptance-sdk/exec-output.test.mjs +8 -20
- package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +13 -25
- package/testdriver/acceptance-sdk/focus-window.test.mjs +8 -20
- package/testdriver/acceptance-sdk/formatted-logging.test.mjs +5 -20
- package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
- package/testdriver/acceptance-sdk/hover-image.test.mjs +10 -19
- package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +7 -19
- package/testdriver/acceptance-sdk/hover-text.test.mjs +5 -19
- package/testdriver/acceptance-sdk/match-image.test.mjs +7 -19
- package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
- package/testdriver/acceptance-sdk/press-keys.test.mjs +5 -19
- package/testdriver/acceptance-sdk/prompt.test.mjs +6 -18
- package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +6 -20
- package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +6 -18
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +9 -23
- package/testdriver/acceptance-sdk/scroll.test.mjs +12 -21
- package/testdriver/acceptance-sdk/setup/testHelpers.mjs +124 -352
- package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
- package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
- package/testdriver/acceptance-sdk/type.test.mjs +19 -58
- package/vitest.config.mjs +1 -0
- package/.vscode/mcp.json +0 -9
- package/MIGRATION.md +0 -389
- package/PLUGIN_MIGRATION.md +0 -222
- package/PROMPT_CACHE.md +0 -200
- package/SDK_LOGGING.md +0 -222
- package/SDK_MIGRATION.md +0 -474
- package/SDK_README.md +0 -1122
- package/debug-screenshot-1763401388589.png +0 -0
- package/examples/run-tests-with-recording.sh +0 -70
- package/examples/screenshot-example.js +0 -63
- package/examples/sdk-awesome-logs-demo.js +0 -177
- package/examples/sdk-cache-thresholds.js +0 -96
- package/examples/sdk-element-properties.js +0 -155
- package/examples/sdk-simple-example.js +0 -65
- package/examples/test-recording-example.test.js +0 -166
- package/mcp-server/AI_GUIDELINES.md +0 -57
- package/test-find-api.js +0 -73
- package/test-prompt-cache.js +0 -96
- package/test-sandbox-render.js +0 -28
- package/test-sdk-methods.js +0 -15
- package/test-sdk-refactor.js +0 -53
- package/test-stack-trace.mjs +0 -57
- package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
|
@@ -0,0 +1,292 @@
|
|
|
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
|
+
This provides:
|
|
13
|
+
- ⚡ **Up to 10x faster** - Skip AI vision analysis
|
|
14
|
+
- 💰 **Lower AI costs** - Fewer vision API calls
|
|
15
|
+
- 🎯 **Consistent results** - Same UI = same coordinates
|
|
16
|
+
- 📊 **Metrics tracking** - See cache hit rates in console
|
|
17
|
+
|
|
18
|
+
## How It Works
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
sequenceDiagram
|
|
22
|
+
participant Test as Your Test
|
|
23
|
+
participant SDK as TestDriver SDK
|
|
24
|
+
participant API as TestDriver API
|
|
25
|
+
participant AI as Claude Vision
|
|
26
|
+
participant Cache as Selector Cache DB
|
|
27
|
+
|
|
28
|
+
Test->>SDK: testdriver.find('submit button')
|
|
29
|
+
SDK->>API: POST /locate (screenshot + prompt)
|
|
30
|
+
|
|
31
|
+
API->>Cache: Check for matching cache entry
|
|
32
|
+
|
|
33
|
+
alt Cache Hit (95%+ similar screenshot)
|
|
34
|
+
Cache-->>API: Return cached coordinates
|
|
35
|
+
API-->>SDK: {x, y, cacheHit: true}
|
|
36
|
+
SDK-->>Test: Element found (instant)
|
|
37
|
+
else Cache Miss
|
|
38
|
+
API->>AI: Analyze screenshot
|
|
39
|
+
AI-->>API: Element coordinates
|
|
40
|
+
API->>Cache: Save new cache entry
|
|
41
|
+
API-->>SDK: {x, y, cacheHit: false}
|
|
42
|
+
SDK-->>Test: Element found
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Cache Matching Strategy
|
|
47
|
+
|
|
48
|
+
The selector cache uses a three-tier matching system:
|
|
49
|
+
|
|
50
|
+
1. **Exact Hash Match** (Fastest)
|
|
51
|
+
- Perceptual hash comparison
|
|
52
|
+
- Same screenshot = instant match
|
|
53
|
+
- 0% difference threshold
|
|
54
|
+
|
|
55
|
+
2. **Pixel Diff Match** (Fast)
|
|
56
|
+
- 80%+ perceptual hash similarity
|
|
57
|
+
- Pixel-by-pixel comparison
|
|
58
|
+
- Default 5% difference threshold (95% similarity)
|
|
59
|
+
- Configurable per call
|
|
60
|
+
|
|
61
|
+
3. **Template Match** (Fallback)
|
|
62
|
+
- Edge detection + template matching
|
|
63
|
+
- Finds visually similar UI elements
|
|
64
|
+
- 75%+ confidence threshold
|
|
65
|
+
|
|
66
|
+
## Controlling Cache Threshold
|
|
67
|
+
|
|
68
|
+
Adjust similarity threshold per call:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// Default: 95% similarity (5% difference allowed)
|
|
72
|
+
await testdriver.find('submit button');
|
|
73
|
+
|
|
74
|
+
// Stricter: 99% similarity (1% difference allowed)
|
|
75
|
+
await testdriver.find('submit button', { threshold: 0.01 });
|
|
76
|
+
|
|
77
|
+
// More lenient: 90% similarity (10% difference allowed)
|
|
78
|
+
await testdriver.find('submit button', { threshold: 0.10 });
|
|
79
|
+
|
|
80
|
+
// Disable cache: force fresh AI analysis
|
|
81
|
+
await testdriver.find('submit button', { threshold: -1 });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Cache Filtering
|
|
85
|
+
|
|
86
|
+
The selector cache automatically filters by:
|
|
87
|
+
|
|
88
|
+
- **Prompt** - Exact text match (case-insensitive)
|
|
89
|
+
- **Team** - Your team ID
|
|
90
|
+
- **OS** - Operating system (if specified)
|
|
91
|
+
- **Resolution** - Screen resolution (if specified)
|
|
92
|
+
- **Time Window** - Last 7 days by default
|
|
93
|
+
|
|
94
|
+
## Viewing Cache Entries
|
|
95
|
+
|
|
96
|
+
View all cached selectors at [console.testdriver.ai](https://console.testdriver.ai)
|
|
97
|
+
|
|
98
|
+
The console shows:
|
|
99
|
+
- Cached screenshots with green circles on found elements
|
|
100
|
+
- Original prompts
|
|
101
|
+
- Hit count (how many times cache was used)
|
|
102
|
+
- Similarity scores
|
|
103
|
+
- Cache age and last accessed time
|
|
104
|
+
|
|
105
|
+
## Cache Statistics
|
|
106
|
+
|
|
107
|
+
Each cache entry tracks:
|
|
108
|
+
|
|
109
|
+
- **Hit Count** - Number of times cache was used
|
|
110
|
+
- **Last Hit** - When cache was last accessed
|
|
111
|
+
- **Similarity** - Percentage match to original
|
|
112
|
+
- **Created At** - When entry was created
|
|
113
|
+
- **Element Type** - button, input, link, etc.
|
|
114
|
+
- **Element Bounds** - Bounding box coordinates
|
|
115
|
+
|
|
116
|
+
## Usage Examples
|
|
117
|
+
|
|
118
|
+
### Basic Selector Caching
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
import { test } from 'vitest';
|
|
122
|
+
import { chrome } from 'testdriverai/presets';
|
|
123
|
+
|
|
124
|
+
test('find element', async (context) => {
|
|
125
|
+
const { testdriver } = await chrome(context, {
|
|
126
|
+
url: 'https://example.com'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// First call: AI vision analysis, saves to cache
|
|
130
|
+
const button = await testdriver.find('More information link');
|
|
131
|
+
console.log('Cache hit:', button.cacheHit); // false
|
|
132
|
+
|
|
133
|
+
// Second call: uses cache (instant)
|
|
134
|
+
const button2 = await testdriver.find('More information link');
|
|
135
|
+
console.log('Cache hit:', button2.cacheHit); // true
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Dynamic Threshold Example
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
test('strict vs lenient matching', async (context) => {
|
|
143
|
+
const { testdriver } = await chrome(context, { url });
|
|
144
|
+
|
|
145
|
+
// Strict: 99% similarity required
|
|
146
|
+
const elem1 = await testdriver.find('button', { threshold: 0.01 });
|
|
147
|
+
|
|
148
|
+
// Lenient: 90% similarity acceptable
|
|
149
|
+
const elem2 = await testdriver.find('button', { threshold: 0.10 });
|
|
150
|
+
|
|
151
|
+
// Bypass cache entirely
|
|
152
|
+
const elem3 = await testdriver.find('button', { threshold: -1 });
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Checking Cache Hits
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
test('monitor cache performance', async (context) => {
|
|
160
|
+
const { testdriver } = await chrome(context, { url });
|
|
161
|
+
|
|
162
|
+
const element = await testdriver.find('submit button');
|
|
163
|
+
|
|
164
|
+
if (element.cacheHit) {
|
|
165
|
+
console.log('✅ Cache hit - instant response');
|
|
166
|
+
} else {
|
|
167
|
+
console.log('⏱️ Cache miss - AI analysis performed');
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Best Practices
|
|
173
|
+
|
|
174
|
+
### 1. Use Appropriate Thresholds
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Stable UI: strict threshold
|
|
178
|
+
await testdriver.find('logo', { threshold: 0.01 });
|
|
179
|
+
|
|
180
|
+
// Dynamic UI: lenient threshold
|
|
181
|
+
await testdriver.find('news feed item', { threshold: 0.10 });
|
|
182
|
+
|
|
183
|
+
// Always fresh: disable cache
|
|
184
|
+
await testdriver.find('timestamp', { threshold: -1 });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 2. Monitor Cache Performance
|
|
188
|
+
|
|
189
|
+
Check [console.testdriver.ai](https://console.testdriver.ai) regularly to:
|
|
190
|
+
- See cache hit rates
|
|
191
|
+
- Identify frequently used selectors
|
|
192
|
+
- Remove stale cache entries
|
|
193
|
+
- Optimize threshold settings
|
|
194
|
+
|
|
195
|
+
### 3. Clear Cache When UI Changes
|
|
196
|
+
|
|
197
|
+
If your UI changes significantly, delete cache entries through the console dashboard.
|
|
198
|
+
|
|
199
|
+
### 4. Use Consistent Prompts
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
// ✅ Good - consistent prompt
|
|
203
|
+
await testdriver.find('submit button');
|
|
204
|
+
await testdriver.find('submit button'); // Cache hit
|
|
205
|
+
|
|
206
|
+
// ❌ Bad - different prompts
|
|
207
|
+
await testdriver.find('submit button');
|
|
208
|
+
await testdriver.find('the submit button'); // Cache miss
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Cache Storage Details
|
|
212
|
+
|
|
213
|
+
| Property | Value |
|
|
214
|
+
|----------|-------|
|
|
215
|
+
| Location | Server (MongoDB + S3) |
|
|
216
|
+
| Persistence | 7 days default |
|
|
217
|
+
| Scope | Per-team |
|
|
218
|
+
| Matching | Screenshot similarity + prompt |
|
|
219
|
+
| Expiration | 7-day rolling window |
|
|
220
|
+
|
|
221
|
+
## Troubleshooting
|
|
222
|
+
|
|
223
|
+
### Cache Not Working
|
|
224
|
+
|
|
225
|
+
Check:
|
|
226
|
+
1. Threshold isn't too strict (try 0.10 for 90% similarity)
|
|
227
|
+
2. Screenshot hasn't changed significantly
|
|
228
|
+
3. OS/resolution matches cached entry
|
|
229
|
+
4. Cache entry isn't older than 7 days
|
|
230
|
+
5. Prompt matches exactly (case-insensitive)
|
|
231
|
+
|
|
232
|
+
### Low Cache Hit Rate
|
|
233
|
+
|
|
234
|
+
If you're seeing low cache hit rates:
|
|
235
|
+
|
|
236
|
+
1. **Increase threshold** - Try 0.10 (90% similarity) for dynamic UIs
|
|
237
|
+
2. **Stabilize UI** - Minimize animations, random data, timestamps
|
|
238
|
+
3. **Use consistent prompts** - Same wording every time
|
|
239
|
+
4. **Check console** - View similarity scores in dashboard
|
|
240
|
+
|
|
241
|
+
### Stale Cache Data
|
|
242
|
+
|
|
243
|
+
Delete selector cache entries at [console.testdriver.ai](https://console.testdriver.ai)
|
|
244
|
+
|
|
245
|
+
- Find the cached entry by prompt or screenshot
|
|
246
|
+
- Click delete to remove stale entries
|
|
247
|
+
- Run test again to create fresh cache
|
|
248
|
+
|
|
249
|
+
### Cache Misses on Identical UI
|
|
250
|
+
|
|
251
|
+
If cache misses occur on seemingly identical screens:
|
|
252
|
+
|
|
253
|
+
1. **Check resolution** - Cache is resolution-specific
|
|
254
|
+
2. **Check OS** - Cache is platform-specific
|
|
255
|
+
3. **Check pixel differences** - Even 1px changes can cause misses with strict thresholds
|
|
256
|
+
4. **Increase threshold** - Allow more similarity variance
|
|
257
|
+
|
|
258
|
+
## Advanced Configuration
|
|
259
|
+
|
|
260
|
+
### Environment Variables
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Disable selector cache entirely
|
|
264
|
+
TD_NO_SELECTOR_CACHE=1
|
|
265
|
+
|
|
266
|
+
# Set default threshold globally
|
|
267
|
+
TD_DEFAULT_THRESHOLD=0.10
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Per-Test Configuration
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
test('custom cache settings', async (context) => {
|
|
274
|
+
const { testdriver } = await chrome(context, {
|
|
275
|
+
url,
|
|
276
|
+
cacheDefaults: {
|
|
277
|
+
threshold: 0.10, // 90% similarity
|
|
278
|
+
enabled: true
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Uses custom defaults
|
|
283
|
+
await testdriver.find('button');
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## See Also
|
|
288
|
+
|
|
289
|
+
- [AI Prompt Caching](/v7/guides/caching-ai) - Cache AI-generated YAML
|
|
290
|
+
- [Console Dashboard](https://console.testdriver.ai) - View and manage selector cache
|
|
291
|
+
- [`.find()` Method](/v7/api/find) - Element location
|
|
292
|
+
- [Vitest Integration](/v7/guides/vitest) - Testing with TestDriver
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Caching"
|
|
3
|
+
sidebarTitle: "Caching"
|
|
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
|