testdriverai 7.8.0-test.7 → 7.8.0-test.71
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/agent/index.js +18 -5
- package/agent/lib/commands.js +3 -2
- package/agent/lib/http.js +162 -0
- package/agent/lib/logger.js +15 -0
- package/agent/lib/sandbox.js +554 -209
- package/agent/lib/sdk.js +5 -22
- package/agent/lib/system.js +25 -65
- package/ai/skills/testdriver-cache/SKILL.md +221 -0
- package/ai/skills/testdriver-errors/SKILL.md +246 -0
- package/ai/skills/testdriver-events/SKILL.md +356 -0
- package/ai/skills/testdriver-find/SKILL.md +14 -20
- package/ai/skills/testdriver-mcp/SKILL.md +7 -0
- package/ai/skills/testdriver-provision/SKILL.md +331 -0
- package/ai/skills/testdriver-redraw/SKILL.md +214 -0
- package/ai/skills/testdriver-running-tests/SKILL.md +1 -1
- package/ai/skills/testdriver-screenshots/SKILL.md +184 -0
- package/docs/_data/examples-manifest.json +46 -46
- package/docs/_scripts/extract-example-urls.js +67 -72
- package/docs/changelog.mdx +148 -8
- package/docs/docs.json +46 -38
- package/docs/images/content/vscode/v7-chat.png +0 -0
- package/docs/images/content/vscode/v7-choose-agent.png +0 -0
- package/docs/images/content/vscode/v7-full.png +0 -0
- package/docs/images/content/vscode/v7-onboarding.png +0 -0
- package/docs/v7/cache.mdx +223 -0
- package/docs/v7/copilot/auto-healing.mdx +265 -0
- package/docs/v7/copilot/creating-tests.mdx +156 -0
- package/docs/v7/copilot/github.mdx +143 -0
- package/docs/v7/copilot/running-tests.mdx +149 -0
- package/docs/v7/copilot/setup.mdx +143 -0
- package/docs/v7/enterprise.mdx +3 -110
- package/docs/v7/errors.mdx +248 -0
- package/docs/v7/events.mdx +358 -0
- package/docs/v7/examples/ai.mdx +1 -1
- package/docs/v7/examples/assert.mdx +1 -1
- package/docs/v7/examples/captcha-api.mdx +1 -1
- package/docs/v7/examples/chrome-extension.mdx +1 -1
- package/docs/v7/examples/drag-and-drop.mdx +1 -1
- package/docs/v7/examples/element-not-found.mdx +1 -1
- package/docs/v7/examples/exec-output.mdx +85 -0
- package/docs/v7/examples/exec-pwsh.mdx +83 -0
- package/docs/v7/examples/focus-window.mdx +62 -0
- package/docs/v7/examples/hover-image.mdx +1 -1
- package/docs/v7/examples/hover-text.mdx +1 -1
- package/docs/v7/examples/installer.mdx +1 -1
- package/docs/v7/examples/launch-vscode-linux.mdx +1 -1
- package/docs/v7/examples/match-image.mdx +1 -1
- package/docs/v7/examples/press-keys.mdx +1 -1
- package/docs/v7/examples/scroll-keyboard.mdx +1 -1
- package/docs/v7/examples/scroll-until-image.mdx +1 -1
- package/docs/v7/examples/scroll-until-text.mdx +1 -1
- package/docs/v7/examples/scroll.mdx +1 -1
- package/docs/v7/examples/type.mdx +1 -1
- package/docs/v7/examples/windows-installer.mdx +1 -1
- package/docs/v7/find.mdx +14 -20
- package/docs/v7/{cloud.mdx → hosted.mdx} +43 -5
- package/docs/v7/mcp.mdx +9 -0
- package/docs/v7/provision.mdx +333 -0
- package/docs/v7/quickstart.mdx +30 -2
- package/docs/v7/redraw.mdx +216 -0
- package/docs/v7/running-tests.mdx +1 -1
- package/docs/v7/screenshots.mdx +186 -0
- package/docs/v7/self-hosted.mdx +127 -44
- package/docs/v7/test-results-json.mdx +258 -0
- package/examples/scroll-keyboard.test.mjs +1 -1
- package/examples/scroll.test.mjs +1 -12
- package/interfaces/logger.js +0 -12
- package/interfaces/vitest-plugin.mjs +170 -51
- package/lib/core/Dashcam.js +30 -23
- package/lib/environments.json +22 -0
- package/lib/github-comment.mjs +58 -40
- package/lib/init-project.js +5 -67
- package/lib/resolve-channel.js +42 -12
- package/lib/sentry.js +47 -23
- package/lib/vitest/hooks.mjs +63 -3
- package/{examples → manual}/drag-and-drop.test.mjs +1 -1
- package/manual/exec-stream-logs.test.mjs +25 -0
- package/mcp-server/dist/server.mjs +28 -8
- package/mcp-server/src/server.ts +31 -8
- package/package.json +4 -3
- package/sdk.d.ts +4 -0
- package/sdk.js +45 -15
- package/setup/aws/install-dev-runner.sh +79 -0
- package/setup/aws/spawn-runner.sh +165 -0
- package/test-sentry-span.js +35 -0
- package/vitest.config.mjs +22 -34
- package/vitest.runner.config.mjs +33 -0
- /package/{examples → manual}/flake-diffthreshold-001.test.mjs +0 -0
- /package/{examples → manual}/flake-diffthreshold-01.test.mjs +0 -0
- /package/{examples → manual}/flake-diffthreshold-05.test.mjs +0 -0
- /package/{examples → manual}/flake-noredraw-cache.test.mjs +0 -0
- /package/{examples → manual}/flake-noredraw-nocache.test.mjs +0 -0
- /package/{examples → manual}/flake-redraw-cache.test.mjs +0 -0
- /package/{examples → manual}/flake-redraw-nocache.test.mjs +0 -0
- /package/{examples → manual}/flake-rocket-match.test.mjs +0 -0
- /package/{examples → manual}/flake-shared.mjs +0 -0
- /package/{examples → manual}/no-provision.test.mjs +0 -0
- /package/{examples → manual}/scroll-until-text.test.mjs +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testdriver:events
|
|
3
|
+
description: Listen to SDK lifecycle events with wildcard support
|
|
4
|
+
---
|
|
5
|
+
<!-- Generated from events.mdx. DO NOT EDIT. -->
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
TestDriver uses [EventEmitter2](https://github.com/EventEmitter2/EventEmitter2) for its event system. Events use a colon-delimited namespace pattern and support wildcard listeners.
|
|
10
|
+
|
|
11
|
+
Access the emitter through `testdriver.emitter`:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
testdriver.emitter.on('command:start', (data) => {
|
|
15
|
+
console.log(`Running: ${data.command}`);
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Configuration
|
|
20
|
+
|
|
21
|
+
The internal emitter is created with:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
new EventEmitter2({
|
|
25
|
+
wildcard: true,
|
|
26
|
+
delimiter: ':',
|
|
27
|
+
maxListeners: 20,
|
|
28
|
+
verboseMemoryLeak: false,
|
|
29
|
+
ignoreErrors: false,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Wildcard Listeners
|
|
34
|
+
|
|
35
|
+
Use `*` to match a single level or `**` to match multiple levels:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// Match all log events
|
|
39
|
+
testdriver.emitter.on('log:*', (message) => {
|
|
40
|
+
console.log(message);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Match all events in any namespace
|
|
44
|
+
testdriver.emitter.on('**', (...args) => {
|
|
45
|
+
console.log('Event:', this.event, args);
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Event Reference
|
|
50
|
+
|
|
51
|
+
### Command Events
|
|
52
|
+
|
|
53
|
+
Emitted during the execution of SDK commands (`click`, `type`, `find`, etc.).
|
|
54
|
+
|
|
55
|
+
| Event | Payload |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `command:start` | `{ command, depth, data, timestamp, sourcePosition }` |
|
|
58
|
+
| `command:success` | `{ command, depth, data, duration, response, timestamp, sourcePosition }` |
|
|
59
|
+
| `command:error` | `{ command, depth, data, error, duration, timestamp, sourcePosition }` |
|
|
60
|
+
| `command:status` | `{ command, status: "executing", data, depth, timestamp }` |
|
|
61
|
+
| `command:progress` | `{ command, status: "completed", timing, data, depth, timestamp }` |
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
testdriver.emitter.on('command:start', ({ command, data }) => {
|
|
65
|
+
console.log(`Starting ${command}`, data);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
testdriver.emitter.on('command:error', ({ command, error, duration }) => {
|
|
69
|
+
console.error(`${command} failed after ${duration}ms: ${error}`);
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Step Events
|
|
74
|
+
|
|
75
|
+
Emitted for each AI reasoning step within a command.
|
|
76
|
+
|
|
77
|
+
| Event | Payload |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `step:start` | `{ stepIndex, prompt, commandCount, timestamp, sourcePosition }` |
|
|
80
|
+
| `step:success` | `{ stepIndex, prompt, commandCount, duration, timestamp, sourcePosition }` |
|
|
81
|
+
| `step:error` | `{ stepIndex, prompt, error, duration?, timestamp, sourcePosition? }` |
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
|
|
85
|
+
console.log(`Step ${stepIndex}: ${prompt}`);
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Test Events
|
|
90
|
+
|
|
91
|
+
Emitted when a test file execution starts.
|
|
92
|
+
|
|
93
|
+
| Event | Payload |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `test:start` | `{ filePath, timestamp }` |
|
|
96
|
+
| `test:success` | *Emitted on test completion* |
|
|
97
|
+
| `test:error` | *Emitted on test failure* |
|
|
98
|
+
|
|
99
|
+
### Log Events
|
|
100
|
+
|
|
101
|
+
Emitted for all log output from the SDK.
|
|
102
|
+
|
|
103
|
+
| Event | Payload |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `log:log` | `(message: string)` — general log message |
|
|
106
|
+
| `log:warn` | `(message: string)` — warning message |
|
|
107
|
+
| `log:debug` | `(message: string)` — debug output (only when `VERBOSE`/`DEBUG`/`TD_DEBUG` env set) |
|
|
108
|
+
| `log:info` | `(message: string)` — informational message |
|
|
109
|
+
| `log:error` | `(message: string)` — error message |
|
|
110
|
+
| `log:narration` | `(message: string, overwrite?: boolean)` — in-place status line |
|
|
111
|
+
| `log:markdown` | `(markdown: string)` — full static markdown content |
|
|
112
|
+
| `log:markdown:start` | `(streamId: string)` — begin streaming markdown |
|
|
113
|
+
| `log:markdown:chunk` | `(streamId: string, chunk: string)` — incremental chunk |
|
|
114
|
+
| `log:markdown:end` | `(streamId: string)` — end streaming markdown |
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
// Capture all logs
|
|
118
|
+
testdriver.emitter.on('log:*', function (message) {
|
|
119
|
+
console.log(`[${this.event}]`, message);
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Screen Capture Events
|
|
124
|
+
|
|
125
|
+
Emitted during screenshot capture.
|
|
126
|
+
|
|
127
|
+
| Event | Payload |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `screen-capture:start` | `{ scale, silent, display }` |
|
|
130
|
+
| `screen-capture:end` | `{ scale, silent, display }` |
|
|
131
|
+
| `screen-capture:error` | `{ error, scale, silent, display }` |
|
|
132
|
+
|
|
133
|
+
### Sandbox Events
|
|
134
|
+
|
|
135
|
+
Emitted for sandbox WebSocket lifecycle and communication.
|
|
136
|
+
|
|
137
|
+
| Event | Payload |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `sandbox:connected` | *No payload* — WebSocket connection established |
|
|
140
|
+
| `sandbox:authenticated` | `{ traceId }` — authentication successful |
|
|
141
|
+
| `sandbox:error` | `(err: Error \| string)` — connection or sandbox error |
|
|
142
|
+
| `sandbox:sent` | `(message: object)` — WebSocket message sent |
|
|
143
|
+
| `sandbox:received` | *No payload* — successful message reply received |
|
|
144
|
+
| `sandbox:progress` | `{ step, message }` — sandbox setup progress |
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
testdriver.emitter.on('sandbox:connected', () => {
|
|
148
|
+
console.log('Connected to sandbox');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
testdriver.emitter.on('sandbox:progress', ({ step, message }) => {
|
|
152
|
+
console.log(`Sandbox: [${step}] ${message}`);
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Redraw Events
|
|
157
|
+
|
|
158
|
+
Emitted during screen stability detection. See [Redraw](/v7/redraw) for more details.
|
|
159
|
+
|
|
160
|
+
| Event | Payload |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `redraw:status` | `{ redraw: { enabled, settled, hasChangedFromInitial, consecutiveFramesStable, diffFromInitial, diffFromLast, text }, network: { enabled, settled, rxBytes, txBytes, text }, timeout: { isTimeout, elapsed, max, text } }` |
|
|
163
|
+
| `redraw:complete` | `{ screenSettled, hasChangedFromInitial, consecutiveFramesStable, networkSettled, isTimeout, timeElapsed }` |
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
testdriver.emitter.on('redraw:complete', (result) => {
|
|
167
|
+
if (result.isTimeout) {
|
|
168
|
+
console.warn('Redraw timed out after', result.timeElapsed, 'ms');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### File Events
|
|
174
|
+
|
|
175
|
+
Emitted during file load/save operations in the agent.
|
|
176
|
+
|
|
177
|
+
| Event | Payload |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `file:start` | `{ operation: "load" \| "save" \| "run", filePath, timestamp }` |
|
|
180
|
+
| `file:stop` | `{ operation, filePath, duration, success, sourceMap?, reason?, timestamp }` |
|
|
181
|
+
| `file:load` | `{ filePath, size, timestamp }` |
|
|
182
|
+
| `file:save` | `{ filePath, size, timestamp }` |
|
|
183
|
+
| `file:diff` | `{ filePath, diff: { patches, sourceMaps, summary: { additions, deletions, modifications } }, timestamp }` |
|
|
184
|
+
| `file:error` | `{ operation, filePath, error, duration?, timestamp }` |
|
|
185
|
+
|
|
186
|
+
### Error Events
|
|
187
|
+
|
|
188
|
+
Emitted for errors at various severity levels.
|
|
189
|
+
|
|
190
|
+
| Event | Payload |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `error:fatal` | `(error: string \| Error)` — terminates the process |
|
|
193
|
+
| `error:general` | `(message: string)` — non-fatal error |
|
|
194
|
+
| `error:sandbox` | `(err: Error \| string)` — sandbox/WebSocket error |
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
testdriver.emitter.on('error:*', function (err) {
|
|
198
|
+
console.error(`[${this.event}]`, err);
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### SDK Events
|
|
203
|
+
|
|
204
|
+
Emitted for API request lifecycle.
|
|
205
|
+
|
|
206
|
+
| Event | Payload |
|
|
207
|
+
|---|---|
|
|
208
|
+
| `sdk:request` | `{ path }` — outgoing API request |
|
|
209
|
+
| `sdk:response` | `{ path }` — API response received |
|
|
210
|
+
| `sdk:retry` | `{ path, attempt, error, delayMs }` — request retry |
|
|
211
|
+
|
|
212
|
+
### Other Events
|
|
213
|
+
|
|
214
|
+
| Event | Payload |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `exit` | `(exitCode: number)` — `0` for success, `1` for failure |
|
|
217
|
+
| `status` | `(message: string)` — general status updates |
|
|
218
|
+
| `mouse-click` | `{ x, y, button, click, double }` — mouse click performed |
|
|
219
|
+
| `terminal:stdout` | Terminal stdout output |
|
|
220
|
+
| `terminal:stderr` | Terminal stderr output |
|
|
221
|
+
|
|
222
|
+
## Practical Examples
|
|
223
|
+
|
|
224
|
+
### Custom Test Reporter
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const results = [];
|
|
228
|
+
|
|
229
|
+
testdriver.emitter.on('command:success', ({ command, duration }) => {
|
|
230
|
+
results.push({ command, duration, status: 'pass' });
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
testdriver.emitter.on('command:error', ({ command, duration, error }) => {
|
|
234
|
+
results.push({ command, duration, status: 'fail', error });
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// After test completes
|
|
238
|
+
afterAll(() => {
|
|
239
|
+
console.table(results);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Progress Monitoring
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
|
|
247
|
+
process.stdout.write(`\r Step ${stepIndex}: ${prompt}`);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
testdriver.emitter.on('command:progress', ({ command, timing }) => {
|
|
251
|
+
process.stdout.write(`\r ${command} completed in ${timing}ms`);
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Debug Logging
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
// Log every event (verbose)
|
|
259
|
+
testdriver.emitter.on('**', function (...args) {
|
|
260
|
+
console.debug(`[EVENT] ${this.event}`, ...args);
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Types
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface CommandStartEvent {
|
|
268
|
+
command: string;
|
|
269
|
+
depth: number;
|
|
270
|
+
data: Record<string, any>;
|
|
271
|
+
timestamp: number;
|
|
272
|
+
sourcePosition: SourcePosition;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
interface CommandSuccessEvent {
|
|
276
|
+
command: string;
|
|
277
|
+
depth: number;
|
|
278
|
+
data: Record<string, any>;
|
|
279
|
+
duration: number;
|
|
280
|
+
response: any;
|
|
281
|
+
timestamp: number;
|
|
282
|
+
sourcePosition: SourcePosition;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
interface CommandErrorEvent {
|
|
286
|
+
command: string;
|
|
287
|
+
depth: number;
|
|
288
|
+
data: Record<string, any>;
|
|
289
|
+
error: string;
|
|
290
|
+
duration: number;
|
|
291
|
+
timestamp: number;
|
|
292
|
+
sourcePosition: SourcePosition;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
interface StepStartEvent {
|
|
296
|
+
stepIndex: number;
|
|
297
|
+
prompt: string;
|
|
298
|
+
commandCount: number;
|
|
299
|
+
timestamp: number;
|
|
300
|
+
sourcePosition: SourcePosition;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
interface StepSuccessEvent {
|
|
304
|
+
stepIndex: number;
|
|
305
|
+
prompt: string;
|
|
306
|
+
commandCount: number;
|
|
307
|
+
duration: number;
|
|
308
|
+
timestamp: number;
|
|
309
|
+
sourcePosition: SourcePosition;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
interface RedrawStatusEvent {
|
|
313
|
+
redraw: {
|
|
314
|
+
enabled: boolean;
|
|
315
|
+
settled: boolean;
|
|
316
|
+
hasChangedFromInitial: boolean;
|
|
317
|
+
consecutiveFramesStable: number;
|
|
318
|
+
diffFromInitial: number;
|
|
319
|
+
diffFromLast: number;
|
|
320
|
+
text: string;
|
|
321
|
+
};
|
|
322
|
+
network: {
|
|
323
|
+
enabled: boolean;
|
|
324
|
+
settled: boolean;
|
|
325
|
+
rxBytes: number;
|
|
326
|
+
txBytes: number;
|
|
327
|
+
text: string;
|
|
328
|
+
};
|
|
329
|
+
timeout: {
|
|
330
|
+
isTimeout: boolean;
|
|
331
|
+
elapsed: number;
|
|
332
|
+
max: number;
|
|
333
|
+
text: string;
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface RedrawCompleteEvent {
|
|
338
|
+
screenSettled: boolean;
|
|
339
|
+
hasChangedFromInitial: boolean;
|
|
340
|
+
consecutiveFramesStable: number;
|
|
341
|
+
networkSettled: boolean;
|
|
342
|
+
isTimeout: boolean;
|
|
343
|
+
timeElapsed: number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
interface SandboxProgressEvent {
|
|
347
|
+
step: string;
|
|
348
|
+
message: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
interface SourcePosition {
|
|
352
|
+
file: string;
|
|
353
|
+
line: number;
|
|
354
|
+
column: number;
|
|
355
|
+
}
|
|
356
|
+
```
|
|
@@ -49,8 +49,8 @@ const element = await testdriver.find(description, options)
|
|
|
49
49
|
- `"any"` — No wrapping, uses the description as-is (default behavior)
|
|
50
50
|
</ParamField>
|
|
51
51
|
|
|
52
|
-
<ParamField path="zoom" type="boolean" default={
|
|
53
|
-
|
|
52
|
+
<ParamField path="zoom" type="boolean" default={true}>
|
|
53
|
+
Two-phase zoom mode for better precision in crowded UIs with many similar elements. Enabled by default.
|
|
54
54
|
</ParamField>
|
|
55
55
|
|
|
56
56
|
<ParamField path="ai" type="object">
|
|
@@ -332,14 +332,19 @@ The `timeout` option:
|
|
|
332
332
|
- Returns the element (check `element.found()` if not throwing on failure)
|
|
333
333
|
- Set to `0` to disable polling and make a single attempt
|
|
334
334
|
|
|
335
|
-
## Zoom Mode
|
|
335
|
+
## Zoom Mode
|
|
336
336
|
|
|
337
|
-
|
|
337
|
+
Zoom mode is **enabled by default**. It uses a two-phase approach for better precision when locating elements, especially in crowded UIs with many similar elements.
|
|
338
|
+
|
|
339
|
+
To disable zoom for a specific find call, pass `zoom: false`:
|
|
338
340
|
|
|
339
341
|
```javascript
|
|
340
|
-
//
|
|
341
|
-
const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar'
|
|
342
|
+
// Zoom is on by default — no option needed
|
|
343
|
+
const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar');
|
|
342
344
|
await extensionsBtn.click();
|
|
345
|
+
|
|
346
|
+
// Disable zoom for a specific call if needed
|
|
347
|
+
const largeButton = await testdriver.find('big hero button', { zoom: false });
|
|
343
348
|
```
|
|
344
349
|
|
|
345
350
|
### How Zoom Mode Works
|
|
@@ -352,22 +357,11 @@ await extensionsBtn.click();
|
|
|
352
357
|
This two-phase approach gives the AI a higher-resolution view of the target area, improving accuracy when multiple similar elements are close together.
|
|
353
358
|
|
|
354
359
|
<Tip>
|
|
355
|
-
|
|
356
|
-
-
|
|
357
|
-
-
|
|
358
|
-
- Targeting elements in dense UI areas
|
|
359
|
-
- The default locate is clicking the wrong similar element
|
|
360
|
-
- You get an AI verification rejection like "The crosshair is located in the empty space of the browser's tab bar/title bar area" — this means the initial locate was imprecise and zoom will help the AI pinpoint the correct element
|
|
360
|
+
You may want to disable zoom with `zoom: false` when:
|
|
361
|
+
- Targeting large, isolated elements where the extra precision isn't needed
|
|
362
|
+
- You want to speed up find calls in simple UIs
|
|
361
363
|
</Tip>
|
|
362
364
|
|
|
363
|
-
```javascript
|
|
364
|
-
// Without zoom - may click wrong icon in toolbar
|
|
365
|
-
const icon = await testdriver.find('settings icon');
|
|
366
|
-
|
|
367
|
-
// With zoom - better precision for crowded areas
|
|
368
|
-
const icon = await testdriver.find('settings icon', { zoom: true });
|
|
369
|
-
```
|
|
370
|
-
|
|
371
365
|
## Cache Options
|
|
372
366
|
|
|
373
367
|
Control caching behavior to optimize performance, especially when using dynamic variables in prompts.
|