@testdriverai/agent 7.11.229-canary → 7.11.231-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.
- package/docs/_data/examples-manifest.json +16 -16
- package/docs/_scripts/generate-examples.js +38 -45
- package/docs/agent.mdx +174 -93
- package/docs/assert.mdx +73 -269
- package/docs/aws-setup.mdx +196 -314
- package/docs/bring-your-own-machine.mdx +139 -206
- package/docs/cache.mdx +144 -151
- package/docs/caching.mdx +99 -89
- package/docs/captcha.mdx +126 -111
- package/docs/ci-cd.mdx +154 -543
- package/docs/click.mdx +74 -229
- package/docs/client.mdx +177 -231
- package/docs/copilot/auto-healing.mdx +86 -370
- package/docs/copilot/running-tests.mdx +121 -930
- package/docs/customizing-devices.mdx +74 -251
- package/docs/dashcam.mdx +72 -405
- package/docs/debugging-with-screenshots.mdx +105 -371
- package/docs/docs.json +75 -18
- package/docs/double-click.mdx +48 -68
- package/docs/errors.mdx +102 -176
- package/docs/events.mdx +170 -327
- package/docs/examples/{hover-text-with-description.mdx → add-to-cart.mdx} +30 -35
- package/docs/examples/assert.mdx +28 -41
- package/docs/examples/click-button.mdx +71 -0
- package/docs/examples/{hover-image.mdx → click-icon.mdx} +32 -28
- package/docs/examples/element-not-found.mdx +27 -26
- package/docs/examples/findall-coffee-icons.mdx +28 -32
- package/docs/examples/installer.mdx +61 -25
- package/docs/examples/launch-vscode-linux.mdx +28 -51
- package/docs/examples/navigate-and-scroll.mdx +82 -0
- package/docs/examples/parse.mdx +24 -28
- package/docs/examples/press-keys.mdx +28 -25
- package/docs/examples/scroll.mdx +25 -27
- package/docs/examples/type.mdx +26 -21
- package/docs/exec.mdx +92 -256
- package/docs/extract.mdx +69 -170
- package/docs/find.mdx +140 -736
- package/docs/focus-application.mdx +69 -246
- package/docs/generating-tests.mdx +103 -137
- package/docs/guide/best-practices-polling.mdx +65 -141
- package/docs/hosted.mdx +80 -144
- package/docs/hover.mdx +62 -235
- package/docs/locating-elements.mdx +74 -369
- package/docs/making-assertions.mdx +116 -74
- package/docs/mcp-setup.mdx +80 -63
- package/docs/mouse-down.mdx +48 -125
- package/docs/mouse-up.mdx +47 -129
- package/docs/options.mdx +75 -48
- package/docs/parse.mdx +95 -184
- package/docs/performing-actions.mdx +104 -94
- package/docs/press-keys.mdx +59 -299
- package/docs/provision.mdx +137 -182
- package/docs/quickstart-claude.mdx +85 -0
- package/docs/quickstart-github.mdx +62 -32
- package/docs/quickstart-manual.mdx +60 -33
- package/docs/quickstart-vscode.mdx +97 -0
- package/docs/quickstart.mdx +25 -9
- package/docs/redraw.mdx +101 -165
- package/docs/reusable-code.mdx +97 -200
- package/docs/right-click.mdx +47 -89
- package/docs/screenshot.mdx +47 -201
- package/docs/screenshots.mdx +87 -137
- package/docs/scroll.mdx +71 -154
- package/docs/secrets.mdx +96 -91
- package/docs/self-hosted.mdx +83 -142
- package/docs/snippets/enterprise.mdx +15 -0
- package/docs/styles.css +68 -0
- package/docs/test-results-json.mdx +167 -204
- package/docs/type.mdx +56 -304
- package/docs/variables.mdx +121 -81
- package/docs/wait.mdx +33 -31
- package/docs/what-is-testdriver.mdx +80 -32
- package/examples/{hover-text-with-description.test.mjs → add-to-cart.test.mjs} +4 -5
- package/examples/assert.test.mjs +3 -20
- package/examples/{hover-text.test.mjs → click-button.test.mjs} +3 -4
- package/examples/{hover-image.test.mjs → click-icon.test.mjs} +5 -6
- package/examples/element-not-found.test.mjs +3 -5
- package/examples/findall-coffee-icons.test.mjs +3 -3
- package/examples/installer.test.mjs +1 -1
- package/examples/launch-vscode-linux.test.mjs +6 -33
- package/examples/{scroll-keyboard.test.mjs → navigate-and-scroll.test.mjs} +4 -5
- package/examples/parse.test.mjs +1 -2
- package/examples/press-keys.test.mjs +4 -4
- package/examples/scroll.test.mjs +3 -6
- package/examples/type.test.mjs +5 -2
- package/lib/provision.js +6 -2
- package/package.json +1 -1
- package/sdk.d.ts +4 -2
- package/sdk.js +1 -1
- package/docs/claude-mcp-plugin.mdx +0 -244
- package/docs/elements.mdx +0 -606
- package/docs/examples/ai.mdx +0 -78
- package/docs/examples/captcha-api.mdx +0 -92
- package/docs/examples/chrome-extension.mdx +0 -156
- package/docs/examples/drag-and-drop.mdx +0 -100
- package/docs/examples/formatted-logging.mdx +0 -74
- package/docs/examples/hover-text.mdx +0 -70
- package/docs/examples/match-image.mdx +0 -97
- package/docs/examples/scroll-keyboard.mdx +0 -80
- package/docs/examples/scroll-until-text.mdx +0 -109
package/docs/cache.mdx
CHANGED
|
@@ -1,83 +1,53 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
sidebarTitle: "Configuring the
|
|
4
|
-
description: "
|
|
2
|
+
title: "Configure the cache"
|
|
3
|
+
sidebarTitle: "Configuring the cache"
|
|
4
|
+
description: "Every option that controls how find() and assert() reuse cached results."
|
|
5
5
|
icon: "bolt-lightning"
|
|
6
6
|
mode: "wide"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
This page lists every cache option, its default, and where you can set it. The cache is on by default, so you only need these to tune or turn it off.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The cache works at two levels:
|
|
14
|
-
- **Screen cache**: a pixel diff comparison between the present screenshot and the cached screenshot
|
|
15
|
-
- **Element cache**: OpenCV template matching to make sure that the cached element position is still correct
|
|
16
|
-
|
|
17
|
-
## How It Works
|
|
18
|
-
|
|
19
|
-
1. On `find()`, the SDK sends the present screenshot and the cache metadata to the API.
|
|
20
|
-
2. The API compares the screenshot against the cached results for the same `cacheKey`.
|
|
21
|
-
3. If the screen pixel diff is in the `screen` threshold AND the element template match is more than the `element` threshold, TestDriver returns the cached position.
|
|
22
|
-
4. If not, TestDriver makes a new AI call and caches the result.
|
|
23
|
-
|
|
24
|
-
```mermaid
|
|
25
|
-
flowchart LR
|
|
26
|
-
A[Screenshot + cacheKey] --> B{Screen Diff\n< threshold?}
|
|
27
|
-
B -- Yes --> C{Template\nMatch OK?}
|
|
28
|
-
C -- Yes --> D[Return cached position]
|
|
29
|
-
B -- No --> E[AI Call - fresh]
|
|
30
|
-
C -- No --> F[AI Call - fresh]
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Configuration
|
|
34
|
-
|
|
35
|
-
### Constructor Options
|
|
11
|
+
For how caching works and when it helps, see [Speed up reruns with caching](/caching).
|
|
36
12
|
|
|
37
13
|
```javascript
|
|
38
|
-
const testdriver =
|
|
14
|
+
const testdriver = TestDriver(context, {
|
|
39
15
|
cache: {
|
|
40
|
-
enabled: true,
|
|
41
16
|
thresholds: {
|
|
42
|
-
find: {
|
|
43
|
-
|
|
44
|
-
element: 0.8, // 80% OpenCV correlation required (default)
|
|
45
|
-
},
|
|
46
|
-
assert: 0.05, // 5% pixel diff for assertions (default)
|
|
17
|
+
find: { screen: 0.05, element: 0.8 },
|
|
18
|
+
assert: 0.05,
|
|
47
19
|
},
|
|
48
20
|
},
|
|
49
|
-
cacheKey: '
|
|
21
|
+
cacheKey: 'checkout-flow',
|
|
50
22
|
});
|
|
51
23
|
```
|
|
52
24
|
|
|
53
|
-
|
|
54
|
-
Cache configuration object, or `false` to disable entirely.
|
|
25
|
+
## Client options
|
|
55
26
|
|
|
56
|
-
|
|
57
|
-
<ParamField path="enabled" type="boolean" default={true}>
|
|
58
|
-
Enable or disable the cache system. Requires a valid `cacheKey` to actually activate.
|
|
59
|
-
</ParamField>
|
|
60
|
-
|
|
61
|
-
<ParamField path="thresholds" type="CacheThresholds">
|
|
62
|
-
Threshold configuration for different command types.
|
|
27
|
+
Pass these to `TestDriver(context, options)` or `new TestDriver(options)`. They apply to every call the client makes.
|
|
63
28
|
|
|
29
|
+
<ParamField path="cache" type="boolean | object" default="true">
|
|
30
|
+
Pass `false` to turn the cache off. Pass an object to change the match thresholds.
|
|
31
|
+
|
|
32
|
+
<Expandable title="properties">
|
|
33
|
+
<ParamField path="thresholds" type="object">
|
|
64
34
|
<Expandable title="properties">
|
|
65
|
-
<ParamField path="find" type="
|
|
35
|
+
<ParamField path="find" type="object">
|
|
66
36
|
Thresholds for `find()` and `findAll()`.
|
|
67
37
|
|
|
68
38
|
<Expandable title="properties">
|
|
69
|
-
<ParamField path="screen" type="number" default=
|
|
70
|
-
|
|
39
|
+
<ParamField path="screen" type="number" default="0.05">
|
|
40
|
+
The largest share of pixels that may differ between the current screen and the cached screen, from `0` to `1`. `0.05` allows a 5% difference. Lower values require a closer match.
|
|
71
41
|
</ParamField>
|
|
72
|
-
|
|
73
|
-
<ParamField path="element" type="number" default=
|
|
74
|
-
|
|
42
|
+
|
|
43
|
+
<ParamField path="element" type="number" default="0.8">
|
|
44
|
+
How closely the cached image of the element must match what's on screen now, from `0` to `1`. Higher values require a closer match. Used by `find()` only, not `findAll()`.
|
|
75
45
|
</ParamField>
|
|
76
46
|
</Expandable>
|
|
77
47
|
</ParamField>
|
|
78
|
-
|
|
79
|
-
<ParamField path="assert" type="number" default=
|
|
80
|
-
|
|
48
|
+
|
|
49
|
+
<ParamField path="assert" type="number" default="0.05">
|
|
50
|
+
The largest share of pixels that may differ for `assert()` to reuse a cached result, from `0` to `1`.
|
|
81
51
|
</ParamField>
|
|
82
52
|
</Expandable>
|
|
83
53
|
</ParamField>
|
|
@@ -85,139 +55,162 @@ const testdriver = new TestDriver({
|
|
|
85
55
|
</ParamField>
|
|
86
56
|
|
|
87
57
|
<ParamField path="cacheKey" type="string">
|
|
88
|
-
|
|
58
|
+
The key cache entries are stored under. By default, TestDriver generates one from the test file. See [Cache keys](#cache-keys).
|
|
59
|
+
</ParamField>
|
|
60
|
+
|
|
61
|
+
<ParamField path="cacheThreshold" type="object">
|
|
62
|
+
**Deprecated.** Use `cache.thresholds` instead.
|
|
89
63
|
</ParamField>
|
|
90
64
|
|
|
91
|
-
|
|
65
|
+
## Per-call options
|
|
92
66
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
67
|
+
Override the client settings for a single call.
|
|
68
|
+
|
|
69
|
+
### find()
|
|
96
70
|
|
|
97
|
-
|
|
98
|
-
|
|
71
|
+
```javascript
|
|
72
|
+
const priceLabel = await testdriver.find('Total price label', {
|
|
73
|
+
cacheKey: 'checkout-flow',
|
|
74
|
+
cache: { thresholds: { screen: 0.01, element: 0.95 } },
|
|
75
|
+
});
|
|
99
76
|
```
|
|
100
77
|
|
|
101
|
-
|
|
78
|
+
<ParamField path="cacheKey" type="string">
|
|
79
|
+
Use this key for this call instead of the client's key.
|
|
80
|
+
</ParamField>
|
|
102
81
|
|
|
103
|
-
|
|
82
|
+
<ParamField path="cache.thresholds.screen" type="number">
|
|
83
|
+
Overrides `cache.thresholds.find.screen` for this call.
|
|
84
|
+
</ParamField>
|
|
104
85
|
|
|
105
|
-
|
|
86
|
+
<ParamField path="cache.thresholds.element" type="number">
|
|
87
|
+
Overrides `cache.thresholds.find.element` for this call.
|
|
88
|
+
</ParamField>
|
|
89
|
+
|
|
90
|
+
### findAll()
|
|
91
|
+
|
|
92
|
+
`findAll()` takes `cacheKey` and `cache.thresholds.screen`. It doesn't use the `element` threshold.
|
|
106
93
|
|
|
107
94
|
```javascript
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
cache: {
|
|
111
|
-
thresholds: { screen: 0.01, element: 0.95 },
|
|
112
|
-
},
|
|
95
|
+
const productCards = await testdriver.findAll('Product card in the results grid', {
|
|
96
|
+
cache: { thresholds: { screen: 0.02 } },
|
|
113
97
|
});
|
|
98
|
+
```
|
|
114
99
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
100
|
+
### assert()
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
await testdriver.assert('the order confirmation is visible', {
|
|
104
|
+
cacheKey: 'checkout-flow',
|
|
105
|
+
threshold: 0.01,
|
|
119
106
|
});
|
|
120
107
|
```
|
|
121
108
|
|
|
122
|
-
|
|
109
|
+
<ParamField path="cacheKey" type="string">
|
|
110
|
+
Use this key for this call instead of the client's key.
|
|
111
|
+
</ParamField>
|
|
123
112
|
|
|
124
|
-
|
|
113
|
+
<ParamField path="threshold" type="number">
|
|
114
|
+
Overrides `cache.thresholds.assert` for this call.
|
|
115
|
+
</ParamField>
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
|----------|--------|---------|
|
|
128
|
-
| 1 (highest) | Per-command option | `find(desc, { cache: { thresholds: { screen: 0.1 } } })` |
|
|
129
|
-
| 2 | Legacy number argument | `find(desc, 0.1)` |
|
|
130
|
-
| 3 | Global constructor config | `new TestDriver({ cache: { thresholds: { find: { screen: 0.1 } } } })` |
|
|
131
|
-
| 4 (lowest) | Hard-coded defaults | `screen: 0.05`, `element: 0.8`, `assert: 0.05` |
|
|
117
|
+
## Threshold priority
|
|
132
118
|
|
|
133
|
-
|
|
119
|
+
When a threshold is set in more than one place, the most specific wins:
|
|
134
120
|
|
|
135
|
-
|
|
121
|
+
1. The per-call option, such as `find(description, { cache: { thresholds: { screen: 0.1 } } })`
|
|
122
|
+
2. A legacy number argument, such as `find(description, 0.1)`
|
|
123
|
+
3. The client option, `cache.thresholds`
|
|
124
|
+
4. The defaults: `screen` 0.05, `element` 0.8, `assert` 0.05
|
|
136
125
|
|
|
137
|
-
|
|
138
|
-
2. Reads the file content
|
|
139
|
-
3. Computes a **SHA-256 hash** of the content
|
|
140
|
-
4. Uses the **first 16 hex characters** as the cache key
|
|
126
|
+
## Cache keys
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
- **Same test file** → same cache key → cache hits
|
|
144
|
-
- **Modified test file** → different hash → automatic cache invalidation
|
|
145
|
-
- **Different test files** → different keys → isolated caches
|
|
128
|
+
Cache entries are stored under a key. By default, TestDriver generates the key from the test file:
|
|
146
129
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
130
|
+
- It hashes the contents of the file that creates the client (SHA-256, first 16 hex characters).
|
|
131
|
+
- Editing the file changes the hash, so the file starts with a fresh cache.
|
|
132
|
+
- Each test file gets its own cache.
|
|
133
|
+
|
|
134
|
+
Set `cacheKey` to keep a cache across edits, or to share one between files that use the same screens:
|
|
151
135
|
|
|
152
|
-
|
|
153
|
-
const testdriver =
|
|
136
|
+
```javascript
|
|
137
|
+
const testdriver = TestDriver(context, { cacheKey: 'checkout-flow' });
|
|
154
138
|
```
|
|
155
139
|
|
|
156
|
-
|
|
140
|
+
If TestDriver can't read the test file, it can't generate a key. `find()` and `findAll()` then skip the cache unless you set `cacheKey`.
|
|
157
141
|
|
|
158
|
-
|
|
142
|
+
## What must match
|
|
159
143
|
|
|
160
|
-
|
|
161
|
-
1. Load the cached element crop (needle) and current screenshot (haystack)
|
|
162
|
-
2. Run `cv.matchTemplate()` with `TM_CCOEFF_NORMED`
|
|
163
|
-
3. Binary threshold at the configured element threshold
|
|
164
|
-
4. Find contours to extract match positions
|
|
165
|
-
5. Return matches with `{ x, y, width, height, centerX, centerY }`
|
|
144
|
+
A cached entry is reused only when all of these match the run that created it:
|
|
166
145
|
|
|
167
|
-
|
|
168
|
-
|
|
146
|
+
- The cache key.
|
|
147
|
+
- The exact description passed to `find()`, or the exact assertion text.
|
|
148
|
+
- The sandbox OS and screen resolution.
|
|
169
149
|
|
|
170
|
-
|
|
150
|
+
Entries become usable only after the test that created them passes.
|
|
171
151
|
|
|
172
|
-
##
|
|
152
|
+
## Turn the cache off
|
|
173
153
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
154
|
+
Turn the cache off for one client:
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
const testdriver = TestDriver(context, { cache: false });
|
|
158
|
+
```
|
|
178
159
|
|
|
179
|
-
|
|
160
|
+
Or for a whole run:
|
|
180
161
|
|
|
181
|
-
|
|
162
|
+
```bash
|
|
163
|
+
TD_NO_CACHE=true npx vitest run
|
|
164
|
+
```
|
|
182
165
|
|
|
183
|
-
|
|
166
|
+
<Warning>
|
|
167
|
+
`cache: { enabled: false }` doesn't turn the cache off. Use `cache: false` or `TD_NO_CACHE=true`.
|
|
168
|
+
</Warning>
|
|
184
169
|
|
|
185
|
-
|
|
186
|
-
|---|---|
|
|
187
|
-
| `cacheHit` | `true` if cache was used |
|
|
188
|
-
| `similarity` | Pixel diff percentage between screenshots |
|
|
189
|
-
| `cacheSimilarity` | OpenCV template match score |
|
|
170
|
+
## Inspect a result
|
|
190
171
|
|
|
191
|
-
|
|
172
|
+
Read the cache details from the element that `find()` returns:
|
|
192
173
|
|
|
193
174
|
```javascript
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
console.log(debug);
|
|
197
|
-
// { cacheHit: true, similarity: 0.02, cacheSimilarity: 0.92, ... }
|
|
175
|
+
const submitButton = await testdriver.find('Submit button');
|
|
176
|
+
const { cache } = submitButton.toJSON();
|
|
198
177
|
```
|
|
199
178
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
179
|
+
<ResponseField name="cache" type="object">
|
|
180
|
+
<Expandable title="properties">
|
|
181
|
+
<ResponseField name="hit" type="boolean">
|
|
182
|
+
`true` when the location came from the cache.
|
|
183
|
+
</ResponseField>
|
|
184
|
+
<ResponseField name="strategy" type="string">
|
|
185
|
+
How the cached entry was matched.
|
|
186
|
+
</ResponseField>
|
|
187
|
+
<ResponseField name="createdAt" type="string">
|
|
188
|
+
When the cached entry was created.
|
|
189
|
+
</ResponseField>
|
|
190
|
+
<ResponseField name="diffPercent" type="number">
|
|
191
|
+
The share of pixels that differed between the current screen and the cached screen, from `0` to `1`.
|
|
192
|
+
</ResponseField>
|
|
193
|
+
<ResponseField name="imageUrl" type="string">
|
|
194
|
+
A link to the cached screenshot.
|
|
195
|
+
</ResponseField>
|
|
196
|
+
</Expandable>
|
|
197
|
+
</ResponseField>
|
|
198
|
+
|
|
199
|
+
To browse or clear your team's cached entries, open the [Cache page in the TestDriver console](https://console.testdriver.ai/cache).
|
|
200
|
+
|
|
201
|
+
## Related
|
|
202
|
+
|
|
203
|
+
<CardGroup cols={2}>
|
|
204
|
+
<Card title="Caching" icon="brain" href="/caching">
|
|
205
|
+
How the cache works and when it helps.
|
|
206
|
+
</Card>
|
|
207
|
+
<Card title="Options" icon="sliders" href="/options">
|
|
208
|
+
Every client option, with its default.
|
|
209
|
+
</Card>
|
|
210
|
+
<Card title="find()" icon="magnifying-glass" href="/find">
|
|
211
|
+
Locate an element by describing it.
|
|
212
|
+
</Card>
|
|
213
|
+
<Card title="assert()" icon="check" href="/assert">
|
|
214
|
+
Check the screen with an AI assertion.
|
|
215
|
+
</Card>
|
|
216
|
+
</CardGroup>
|
package/docs/caching.mdx
CHANGED
|
@@ -1,133 +1,143 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
sidebarTitle: "
|
|
4
|
-
description: "
|
|
2
|
+
title: "Speed up reruns with caching"
|
|
3
|
+
sidebarTitle: "Caching"
|
|
4
|
+
description: "Reuse element locations from passing runs to skip the AI when the screen is unchanged."
|
|
5
5
|
icon: "brain"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
After
|
|
8
|
+
After a test passes, TestDriver remembers where it found each element.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
- When the screen looks the same on a later run, `find()` reuses that location instead of asking the AI.
|
|
11
|
+
- The step is faster, cheaper, and gives the same result every time.
|
|
12
|
+
- When the screen changes, TestDriver falls back to the AI and learns the new location.
|
|
11
13
|
|
|
14
|
+
Caching is on by default. You don't need to configure anything.
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
// First run: builds cache
|
|
15
|
-
await testdriver.find('submit button');
|
|
16
|
+
## How caching works
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
1. **The first run learns.** Each `find()` asks the AI to locate the element. TestDriver saves the result with an image of the screen and of the element.
|
|
19
|
+
2. **A passing run confirms.** Saved entries become usable only once the test passes. A failing run never teaches TestDriver a wrong location.
|
|
20
|
+
3. **Later runs reuse.** On the next run, `find()` compares the current screen with the saved one. TestDriver returns the saved location without calling the AI when both are true:
|
|
21
|
+
- The screen differs by no more than 5% of its pixels.
|
|
22
|
+
- The saved image of the element still matches what's at that spot.
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
Otherwise, it asks the AI and saves a new entry.
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
`assert()` is cached the same way. When the screen matches a confirmed earlier run, the saved result is reused.
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
- **Selector prompt**: The exact text description that you give to `find()`
|
|
27
|
-
- **Screenshot context**: The perceptual hash of the present screen state
|
|
28
|
-
- **Platform**: The operating system and the browser version
|
|
28
|
+
## What has to match
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
A saved entry is reused only when all of these match the run that created it:
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
- **The test file.** The cache is keyed on a hash of the test file's contents, so editing the file starts a fresh cache. A changed test can't reuse results that no longer apply.
|
|
33
|
+
- **The description.** The text you pass to `find()` must match exactly.
|
|
34
|
+
- **The OS and screen resolution** of the sandbox.
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
const { testdriver } = await chrome(context, {
|
|
38
|
-
url: 'https://example.com'
|
|
39
|
-
});
|
|
36
|
+
## Keep changing values out of descriptions
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
await testdriver.find('More information link'); // 2.1s
|
|
38
|
+
The description must match exactly. A description with a value that changes between runs misses the cache every time:
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
40
|
+
```javascript
|
|
41
|
+
// Misses the cache whenever the email changes
|
|
42
|
+
const emailField = await testdriver.find(`input next to ${email}`);
|
|
47
43
|
```
|
|
48
44
|
|
|
49
|
-
|
|
45
|
+
Describe the element itself, and pass the changing value to the action instead:
|
|
50
46
|
|
|
51
|
-
|
|
47
|
+
```javascript
|
|
48
|
+
// Same description every run, so it can be cached
|
|
49
|
+
const emailField = await testdriver.find('Email input field');
|
|
50
|
+
await emailField.click();
|
|
51
|
+
await testdriver.type(email);
|
|
52
|
+
```
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
Manage and clear your test cache from the TestDriver console.
|
|
55
|
-
</Card>
|
|
54
|
+
## Choose your own cache key
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
By default, each test file has its own cache, which resets when you edit the file.
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
Set a `cacheKey` when you create the client to keep the cache across edits, or to share it between files that use the same screens:
|
|
60
59
|
|
|
61
60
|
```javascript
|
|
62
|
-
|
|
63
|
-
const { testdriver } = await chrome(context, { url });
|
|
64
|
-
|
|
65
|
-
const element = await testdriver.find('submit button');
|
|
66
|
-
|
|
67
|
-
if (element.cacheHit) {
|
|
68
|
-
console.log('✅ Cache hit - instant response');
|
|
69
|
-
console.log('Strategy:', element.cacheStrategy); // 'exact', 'pixeldiff', or 'template'
|
|
70
|
-
console.log('Similarity:', `${(element.similarity * 100).toFixed(1)}%`);
|
|
71
|
-
console.log('Cache age:', element.cacheCreatedAt);
|
|
72
|
-
} else {
|
|
73
|
-
console.log('⏱️ Cache miss - AI analysis performed');
|
|
74
|
-
console.log('New cache entry created');
|
|
75
|
-
}
|
|
76
|
-
});
|
|
61
|
+
const testdriver = TestDriver(context, { cacheKey: 'checkout-flow' });
|
|
77
62
|
```
|
|
78
63
|
|
|
79
|
-
|
|
64
|
+
You can also pass `cacheKey` to a single `find()` call.
|
|
65
|
+
|
|
66
|
+
A stable key doesn't make TestDriver reuse a location for a changed page. Entries are still reused only when the description, OS, and resolution match and the screen looks the same.
|
|
67
|
+
|
|
68
|
+
## Adjust how closely the screen must match
|
|
80
69
|
|
|
81
|
-
|
|
70
|
+
Two thresholds control when a saved location is reused:
|
|
71
|
+
|
|
72
|
+
| Threshold | Default | Meaning |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `screen` | `0.05` | The largest share of pixels that may differ from the saved screen (5%) |
|
|
75
|
+
| `element` | `0.8` | How closely the saved element image must match what's on screen now (0 to 1) |
|
|
76
|
+
|
|
77
|
+
Set them for every call when you create the client:
|
|
82
78
|
|
|
83
79
|
```javascript
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
80
|
+
const testdriver = TestDriver(context, {
|
|
81
|
+
cache: {
|
|
82
|
+
thresholds: {
|
|
83
|
+
find: { screen: 0.02, element: 0.9 },
|
|
84
|
+
assert: 0.02,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
92
87
|
});
|
|
93
88
|
```
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
Or override them for one call:
|
|
96
91
|
|
|
97
92
|
```javascript
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// Explicit strict threshold
|
|
102
|
-
await testdriver.find('submit button', {
|
|
103
|
-
cacheThreshold: 0.01 // 99% similarity
|
|
93
|
+
const priceLabel = await testdriver.find('Total price label', {
|
|
94
|
+
cache: { thresholds: { screen: 0.01 } },
|
|
104
95
|
});
|
|
105
96
|
```
|
|
106
97
|
|
|
107
|
-
|
|
98
|
+
Lower `screen` and higher `element` values make reuse stricter. That helps on screens where small details matter, but costs more AI calls.
|
|
108
99
|
|
|
109
|
-
|
|
100
|
+
For every cache option, see [Configure the cache](/cache).
|
|
101
|
+
|
|
102
|
+
## Turn caching off
|
|
103
|
+
|
|
104
|
+
Disable caching for a client with `cache: false`, or for a whole run with `TD_NO_CACHE`:
|
|
110
105
|
|
|
111
106
|
```javascript
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
await testdriver.find(`input for ${email}`); // Cache miss every time
|
|
115
|
-
|
|
116
|
-
// ✅ With cache key - reuses cache regardless of variable
|
|
117
|
-
const email = 'user@example.com';
|
|
118
|
-
await testdriver.find(`input for ${email}`, {
|
|
119
|
-
cacheKey: 'email-input'
|
|
120
|
-
});
|
|
107
|
+
const testdriver = TestDriver(context, { cache: false });
|
|
108
|
+
```
|
|
121
109
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await testdriver.find(`order ${orderId} status`, {
|
|
125
|
-
cacheKey: 'order-status' // Same cache for all orders
|
|
126
|
-
});
|
|
110
|
+
```bash
|
|
111
|
+
TD_NO_CACHE=true npx vitest run
|
|
127
112
|
```
|
|
128
113
|
|
|
129
|
-
##
|
|
114
|
+
## See what's cached
|
|
115
|
+
|
|
116
|
+
The [Cache page in the TestDriver console](https://console.testdriver.ai/cache) lists your team's cached elements and assertions. It shows a preview and the description for each, and lets you clear entries.
|
|
117
|
+
|
|
118
|
+
To check a single `find()` in your test, read the cache details from the element:
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
const submitButton = await testdriver.find('Submit button');
|
|
122
|
+
const { cache } = submitButton.toJSON();
|
|
123
|
+
|
|
124
|
+
console.log(cache.hit); // true when the location came from the cache
|
|
125
|
+
console.log(cache.strategy); // how the cached entry was matched
|
|
126
|
+
```
|
|
130
127
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
## Next steps
|
|
129
|
+
|
|
130
|
+
<CardGroup cols={2}>
|
|
131
|
+
<Card title="Configure the cache" icon="sliders" href="/cache">
|
|
132
|
+
Every cache option, threshold, and override.
|
|
133
|
+
</Card>
|
|
134
|
+
<Card title="Locate elements" icon="crosshairs" href="/locating-elements">
|
|
135
|
+
Write descriptions that find the right element and cache well.
|
|
136
|
+
</Card>
|
|
137
|
+
<Card title="Run tests" icon="play" href="/copilot/running-tests">
|
|
138
|
+
Run your tests locally and in parallel.
|
|
139
|
+
</Card>
|
|
140
|
+
<Card title="Run in CI/CD" icon="code-branch" href="/ci-cd">
|
|
141
|
+
Run cached tests on every pull request.
|
|
142
|
+
</Card>
|
|
143
|
+
</CardGroup>
|