testdriverai 7.11.264-test → 7.11.265-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 (67) hide show
  1. package/ai/skills/testdriver-quickstart/SKILL.md +1 -1
  2. package/ai/skills/testdriver-quickstart-claude/SKILL.md +47 -10
  3. package/docs/_scripts/generate-skills.js +76 -24
  4. package/docs/quickstart-claude.mdx +47 -10
  5. package/docs/quickstart.mdx +1 -1
  6. package/package.json +2 -2
  7. package/ai/skills/testdriver-ai/SKILL.md +0 -204
  8. package/ai/skills/testdriver-claude-mcp-plugin/SKILL.md +0 -245
  9. package/ai/skills/testdriver-cloud/SKILL.md +0 -119
  10. package/ai/skills/testdriver-device-config/SKILL.md +0 -317
  11. package/ai/skills/testdriver-elements/SKILL.md +0 -605
  12. package/ai/skills/testdriver-examples/SKILL.md +0 -7
  13. package/ai/skills/testdriver-machine-setup/SKILL.md +0 -331
  14. package/ai/skills/testdriver-running-tests/SKILL.md +0 -185
  15. package/ai/skills/testdriver-test-writer/SKILL.md +0 -446
  16. package/ai/skills/testdriver-waiting-for-elements/SKILL.md +0 -90
  17. package/ai/skills/testdriver:ai/SKILL.md +0 -204
  18. package/ai/skills/testdriver:assert/SKILL.md +0 -315
  19. package/ai/skills/testdriver:aws-setup/SKILL.md +0 -448
  20. package/ai/skills/testdriver:cache/SKILL.md +0 -221
  21. package/ai/skills/testdriver:caching/SKILL.md +0 -124
  22. package/ai/skills/testdriver:captcha/SKILL.md +0 -158
  23. package/ai/skills/testdriver:ci-cd/SKILL.md +0 -659
  24. package/ai/skills/testdriver:click/SKILL.md +0 -286
  25. package/ai/skills/testdriver:client/SKILL.md +0 -481
  26. package/ai/skills/testdriver:customizing-devices/SKILL.md +0 -319
  27. package/ai/skills/testdriver:dashcam/SKILL.md +0 -451
  28. package/ai/skills/testdriver:debugging-with-screenshots/SKILL.md +0 -415
  29. package/ai/skills/testdriver:device-config/SKILL.md +0 -317
  30. package/ai/skills/testdriver:double-click/SKILL.md +0 -102
  31. package/ai/skills/testdriver:elements/SKILL.md +0 -605
  32. package/ai/skills/testdriver:enterprise/SKILL.md +0 -7
  33. package/ai/skills/testdriver:errors/SKILL.md +0 -246
  34. package/ai/skills/testdriver:events/SKILL.md +0 -356
  35. package/ai/skills/testdriver:exec/SKILL.md +0 -317
  36. package/ai/skills/testdriver:find/SKILL.md +0 -856
  37. package/ai/skills/testdriver:focus-application/SKILL.md +0 -293
  38. package/ai/skills/testdriver:generating-tests/SKILL.md +0 -25
  39. package/ai/skills/testdriver:hosted/SKILL.md +0 -155
  40. package/ai/skills/testdriver:hover/SKILL.md +0 -278
  41. package/ai/skills/testdriver:locating-elements/SKILL.md +0 -71
  42. package/ai/skills/testdriver:making-assertions/SKILL.md +0 -32
  43. package/ai/skills/testdriver:mcp/SKILL.md +0 -7
  44. package/ai/skills/testdriver:mouse-down/SKILL.md +0 -161
  45. package/ai/skills/testdriver:mouse-up/SKILL.md +0 -164
  46. package/ai/skills/testdriver:parse/SKILL.md +0 -236
  47. package/ai/skills/testdriver:performing-actions/SKILL.md +0 -53
  48. package/ai/skills/testdriver:press-keys/SKILL.md +0 -348
  49. package/ai/skills/testdriver:provision/SKILL.md +0 -331
  50. package/ai/skills/testdriver:quickstart/SKILL.md +0 -172
  51. package/ai/skills/testdriver:redraw/SKILL.md +0 -214
  52. package/ai/skills/testdriver:reusable-code/SKILL.md +0 -249
  53. package/ai/skills/testdriver:right-click/SKILL.md +0 -123
  54. package/ai/skills/testdriver:running-tests/SKILL.md +0 -185
  55. package/ai/skills/testdriver:screenshot/SKILL.md +0 -248
  56. package/ai/skills/testdriver:screenshots/SKILL.md +0 -184
  57. package/ai/skills/testdriver:scroll/SKILL.md +0 -205
  58. package/ai/skills/testdriver:secrets/SKILL.md +0 -115
  59. package/ai/skills/testdriver:self-hosted/SKILL.md +0 -147
  60. package/ai/skills/testdriver:test-results-json/SKILL.md +0 -257
  61. package/ai/skills/testdriver:testdriver/SKILL.md +0 -624
  62. package/ai/skills/testdriver:type/SKILL.md +0 -357
  63. package/ai/skills/testdriver:variables/SKILL.md +0 -111
  64. package/ai/skills/testdriver:wait/SKILL.md +0 -50
  65. package/ai/skills/testdriver:waiting-for-elements/SKILL.md +0 -90
  66. package/ai/skills/testdriver:what-is-testdriver/SKILL.md +0 -54
  67. package/scripts/generate-skills.js +0 -94
