@testdriverai/agent 7.11.229-test → 7.11.232-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 (100) hide show
  1. package/docs/_data/examples-manifest.json +16 -16
  2. package/docs/_scripts/generate-examples.js +38 -45
  3. package/docs/agent.mdx +174 -93
  4. package/docs/assert.mdx +73 -269
  5. package/docs/aws-setup.mdx +196 -314
  6. package/docs/bring-your-own-machine.mdx +139 -206
  7. package/docs/cache.mdx +144 -151
  8. package/docs/caching.mdx +99 -89
  9. package/docs/captcha.mdx +126 -111
  10. package/docs/ci-cd.mdx +154 -543
  11. package/docs/click.mdx +74 -229
  12. package/docs/client.mdx +177 -231
  13. package/docs/copilot/auto-healing.mdx +86 -370
  14. package/docs/copilot/running-tests.mdx +121 -930
  15. package/docs/customizing-devices.mdx +74 -251
  16. package/docs/dashcam.mdx +72 -405
  17. package/docs/debugging-with-screenshots.mdx +105 -371
  18. package/docs/docs.json +79 -22
  19. package/docs/double-click.mdx +48 -68
  20. package/docs/errors.mdx +102 -176
  21. package/docs/events.mdx +170 -327
  22. package/docs/examples/{hover-text-with-description.mdx → add-to-cart.mdx} +30 -35
  23. package/docs/examples/assert.mdx +28 -41
  24. package/docs/examples/click-button.mdx +71 -0
  25. package/docs/examples/{hover-image.mdx → click-icon.mdx} +32 -28
  26. package/docs/examples/element-not-found.mdx +27 -26
  27. package/docs/examples/findall-coffee-icons.mdx +28 -32
  28. package/docs/examples/installer.mdx +61 -25
  29. package/docs/examples/launch-vscode-linux.mdx +28 -51
  30. package/docs/examples/navigate-and-scroll.mdx +82 -0
  31. package/docs/examples/parse.mdx +24 -28
  32. package/docs/examples/press-keys.mdx +28 -25
  33. package/docs/examples/scroll.mdx +25 -27
  34. package/docs/examples/type.mdx +26 -21
  35. package/docs/exec.mdx +92 -256
  36. package/docs/extract.mdx +69 -170
  37. package/docs/find.mdx +140 -736
  38. package/docs/focus-application.mdx +69 -246
  39. package/docs/generating-tests.mdx +103 -137
  40. package/docs/guide/best-practices-polling.mdx +65 -141
  41. package/docs/hosted.mdx +80 -144
  42. package/docs/hover.mdx +62 -235
  43. package/docs/locating-elements.mdx +74 -369
  44. package/docs/making-assertions.mdx +116 -74
  45. package/docs/mcp-setup.mdx +80 -63
  46. package/docs/mouse-down.mdx +48 -125
  47. package/docs/mouse-up.mdx +47 -129
  48. package/docs/options.mdx +75 -48
  49. package/docs/parse.mdx +95 -184
  50. package/docs/performing-actions.mdx +104 -94
  51. package/docs/press-keys.mdx +59 -299
  52. package/docs/provision.mdx +137 -182
  53. package/docs/quickstart-claude.mdx +85 -0
  54. package/docs/quickstart-github.mdx +62 -32
  55. package/docs/quickstart-manual.mdx +60 -33
  56. package/docs/quickstart-vscode.mdx +97 -0
  57. package/docs/quickstart.mdx +26 -9
  58. package/docs/redraw.mdx +101 -165
  59. package/docs/reusable-code.mdx +97 -200
  60. package/docs/right-click.mdx +47 -89
  61. package/docs/screenshot.mdx +47 -201
  62. package/docs/screenshots.mdx +87 -137
  63. package/docs/scroll.mdx +71 -154
  64. package/docs/secrets.mdx +96 -91
  65. package/docs/self-hosted.mdx +83 -142
  66. package/docs/snippets/enterprise.mdx +15 -0
  67. package/docs/styles.css +68 -0
  68. package/docs/test-results-json.mdx +167 -204
  69. package/docs/type.mdx +56 -304
  70. package/docs/variables.mdx +121 -81
  71. package/docs/wait.mdx +33 -31
  72. package/docs/what-is-testdriver.mdx +80 -32
  73. package/examples/{hover-text-with-description.test.mjs → add-to-cart.test.mjs} +4 -5
  74. package/examples/assert.test.mjs +3 -20
  75. package/examples/{hover-text.test.mjs → click-button.test.mjs} +3 -4
  76. package/examples/{hover-image.test.mjs → click-icon.test.mjs} +5 -6
  77. package/examples/element-not-found.test.mjs +3 -5
  78. package/examples/findall-coffee-icons.test.mjs +3 -3
  79. package/examples/installer.test.mjs +1 -1
  80. package/examples/launch-vscode-linux.test.mjs +6 -33
  81. package/examples/{scroll-keyboard.test.mjs → navigate-and-scroll.test.mjs} +4 -5
  82. package/examples/parse.test.mjs +1 -2
  83. package/examples/press-keys.test.mjs +4 -4
  84. package/examples/scroll.test.mjs +3 -6
  85. package/examples/type.test.mjs +5 -2
  86. package/lib/provision.js +6 -2
  87. package/package.json +1 -1
  88. package/sdk.d.ts +4 -2
  89. package/sdk.js +1 -1
  90. package/docs/claude-mcp-plugin.mdx +0 -244
  91. package/docs/elements.mdx +0 -606
  92. package/docs/examples/ai.mdx +0 -78
  93. package/docs/examples/captcha-api.mdx +0 -92
  94. package/docs/examples/chrome-extension.mdx +0 -156
  95. package/docs/examples/drag-and-drop.mdx +0 -100
  96. package/docs/examples/formatted-logging.mdx +0 -74
  97. package/docs/examples/hover-text.mdx +0 -70
  98. package/docs/examples/match-image.mdx +0 -97
  99. package/docs/examples/scroll-keyboard.mdx +0 -80
  100. package/docs/examples/scroll-until-text.mdx +0 -109