@@ -1,856 +0,0 @@
1
- ---
2
- name: testdriver:find
3
- description: Locate UI elements using natural language
4
- ---
5
- <!-- Generated from find.mdx. DO NOT EDIT. -->
6
-
7
- ## Overview
8
-
9
- Locate UI elements on screen using AI-powered natural language descriptions. Returns an `Element` object that can be interacted with.
10
-
11
- ## Syntax
12
-
13
- ```javascript
14
- const element = await testdriver.find(description)
15
- const element = await testdriver.find(description, options)
16
- ```
17
-
18
- ## Parameters
19
-
20
- <ParamField path="description" type="string" required>
21
- Natural language description of the element to find
22
- </ParamField>
23
-
24
- <ParamField path="options" type="object | number">
25
- Optional configuration for finding and caching
26
-
27
- <Expandable title="properties">
28
- <ParamField path="cacheKey" type="string">
29
- Custom cache key for storing element location. Use this to prevent cache pollution when using dynamic variables in prompts, or to share cache across tests.
30
- </ParamField>
31
-
32
- <ParamField path="cacheThreshold" type="number" default={0.05}>
33
- Similarity threshold (0-1) for cache matching. Lower values require more similarity. Set to -1 to disable cache.
34
- </ParamField>
35
-
36
- <ParamField path="timeout" type="number" default={10000}>
37
- Maximum time in milliseconds to poll for the element. Retries every 5 seconds until found or timeout expires. Defaults to `10000` (10 seconds). Set to `0` to disable polling and make a single attempt.
38
- </ParamField>
39
-
40
- <ParamField path="confidence" type="number">
41
- Minimum confidence threshold (0-1). If the AI's confidence score for the found element is below this value, the find will be treated as a failure (`element.found()` returns `false`). Useful for ensuring high-quality matches in critical test steps.
42
- </ParamField>
43
-
44
- <ParamField path="type" type="string">
45
- Element type hint that wraps the description for better matching. Accepted values:
46
- - `"text"` — Wraps the prompt as `The text "..."`
47
- - `"image"` — Wraps the prompt as `The image "..."`
48
- - `"ui"` — Wraps the prompt as `The UI element "..."`
49
- - `"any"` — No wrapping, uses the description as-is (default behavior)
50
- </ParamField>
51
-
52
- <ParamField path="zoom" type="boolean" default={false}>
53
- Two-phase zoom mode for better precision in crowded UIs with many similar elements. Disabled by default.
54
- </ParamField>
55
-
56
- <ParamField path="verify" type="boolean" default={false}>
57
- Enable AI verification of the located element. When `true`, a second AI call checks that the coordinates returned actually correspond to the requested element, catching hallucinated or incorrect positions. Disabled by default for lower latency. Defaults to the global `verify` option set on the SDK constructor when not specified per call.
58
- </ParamField>
59
-
60
- <ParamField path="ai" type="object">
61
- AI sampling configuration for this find call (overrides global `ai` config from constructor).
62
-
63
- <Expandable title="properties">
64
- <ParamField path="temperature" type="number">
65
- Controls randomness. `0` = deterministic. Default: `0` for find verification.
66
- </ParamField>
67
-
68
- <ParamField path="top" type="object">
69
- Sampling parameters
70
-
71
- <Expandable title="properties">
72
- <ParamField path="p" type="number">
73
- Top-P (nucleus sampling). Range: 0-1.
74
- </ParamField>
75
-
76
- <ParamField path="k" type="number">
77
- Top-K sampling. `1` = most deterministic.
78
- </ParamField>
79
- </Expandable>
80
- </ParamField>
81
- </Expandable>
82
- </ParamField>
83
- </Expandable>
84
- </ParamField>
85
-
86
- ## Returns
87
-
88
- `Promise<Element>` - Element instance that has been automatically located
89
-
90
- ## Examples
91
-
92
- ### Basic Element Finding
93
-
94
- ```javascript
95
- // Find by role
96
- const button = await testdriver.find('submit button');
97
- const input = await testdriver.find('email input field');
98
-
99
- // Find by text content
100
- const link = await testdriver.find('Contact Us link');
101
- const heading = await testdriver.find('Welcome heading');
102
-
103
- // Find by visual appearance
104
- const icon = await testdriver.find('red warning icon');
105
- const image = await testdriver.find('company logo image');
106
- ```
107
-
108
- ### Finding with Context
109
-
110
- ```javascript
111
- // Provide location context
112
- const field = await testdriver.find('username input in the login form');
113
- const button = await testdriver.find('delete button in the top right corner');
114
-
115
- // Describe nearby elements
116
- const input = await testdriver.find('input field below the email label');
117
- const checkbox = await testdriver.find('checkbox next to "Remember me"');
118
-
119
- // Describe visual position
120
- const menu = await testdriver.find('hamburger menu icon in the top left');
121
- ```
122
-
123
- ### Interacting with Found Elements
124
-
125
- ```javascript
126
- // Find and click
127
- const submitBtn = await testdriver.find('submit button');
128
- await submitBtn.click();
129
-
130
- // Find and verify
131
- const message = await testdriver.find('success message');
132
- if (message.found()) {
133
- console.log('Success message appeared');
134
- }
135
-
136
- // Find and extract info
137
- const price = await testdriver.find('product price');
138
- console.log('Price location:', price.coordinates);
139
- console.log('Price text:', price.text);
140
- ```
141
-
142
- ## Element Object
143
-
144
- The returned `Element` object provides:
145
-
146
- ### Methods
147
-
148
- - `found()` - Check if element was located
149
- - `click(action)` - Click the element
150
- - `hover()` - Hover over the element
151
- - `doubleClick()` - Double-click the element
152
- - `rightClick()` - Right-click the element
153
- - `find(newDescription)` - Re-locate with optional new description
154
-
155
- ### Properties
156
-
157
- - `coordinates` - Element position `{x, y, centerX, centerY}`
158
- - `x`, `y` - Top-left coordinates
159
- - `centerX`, `centerY` - Center coordinates
160
- - `text` - Text content (if available)
161
- - `screenshot` - Base64 screenshot (if available)
162
- - `confidence` - AI confidence score
163
- - `width`, `height` - Element dimensions
164
- - `boundingBox` - Complete bounding box
165
-
166
- See [Elements Reference](/v7/elements) for complete details.
167
-
168
- ### JSON Serialization
169
-
170
- Elements can be safely serialized using `JSON.stringify()` for logging and debugging. Circular references are automatically removed:
171
-
172
- ```javascript
173
- const element = await testdriver.find('login button');
174
-
175
- // Safe to stringify - no circular reference errors
176
- console.log(JSON.stringify(element, null, 2));
177
-
178
- // Output includes useful debugging info:
179
- // {
180
- // "description": "login button",
181
- // "coordinates": { "x": 100, "y": 200, "centerX": 150, "centerY": 225 },
182
- // "found": true,
183
- // "threshold": 0.01,
184
- // "x": 100,
185
- // "y": 200,
186
- // "cache": {
187
- // "hit": true,
188
- // "strategy": "pixel-diff",
189
- // "createdAt": "2025-12-09T10:30:00Z",
190
- // "diffPercent": 0.0023,
191
- // "imageUrl": "https://..."
192
- // },
193
- // "similarity": 0.98,
194
- // "confidence": 0.95,
195
- // "selector": "button#login",
196
- // "aiResponse": "Found the blue login button..."
197
- // }
198
- ```
199
-
200
- This is useful for:
201
- - Debugging element detection issues
202
- - Logging test execution details
203
- - Sharing element information across processes
204
- - Analyzing cache performance
205
-
206
- ## Best Practices
207
-
208
- <Check>
209
- **Be specific in descriptions**
210
-
211
- More specific descriptions improve accuracy:
212
-
213
- ```javascript
214
- // ✅ Good
215
- await testdriver.find('blue submit button below the email field');
216
-
217
- // ❌ Too vague
218
- await testdriver.find('button');
219
- ```
220
- </Check>
221
-
222
- <Check>
223
- **Always check if found**
224
-
225
- Verify elements were located before interacting:
226
-
227
- ```javascript
228
- const element = await testdriver.find('login button');
229
- if (!element.found()) {
230
- throw new Error('Login button not found');
231
- }
232
- await element.click();
233
- ```
234
- </Check>
235
-
236
- <Check>
237
- **Include visual or positional context**
238
-
239
- ```javascript
240
- // Include color
241
- await testdriver.find('red error icon');
242
-
243
- // Include position
244
- await testdriver.find('search button in the top navigation bar');
245
-
246
- // Include nearby text
247
- await testdriver.find('checkbox next to "I agree to terms"');
248
- ```
249
- </Check>
250
-
251
- ## Confidence Threshold
252
-
253
- Require a minimum AI confidence score for element matches. If the confidence is below the threshold, `find()` treats the result as not found:
254
-
255
- ```javascript
256
- // Require at least 90% confidence
257
- const element = await testdriver.find('submit button', { confidence: 0.9 });
258
-
259
- if (!element.found()) {
260
- // AI found something but wasn't confident enough
261
- throw new Error('Could not confidently locate submit button');
262
- }
263
-
264
- await element.click();
265
- ```
266
-
267
- This is useful for:
268
- - Critical test steps where an incorrect click could cause cascading failures
269
- - Distinguishing between similar elements (e.g., multiple buttons)
270
- - Failing fast when the UI has changed unexpectedly
271
-
272
- ```javascript
273
- // Combine with timeout for robust polling with confidence gate
274
- const element = await testdriver.find('success notification', {
275
- confidence: 0.85,
276
- timeout: 15000,
277
- });
278
- ```
279
-
280
- <Tip>
281
- The `confidence` value is a float between 0 and 1 (e.g., `0.9` = 90%). The AI returns its confidence with each find result, which you can also read from `element.confidence` after a successful find.
282
- </Tip>
283
- ## Element Type
284
-
285
- Use the `type` option to hint what kind of element you're looking for. This wraps your description into a more specific prompt for the AI, improving match accuracy — especially when users provide short or ambiguous descriptions.
286
-
287
- ```javascript
288
- // Find text on the page
289
- const label = await testdriver.find('Sign In', { type: 'text' });
290
- // AI prompt becomes: The text "Sign In"
291
-
292
- // Find an image
293
- const logo = await testdriver.find('company logo', { type: 'image' });
294
- // AI prompt becomes: The image "company logo"
295
-
296
- // Find a UI element (button, input, checkbox, etc.)
297
- const btn = await testdriver.find('Submit', { type: 'ui' });
298
- // AI prompt becomes: The UI element "Submit"
299
-
300
- // No wrapping — same as omitting the option
301
- const el = await testdriver.find('the blue submit button', { type: 'any' });
302
- ```
303
-
304
- | Type | Prompt sent to AI |
305
- |------|----|
306
- | `"text"` | `The text "..."` |
307
- | `"image"` | `The image "..."` |
308
- | `"ui"` | `The UI element "..."` |
309
- | `"any"` | Original description (no wrapping) |
310
-
311
- <Tip>
312
- This is particularly useful for short descriptions like `"Submit"` or `"Login"` where the AI may not know whether to look for a button, a link, or visible text. Specifying `type` removes the ambiguity.
313
- </Tip>
314
- ## Polling for Dynamic Elements
315
-
316
- By default, `find()` polls for up to 10 seconds (retrying every 5 seconds) until the element is found. You can customize this with the `timeout` option:
317
-
318
- ```javascript
319
- // Uses default 10s timeout - polls every 5 seconds
320
- const element = await testdriver.find('login button');
321
- await element.click();
322
-
323
- // Custom timeout - wait up to 30 seconds
324
- const element = await testdriver.find('login button', { timeout: 30000 });
325
- await element.click();
326
-
327
- // Disable polling - single attempt only
328
- const element = await testdriver.find('login button', { timeout: 0 });
329
- ```
330
-
331
- The `timeout` option:
332
- - Defaults to `10000` (10 seconds)
333
- - Retries finding the element every 5 seconds
334
- - Stops when the element is found or the timeout expires
335
- - Logs progress during polling
336
- - Returns the element (check `element.found()` if not throwing on failure)
337
- - Set to `0` to disable polling and make a single attempt
338
-
339
- ## Zoom Mode
340
-
341
- Zoom mode is **disabled by default**. It uses a two-phase approach for better precision when locating elements, especially in crowded UIs with many similar elements.
342
-
343
- To enable zoom for a specific find call, pass `zoom: true`:
344
-
345
- ```javascript
346
- // Enable zoom for better precision in crowded UIs
347
- const extensionsBtn = await testdriver.find('extensions puzzle icon in Chrome toolbar', { zoom: true });
348
- await extensionsBtn.click();
349
-
350
- // Without zoom (default)
351
- const largeButton = await testdriver.find('big hero button');
352
- ```
353
-
354
- ### How Zoom Mode Works
355
-
356
- 1. **Phase 1**: AI identifies the approximate location of the element
357
- 2. **Phase 2**: A 30% crop of the screen is created around that location
358
- 3. **Phase 3**: AI performs precise location on the zoomed/cropped image
359
- 4. **Result**: Coordinates are converted back to absolute screen position
360
-
361
- This two-phase approach gives the AI a higher-resolution view of the target area, improving accuracy when multiple similar elements are close together.
362
-
363
- <Tip>
364
- You may want to enable zoom with `zoom: true` when:
365
- - Targeting small elements in crowded UIs with many similar elements
366
- - You need extra precision for closely spaced UI elements
367
- </Tip>
368
-
369
- ## Verify Mode
370
-
371
- Verify mode is **disabled by default**. When enabled, a second AI call checks that the coordinates returned by `find()` actually correspond to the requested element, catching hallucinated or incorrect positions.
372
-
373
- ```javascript
374
- // Enable verification for critical interactions
375
- const deleteBtn = await testdriver.find('delete account button', { verify: true });
376
- await deleteBtn.click();
377
- ```
378
-
379
- ### How Verify Mode Works
380
-
381
- 1. **Phase 1**: AI locates the element and returns coordinates
382
- 2. **Phase 2**: A second AI call examines the screenshot at those coordinates to confirm the element matches the description
383
- 3. **Result**: If verification fails, the find is retried or marked as not found
384
-
385
- ### Combining Zoom and Verify
386
-
387
- For maximum accuracy, enable both `zoom` and `verify` together. This is useful for critical interactions where clicking the wrong element could cause cascading failures:
388
-
389
- ```javascript
390
- // Maximum accuracy: zoom for precision + verify to catch hallucinations
391
- const element = await testdriver.find('small cancel icon next to the subscription', {
392
- zoom: true,
393
- verify: true,
394
- });
395
- await element.click();
396
- ```
397
-
398
- ## Cache Options
399
-
400
- Control caching behavior to optimize performance, especially when using dynamic variables in prompts.
401
-
402
- ### Custom Cache Key
403
-
404
- Use `cacheKey` to prevent cache pollution when prompts contain variables:
405
-
406
- ```javascript
407
- // ❌ Without cacheKey - creates new cache entry for each email value
408
- const email = 'user@example.com';
409
- await testdriver.find(`input for ${email}`); // Cache miss every time
410
-
411
- // ✅ With cacheKey - reuses cache regardless of variable
412
- const email = 'user@example.com';
413
- await testdriver.find(`input for ${email}`, {
414
- cacheKey: 'email-input'
415
- });
416
-
417
- // Also useful for dynamic IDs, names, or other changing data
418
- const orderId = generateOrderId();
419
- await testdriver.find(`order ${orderId} status`, {
420
- cacheKey: 'order-status' // Same cache for all orders
421
- });
422
- ```
423
-
424
- ### Cache Threshold
425
-
426
- Control how similar a cached result must be to reuse it:
427
-
428
- ```javascript
429
- // Default: 95% similarity required
430
- await testdriver.find('submit button');
431
-
432
- // Strict threshold - 99% similarity required
433
- await testdriver.find('submit button', {
434
- cacheThreshold: 0.01
435
- });
436
-
437
- // Disable cache entirely for this call
438
- await testdriver.find('submit button', {
439
- cacheThreshold: -1
440
- });
441
-
442
- // Combine cacheKey with threshold
443
- await testdriver.find('submit button', {
444
- cacheKey: 'submit-btn',
445
- cacheThreshold: 0.01
446
- });
447
- ```
448
-
449
- <Tip>
450
- By default, TestDriver auto-generates a cache key from the SHA-256 hash of your test file. When you modify your test file, the hash changes automatically, invalidating stale cache entries.
451
- </Tip>
452
-
453
- ### Manual Polling (Alternative)
454
-
455
- If you need custom polling logic:
456
-
457
- ```javascript
458
- async function waitForElement(testdriver, description, timeout = 30000) {
459
- const startTime = Date.now();
460
-
461
- while (Date.now() - startTime < timeout) {
462
- const element = await testdriver.find(description);
463
- if (element.found()) return element;
464
- await new Promise(r => setTimeout(r, 1000));
465
- }
466
-
467
- throw new Error(`Element "${description}" not found after ${timeout}ms`);
468
- }
469
-
470
- // Usage
471
- const button = await waitForElement(testdriver, 'submit button', 10000);
472
- await button.click();
473
- ```
474
-
475
- ## Use Cases
476
-
477
- <AccordionGroup>
478
- <Accordion title="Form Fields">
479
- ```javascript
480
- const emailField = await testdriver.find('email input field');
481
- await emailField.click();
482
- await testdriver.type('user@example.com');
483
-
484
- const passwordField = await testdriver.find('password input');
485
- await passwordField.click();
486
- await testdriver.type('MyP@ssw0rd');
487
- ```
488
- </Accordion>
489
-
490
- <Accordion title="Buttons and Links">
491
- ```javascript
492
- const submitBtn = await testdriver.find('submit button');
493
- await submitBtn.click();
494
-
495
- const cancelLink = await testdriver.find('cancel link');
496
- await cancelLink.click();
497
-
498
- const menuIcon = await testdriver.find('hamburger menu icon');
499
- await menuIcon.click();
500
- ```
501
- </Accordion>
502
-
503
- <Accordion title="Dynamic Content">
504
- ```javascript
505
- // Wait for loading to complete
506
- let content;
507
- for (let i = 0; i < 30; i++) {
508
- content = await testdriver.find('results table');
509
- if (content.found()) break;
510
- await new Promise(r => setTimeout(r, 1000));
511
- }
512
-
513
- // Interact with loaded content
514
- const firstRow = await testdriver.find('first row in the results table');
515
- await firstRow.click();
516
- ```
517
- </Accordion>
518
-
519
- <Accordion title="Complex UI Elements">
520
- ```javascript
521
- // Modals and dialogs
522
- const modal = await testdriver.find('confirmation dialog');
523
- if (modal.found()) {
524
- const confirmBtn = await testdriver.find('confirm button in the dialog');
525
- await confirmBtn.click();
526
- }
527
-
528
- // Dropdown menus
529
- const dropdown = await testdriver.find('country dropdown');
530
- await dropdown.click();
531
-
532
- const option = await testdriver.find('United States option');
533
- await option.click();
534
- ```
535
- </Accordion>
536
- </AccordionGroup>
537
-
538
- ## Complete Example
539
-
540
- ```javascript
541
- import { beforeAll, afterAll, describe, it, expect } from 'vitest';
542
- import TestDriver from 'testdriverai';
543
-
544
- describe('Element Finding', () => {
545
- let testdriver;
546
-
547
- beforeAll(async () => {
548
- client = new TestDriver(process.env.TD_API_KEY);
549
- await testdriver.auth();
550
- await testdriver.connect();
551
- });
552
-
553
- afterAll(async () => {
554
- await testdriver.disconnect();
555
- });
556
-
557
- it('should find and interact with elements', async () => {
558
- await testdriver.focusApplication('Google Chrome');
559
-
560
- // Find login form elements
561
- const usernameField = await testdriver.find('username input field');
562
- expect(usernameField.found()).toBe(true);
563
-
564
- await usernameField.click();
565
- await testdriver.type('testuser');
566
-
567
- // Find with context
568
- const passwordField = await testdriver.find('password input below username');
569
- await passwordField.click();
570
- await testdriver.type('password123');
571
-
572
- // Find button
573
- const submitBtn = await testdriver.find('green submit button');
574
- expect(submitBtn.found()).toBe(true);
575
-
576
- console.log('Button location:', submitBtn.centerX, submitBtn.centerY);
577
-
578
- await submitBtn.click();
579
-
580
- // Wait for success message
581
- let successMsg;
582
- for (let i = 0; i < 10; i++) {
583
- successMsg = await testdriver.find('success notification');
584
- if (successMsg.found()) break;
585
- await new Promise(r => setTimeout(r, 1000));
586
- }
587
-
588
- expect(successMsg.found()).toBe(true);
589
- });
590
- });
591
- ```
592
-
593
- ## Related Methods
594
-
595
- - [`click()`](/v7/click) - Click on found elements
596
- - [`hover()`](/v7/hover) - Hover over elements
597
- - [`assert()`](/v7/assert) - Verify element states
598
- - [Elements Reference](/v7/elements) - Complete Element API
599
-
600
- ---
601
-
602
- ## findAll()
603
-
604
- Locate **all elements** matching a description, rather than just one.
605
-
606
- ### Syntax
607
-
608
- ```javascript
609
- const elements = await testdriver.findAll(description, options)
610
- ```
611
-
612
- ### Parameters
613
-
614
- <ParamField path="description" type="string" required>
615
- Natural language description of elements to find
616
- </ParamField>
617
-
618
- <ParamField path="options" type="object | number">
619
- Optional cache options (same as `find()`)
620
-
621
- <Expandable title="properties">
622
- <ParamField path="cacheKey" type="string">
623
- Cache key for storing element location
624
- </ParamField>
625
-
626
- <ParamField path="cacheThreshold" type="number" default={-1}>
627
- Similarity threshold (0-1) for cache matching. Set to -1 to disable cache.
628
- </ParamField>
629
- </Expandable>
630
- </ParamField>
631
-
632
- ### Returns
633
-
634
- `Promise<Element[]>` - Array of Element instances
635
-
636
- ### Examples
637
-
638
- #### Basic Usage
639
-
640
- ```javascript
641
- // Find all matching elements
642
- const buttons = await testdriver.findAll('button');
643
- console.log(`Found ${buttons.length} buttons`);
644
-
645
- // Interact with specific element
646
- if (buttons.length > 0) {
647
- await buttons[0].click(); // Click first button
648
- }
649
-
650
- // Iterate over all
651
- for (const button of buttons) {
652
- console.log(`Button at (${button.x}, ${button.y})`);
653
- }
654
- ```
655
-
656
- #### Finding Multiple Items
657
-
658
- ```javascript
659
- // Find all list items
660
- const items = await testdriver.findAll('list item');
661
-
662
- // Find specific item by index
663
- const thirdItem = items[2];
664
- await thirdItem.click();
665
-
666
- // Check all items
667
- for (let i = 0; i < items.length; i++) {
668
- console.log(`Item ${i + 1}: ${items[i].text || 'No text'}`);
669
- }
670
- ```
671
-
672
- #### With Caching
673
-
674
- ```javascript
675
- // Cache element locations for faster subsequent runs
676
- const menuItems = await testdriver.findAll('menu item', {
677
- cacheKey: 'main-menu-items'
678
- });
679
-
680
- // First run: ~2-3 seconds (AI call)
681
- // Subsequent runs: ~100ms (cache hit)
682
- ```
683
-
684
- #### Empty Results
685
-
686
- ```javascript
687
- // Returns empty array if nothing found (doesn't throw error)
688
- const errors = await testdriver.findAll('error message');
689
-
690
- if (errors.length === 0) {
691
- console.log('No errors found - test passed!');
692
- } else {
693
- console.log(`Found ${errors.length} errors`);
694
- }
695
- ```
696
-
697
- ### Differences from find()
698
-
699
- | Feature | find() | findAll() |
700
- |---------|--------|-----------|
701
- | Return type | Single `Element` | Array of `Element[]` |
702
- | If nothing found | Throws `ElementNotFoundError` | Returns empty array `[]` |
703
- | Chainable | ✅ Yes: `await find('button').click()` | ❌ No (returns array) |
704
- | Use case | One specific element | Multiple similar elements |
705
- | Cache support | ✅ Yes | ✅ Yes |
706
-
707
- ### Use Cases
708
-
709
- <AccordionGroup>
710
- <Accordion title="Table Rows">
711
- ```javascript
712
- // Find all rows in a table
713
- const rows = await testdriver.findAll('table row');
714
-
715
- // Click every row
716
- for (const row of rows) {
717
- await row.click();
718
- await new Promise(r => setTimeout(r, 500)); // Wait between clicks
719
- }
720
-
721
- // Or click specific row
722
- await rows[2].click(); // Click third row
723
- ```
724
- </Accordion>
725
-
726
- <Accordion title="Checkboxes/Radio Buttons">
727
- ```javascript
728
- // Find all checkboxes
729
- const checkboxes = await testdriver.findAll('checkbox');
730
-
731
- // Check all boxes
732
- for (const checkbox of checkboxes) {
733
- await checkbox.click();
734
- }
735
-
736
- // Or select first unchecked
737
- const unchecked = checkboxes[0];
738
- await unchecked.click();
739
- ```
740
- </Accordion>
741
-
742
- <Accordion title="Navigation Links">
743
- ```javascript
744
- // Find all navigation links
745
- const navLinks = await testdriver.findAll('navigation link');
746
-
747
- // Validate all are present
748
- expect(navLinks.length).toBeGreaterThan(0);
749
-
750
- // Click specific link by text
751
- const homeLink = navLinks.find(link =>
752
- link.text?.toLowerCase().includes('home')
753
- );
754
-
755
- if (homeLink) {
756
- await homeLink.click();
757
- }
758
- ```
759
- </Accordion>
760
-
761
- <Accordion title="Conditional Interactions">
762
- ```javascript
763
- // Check if any error messages exist
764
- const errors = await testdriver.findAll('error message');
765
-
766
- if (errors.length > 0) {
767
- console.log(`Found ${errors.length} validation errors`);
768
-
769
- // Log each error location
770
- errors.forEach((error, i) => {
771
- console.log(`Error ${i + 1} at (${error.x}, ${error.y})`);
772
- });
773
- } else {
774
- console.log('Form validation passed!');
775
- }
776
- ```
777
- </Accordion>
778
- </AccordionGroup>
779
-
780
- ### Complete Example
781
-
782
- ```javascript
783
- import { test, expect } from 'vitest';
784
- import { chrome } from 'testdriverai/presets';
785
-
786
- test('select multiple items from list', async (context) => {
787
- const { testdriver } = await chrome(context, {
788
- url: 'https://example.com/products'
789
- });
790
-
791
- // Find all product cards
792
- const products = await testdriver.findAll('product card');
793
-
794
- expect(products.length).toBeGreaterThan(0);
795
- console.log(`Found ${products.length} products`);
796
-
797
- // Click first 3 products
798
- const productsToSelect = Math.min(3, products.length);
799
-
800
- for (let i = 0; i < productsToSelect; i++) {
801
- await products[i].click();
802
- console.log(`Selected product ${i + 1}`);
803
- await new Promise(r => setTimeout(r, 500)); // Brief pause
804
- }
805
-
806
- // Verify selections
807
- const selectedBadges = await testdriver.findAll('selected badge');
808
- expect(selectedBadges.length).toBe(productsToSelect);
809
- });
810
- ```
811
-
812
- ### Best Practices
813
-
814
- <Check>
815
- **Handle empty arrays gracefully**
816
-
817
- ```javascript
818
- // ✅ Good - check length first
819
- const items = await testdriver.findAll('list item');
820
- if (items.length > 0) {
821
- await items[0].click();
822
- }
823
-
824
- // ❌ Bad - may throw error
825
- const items = await testdriver.findAll('list item');
826
- await items[0].click(); // Error if array is empty!
827
- ```
828
- </Check>
829
-
830
- <Check>
831
- **Use find() for single elements**
832
-
833
- ```javascript
834
- // ✅ Use find() when you need exactly one
835
- const submitBtn = await testdriver.find('submit button');
836
- await submitBtn.click();
837
-
838
- // ❌ Unnecessary - findAll() returns array
839
- const buttons = await testdriver.findAll('submit button');
840
- await buttons[0].click(); // Extra array handling
841
- ```
842
- </Check>
843
-
844
- <Check>
845
- **Cache for performance**
846
-
847
- ```javascript
848
- // First run - slow (AI call)
849
- const items = await testdriver.findAll('menu item', {
850
- cacheKey: 'menu-items'
851
- });
852
-
853
- // Subsequent runs - fast (cache hit)
854
- // ~10-20x faster than without cache
855
- ```
856
- </Check>