package/docs/cache.mdx CHANGED
@@ -1,83 +1,53 @@
1
1
  ---
2
- title: "Cache"
3
- sidebarTitle: "Configuring the Cache"
4
- description: "Speed up tests with screenshot-based caching"
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
- ## Overview
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
- The cache system makes repeated test runs faster. It compares screenshots to cached results. When the screen did not change much, TestDriver uses the cached element positions again. It does not make an AI call.
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 = new TestDriver({
14
+ const testdriver = TestDriver(context, {
39
15
  cache: {
40
- enabled: true,
41
16
  thresholds: {
42
- find: {
43
- screen: 0.05, // 5% pixel diff allowed (default)
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: 'my-custom-key', // overrides auto-generated key
21
+ cacheKey: 'checkout-flow',
50
22
  });
51
23
  ```
52
24
 
53
- <ParamField path="cache" type="CacheConfig | false">
54
- Cache configuration object, or `false` to disable entirely.
25
+ ## Client options
55
26
 
56
- <Expandable title="properties">
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="FindCacheThresholds">
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={0.05}>
70
- Maximum pixel diff percentage allowed between the current screenshot and the cached screenshot. Lower values require a closer match. Range: `0` to `1`.
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={0.8}>
74
- Minimum OpenCV template matching correlation required for the cached element crop. Higher values require a closer match. Range: `0` to `1`. Only used for `find()`, not `findAll()`.
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={0.05}>
80
- Maximum pixel diff allowed for assertion cache hits.
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
- Unique key for cache lookups. If not provided, an auto-generated key is created from a SHA-256 hash of the calling test file (first 16 hex characters). The cache key changes automatically when your test file changes, providing automatic cache invalidation.
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
- ### Disabling Cache
65
+ ## Per-call options
92
66
 
93
- ```javascript
94
- // Via constructor
95
- const testdriver = new TestDriver({ cache: false });
67
+ Override the client settings for a single call.
68
+
69
+ ### find()
96
70
 
97
- // Via environment variable
98
- // TD_NO_CACHE=true vitest run
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
- When cache is disabled, all thresholds are set to `-1` internally, causing the API to skip cache lookups.
78
+ <ParamField path="cacheKey" type="string">
79
+ Use this key for this call instead of the client's key.
80
+ </ParamField>
102
81
 
103
- ### Per-Command Overrides
82
+ <ParamField path="cache.thresholds.screen" type="number">
83
+ Overrides `cache.thresholds.find.screen` for this call.
84
+ </ParamField>
104
85
 
105
- Override cache thresholds for individual commands:
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
- // Stricter screen matching for this specific find
109
- const el = await testdriver.find('submit button', {
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
- // Custom cache key for a specific assertion
116
- await testdriver.assert('dashboard loaded', {
117
- cache: { threshold: 0.01 },
118
- cacheKey: 'dashboard-check',
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
- ## Threshold Priority
109
+ <ParamField path="cacheKey" type="string">
110
+ Use this key for this call instead of the client's key.
111
+ </ParamField>
123
112
 
124
- Thresholds are resolved in priority order (highest wins):
113
+ <ParamField path="threshold" type="number">
114
+ Overrides `cache.thresholds.assert` for this call.
115
+ </ParamField>
125
116
 
126
- | Priority | Source | Example |
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
- ## Auto-Generated Cache Key
119
+ When a threshold is set in more than one place, the most specific wins:
134
120
 
135
- When you don't specify a `cacheKey`, the SDK automatically generates one:
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
- 1. Walks the call stack to find your test file
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
- This means:
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
- ```javascript
148
- // Auto-generated cache key from test file hash
149
- const testdriver = new TestDriver();
150
- // cacheKey = "a3f2b1c4d5e6f7a8" (auto)
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
- // Manual override
153
- const testdriver = new TestDriver({ cacheKey: 'login-test-v2' });
136
+ ```javascript
137
+ const testdriver = TestDriver(context, { cacheKey: 'checkout-flow' });
154
138
  ```
155
139
 
156
- ## Template Matching (OpenCV)
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
- Element cache validation uses OpenCV's normalized cross-correlation coefficient (`TM_CCOEFF_NORMED`) to verify that the cached element is still visible at the expected position.
142
+ ## What must match
159
143
 
160
- **Algorithm:**
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
- **Scale factors tried:** `[1, 0.5, 2, 0.75, 1.25, 1.5]`
168
- **Thresholds tried:** `[0.9, 0.8, 0.7]` (picks highest matching threshold)
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
- This accounts for minor scaling differences between screenshots taken at different times or resolutions.
150
+ Entries become usable only after the test that created them passes.
171
151
 
172
- ## Cache Partitioning
152
+ ## Turn the cache off
173
153
 
174
- Cache entries are partitioned by:
175
- - **`cacheKey`** — identifies the test file
176
- - **`os`** — operating system (linux, windows, darwin)
177
- - **`resolution`** — screen resolution
154
+ Turn the cache off for one client:
155
+
156
+ ```javascript
157
+ const testdriver = TestDriver(context, { cache: false });
158
+ ```
178
159
 
179
- This means cache from a Linux run won't be used for a Windows run, even with the same cache key.
160
+ Or for a whole run:
180
161
 
181
- ## Debugging Cache
162
+ ```bash
163
+ TD_NO_CACHE=true npx vitest run
164
+ ```
182
165
 
183
- API responses include cache metadata:
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
- | Field | Description |
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
- Use `getDebugInfo()` on an element to inspect cache results:
172
+ Read the cache details from the element that `find()` returns:
192
173
 
193
174
  ```javascript
194
- const el = await testdriver.find('submit button');
195
- const debug = el.getDebugInfo();
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
- ## Types
201
-
202
- ```typescript
203
- interface CacheConfig {
204
- enabled?: boolean; // Default: true
205
- thresholds?: CacheThresholds;
206
- }
207
-
208
- interface CacheThresholds {
209
- find?: FindCacheThresholds;
210
- assert?: number; // Default: 0.05
211
- }
212
-
213
- interface FindCacheThresholds {
214
- screen?: number; // Default: 0.05
215
- element?: number; // Default: 0.8
216
- }
217
-
218
- interface CacheDebugInfo {
219
- cacheHit: boolean;
220
- similarity: number;
221
- cacheSimilarity: number;
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: "Self-Learning"
3
- sidebarTitle: "Self-Learning"
4
- description: "How TestDriver learns your app and caches what it discovers for instant, deterministic replays"
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 the agent [explored your app](/generating-tests), TestDriver keeps what it found. TestDriver caches each element that the AI vision agent finds. It uses a vision fingerprint. This is a perceptual hash of the screen state at the element location. On the next run, TestDriver matches against that cache. It does not call the AI again. Tests that pass replay quickly, in the same way each time, and at a low cost.
8
+ After a test passes, TestDriver remembers where it found each element.
9
9
 
10
- This learning makes TestDriver fast. The cache makes the test run a maximum of **1.7x faster**. It does not do the same AI vision analysis again. The agent thinks only when it sees something new.
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
- ```javascript
14
- // First run: builds cache
15
- await testdriver.find('submit button');
16
+ ## How caching works
16
17
 
17
- // Second run: exact match
18
- await testdriver.find('submit button');
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
- ## Automatic Caching
24
+ Otherwise, it asks the AI and saves a new entry.
22
25
 
23
- TestDriver enables learning automatically. You do not need configuration. TestDriver computes the cache key from these. The cache key is the fingerprint that TestDriver uses to know what it learned:
26
+ `assert()` is cached the same way. When the screen matches a confirmed earlier run, the saved result is reused.
24
27
 
25
- - **File hash**: The SHA-256 hash of the test file contents
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
- When you change your test file, the hash changes automatically. This makes the old cache entries not valid. Then TestDriver does a new AI analysis with your new test logic.
30
+ A saved entry is reused only when all of these match the run that created it:
31
31
 
32
- ```javascript
33
- import { test } from 'vitest';
34
- import { chrome } from 'testdriverai/presets';
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
- test('auto-cached test', async (context) => {
37
- const { testdriver } = await chrome(context, {
38
- url: 'https://example.com'
39
- });
36
+ ## Keep changing values out of descriptions
40
37
 
41
- // First call: AI analyzes screen, saves to cache
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
- // Second call: cache hit, instant response
45
- await testdriver.find('More information link'); // 12ms ⚡
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
- ## Managing the Cache
45
+ Describe the element itself, and pass the changing value to the action instead:
50
46
 
51
- You can clear the cache in the TestDriver console. There, you also find previews of cached elements, the input prompts, and analytics on the cache hit rates.
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
- <Card href="https://console.testdriver.ai/cache" title="TestDriver Cache" icon="database">
54
- Manage and clear your test cache from the TestDriver console.
55
- </Card>
54
+ ## Choose your own cache key
56
55
 
57
- ## Debugging Cache Hits and Misses
56
+ By default, each test file has its own cache, which resets when you edit the file.
58
57
 
59
- You can track what TestDriver has learned by inspecting cache performance in your tests:
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
- test('monitor cache performance', async (context) => {
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
- ## Configuring the Cache
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
- You can configure how TestDriver learns globally when initializing TestDriver:
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
- import { TestDriver } from 'testdriverai';
85
-
86
- const testdriver = new TestDriver({
87
- apiKey: process.env.TD_API_KEY,
88
- cacheKey: 'my-test-suite', // cache-key for this instance
89
- cacheDefaults: {
90
- threshold: 0.05, // 95% similarity
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
- It's also possible to override cache settings per `find()` call:
90
+ Or override them for one call:
96
91
 
97
92
  ```javascript
98
- // Default: 95% similarity required
99
- await testdriver.find('submit button');
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
- ## Caching with Variables
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
- Custom cache keys prevent cache pollution when using variables in prompts, dramatically improving cache hit rates—so TestDriver reuses what it learned even when your data changes.
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
- // ❌ Without cache key - creates new cache for each variable value
113
- const email = 'user@example.com';
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
- // Also useful for dynamic IDs, names, or other changing data
123
- const orderId = generateOrderId();
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
- ## Next
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
- <Card href="/copilot/running-tests" title="Run" icon="play">
132
- Now that TestDriver has learned your app, run your tests in CI and locally—replaying the cache for fast, deterministic results.
133
- </Card>
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>