testdriverai 7.1.4 → 7.2.2
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/.github/workflows/acceptance.yaml +81 -0
- package/.github/workflows/publish.yaml +44 -0
- package/agent/index.js +18 -19
- package/agent/interface.js +4 -0
- package/agent/lib/commands.js +321 -121
- package/agent/lib/redraw.js +99 -39
- package/agent/lib/sandbox.js +98 -6
- package/agent/lib/sdk.js +25 -0
- package/agent/lib/system.js +2 -1
- package/agent/lib/validation.js +6 -6
- package/docs/docs.json +211 -101
- package/docs/snippets/tests/type-repeated-replay.mdx +1 -1
- package/docs/v7/_drafts/caching-selectors.mdx +24 -0
- package/docs/v7/api/act.mdx +1 -1
- package/docs/v7/api/assert.mdx +1 -1
- package/docs/v7/api/assertions.mdx +7 -7
- package/docs/v7/api/elements.mdx +78 -0
- package/docs/v7/api/find.mdx +38 -0
- package/docs/v7/api/focusApplication.mdx +2 -2
- package/docs/v7/api/hover.mdx +2 -2
- package/docs/v7/features/ai-native.mdx +57 -71
- package/docs/v7/features/application-logs.mdx +353 -0
- package/docs/v7/features/browser-logs.mdx +414 -0
- package/docs/v7/features/cache-management.mdx +402 -0
- package/docs/v7/features/continuous-testing.mdx +346 -0
- package/docs/v7/features/coverage.mdx +508 -0
- package/docs/v7/features/data-driven-testing.mdx +441 -0
- package/docs/v7/features/easy-to-write.mdx +2 -73
- package/docs/v7/features/enterprise.mdx +155 -39
- package/docs/v7/features/fast.mdx +63 -81
- package/docs/v7/features/managed-sandboxes.mdx +384 -0
- package/docs/v7/features/network-monitoring.mdx +568 -0
- package/docs/v7/features/observable.mdx +3 -22
- package/docs/v7/features/parallel-execution.mdx +381 -0
- package/docs/v7/features/powerful.mdx +1 -1
- package/docs/v7/features/reports.mdx +414 -0
- package/docs/v7/features/sandbox-customization.mdx +229 -0
- package/docs/v7/features/scalable.mdx +217 -2
- package/docs/v7/features/stable.mdx +106 -147
- package/docs/v7/features/system-performance.mdx +616 -0
- package/docs/v7/features/test-analytics.mdx +373 -0
- package/docs/v7/features/test-cases.mdx +393 -0
- package/docs/v7/features/test-replays.mdx +408 -0
- package/docs/v7/features/test-reports.mdx +308 -0
- package/docs/v7/getting-started/{running-and-debugging.mdx → debugging-tests.mdx} +12 -142
- package/docs/v7/getting-started/quickstart.mdx +22 -305
- package/docs/v7/getting-started/running-tests.mdx +173 -0
- package/docs/v7/overview/what-is-testdriver.mdx +2 -14
- package/docs/v7/presets/chrome-extension.mdx +147 -122
- package/interfaces/cli/commands/init.js +3 -3
- package/interfaces/cli/lib/base.js +3 -2
- package/interfaces/logger.js +0 -2
- package/interfaces/shared-test-state.mjs +0 -5
- package/interfaces/vitest-plugin.mjs +70 -50
- package/lib/core/Dashcam.js +60 -85
- package/lib/vitest/hooks.mjs +42 -50
- package/package.json +1 -1
- package/sdk-log-formatter.js +350 -175
- package/sdk.d.ts +36 -3
- package/sdk.js +431 -116
- package/setup/aws/cloudformation.yaml +2 -2
- package/setup/aws/self-hosted.yml +1 -1
- package/test/testdriver/chrome-extension.test.mjs +55 -72
- package/test/testdriver/element-not-found.test.mjs +2 -1
- package/test/testdriver/hover-image.test.mjs +1 -1
- package/test/testdriver/scroll-until-text.test.mjs +10 -6
- package/test/testdriver/setup/lifecycleHelpers.mjs +19 -24
- package/test/testdriver/setup/testHelpers.mjs +18 -23
- package/vitest.config.mjs +3 -3
- package/.github/workflows/linux-tests.yml +0 -28
- package/docs/v7/getting-started/generating-tests.mdx +0 -525
- package/test/testdriver/auto-cache-key-demo.test.mjs +0 -56
package/docs/docs.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://mintlify.com/docs.json",
|
|
3
|
-
"theme": "
|
|
3
|
+
"theme": "aspen",
|
|
4
4
|
"name": "TestDriver",
|
|
5
5
|
"colors": {
|
|
6
6
|
"primary": "#b3d334",
|
|
@@ -12,12 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"favicon": "/images/template/icon.png",
|
|
14
14
|
"navigation": {
|
|
15
|
-
"tabs": [
|
|
16
|
-
{
|
|
17
|
-
"tab": "Computer-Use SDK",
|
|
18
15
|
"versions": [
|
|
19
16
|
{
|
|
20
|
-
"version": "v6
|
|
17
|
+
"version": "v6",
|
|
21
18
|
"groups": [
|
|
22
19
|
{
|
|
23
20
|
"group": "Overview",
|
|
@@ -68,24 +65,24 @@
|
|
|
68
65
|
"group": "Apps",
|
|
69
66
|
"icon": "laptop",
|
|
70
67
|
"pages": [
|
|
71
|
-
"apps/static-websites",
|
|
72
|
-
"apps/desktop-apps",
|
|
73
|
-
"apps/chrome-extensions",
|
|
74
|
-
"apps/mobile-apps",
|
|
75
|
-
"apps/tauri-apps"
|
|
68
|
+
"/v6/apps/static-websites",
|
|
69
|
+
"/v6/apps/desktop-apps",
|
|
70
|
+
"/v6/apps/chrome-extensions",
|
|
71
|
+
"/v6/apps/mobile-apps",
|
|
72
|
+
"/v6/apps/tauri-apps"
|
|
76
73
|
]
|
|
77
74
|
},
|
|
78
75
|
{
|
|
79
76
|
"group": "Scenarios",
|
|
80
77
|
"icon": "computer-mouse",
|
|
81
78
|
"pages": [
|
|
82
|
-
"scenarios/ai-chatbot",
|
|
83
|
-
"scenarios/cookie-banner",
|
|
84
|
-
"scenarios/file-upload",
|
|
85
|
-
"scenarios/form-filling",
|
|
86
|
-
"scenarios/log-in",
|
|
87
|
-
"scenarios/pdf-generation",
|
|
88
|
-
"scenarios/spell-check"
|
|
79
|
+
"/v6/scenarios/ai-chatbot",
|
|
80
|
+
"/v6/scenarios/cookie-banner",
|
|
81
|
+
"/v6/scenarios/file-upload",
|
|
82
|
+
"/v6/scenarios/form-filling",
|
|
83
|
+
"/v6/scenarios/log-in",
|
|
84
|
+
"/v6/scenarios/pdf-generation",
|
|
85
|
+
"/v6/scenarios/spell-check"
|
|
89
86
|
]
|
|
90
87
|
},
|
|
91
88
|
{
|
|
@@ -156,7 +153,7 @@
|
|
|
156
153
|
{
|
|
157
154
|
"group": "Reporting",
|
|
158
155
|
"icon": "chart-simple",
|
|
159
|
-
"pages": ["exporting/junit", "/v6/bugs/jira"]
|
|
156
|
+
"pages": ["/v6/exporting/junit", "/v6/bugs/jira"]
|
|
160
157
|
}
|
|
161
158
|
]
|
|
162
159
|
},
|
|
@@ -190,87 +187,140 @@
|
|
|
190
187
|
}
|
|
191
188
|
]
|
|
192
189
|
},
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
190
|
+
{
|
|
191
|
+
"version": "v7",
|
|
192
|
+
"groups": [
|
|
193
|
+
{
|
|
194
|
+
"group": "Getting Started",
|
|
195
|
+
"icon": "rocket",
|
|
196
|
+
"pages": [
|
|
197
|
+
"/v7/getting-started/quickstart"
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"group": "Guides",
|
|
202
|
+
"icon": "book",
|
|
203
|
+
"pages": [
|
|
204
|
+
"/v7/getting-started/writing-tests",
|
|
205
|
+
"/v7/getting-started/running-tests",
|
|
206
|
+
"/v7/getting-started/debugging-tests",
|
|
207
|
+
"/v7/getting-started/setting-up-in-ci"
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"group": "Examples",
|
|
212
|
+
"icon": "code",
|
|
213
|
+
"pages": [
|
|
214
|
+
"/v7/presets/chrome",
|
|
215
|
+
"/v7/presets/chrome-extension",
|
|
216
|
+
"/v7/presets/vscode",
|
|
217
|
+
"/v7/presets/electron"
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"group": "Features",
|
|
222
|
+
"icon": "layer-group",
|
|
223
|
+
"pages": [
|
|
224
|
+
{
|
|
225
|
+
"group": "Selectorless Testing",
|
|
226
|
+
"icon": "sparkles",
|
|
227
|
+
"pages": [
|
|
228
|
+
"/v7/features/easy-to-write",
|
|
229
|
+
"/v7/features/coverage",
|
|
230
|
+
"/v7/features/powerful",
|
|
231
|
+
"/v7/features/ai-native"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"group": "Sandbox Environments",
|
|
236
|
+
"icon": "cube",
|
|
237
|
+
"pages": [
|
|
238
|
+
"/v7/features/managed-sandboxes",
|
|
239
|
+
"/v7/features/sandbox-customization",
|
|
240
|
+
"/v7/features/enterprise"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"group": "Test Observability",
|
|
245
|
+
"icon": "microscope",
|
|
246
|
+
"pages": [
|
|
247
|
+
"/v7/features/application-logs",
|
|
248
|
+
"/v7/features/browser-logs",
|
|
249
|
+
"/v7/features/network-monitoring",
|
|
250
|
+
"/v7/features/system-performance"
|
|
251
|
+
]
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"group": "Performance & Reliability",
|
|
255
|
+
"icon": "gauge-high",
|
|
256
|
+
"pages": [
|
|
257
|
+
"/v7/features/fast",
|
|
258
|
+
"/v7/features/stable",
|
|
259
|
+
"/v7/features/parallel-execution",
|
|
260
|
+
"/v7/features/cache-management"
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"group": "Testing at Scale",
|
|
265
|
+
"icon": "arrow-up-right-dots",
|
|
266
|
+
"pages": [
|
|
267
|
+
"/v7/features/data-driven-testing",
|
|
268
|
+
"/v7/features/continuous-testing"
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"group": "Reports & Analytics",
|
|
273
|
+
"icon": "chart-line",
|
|
274
|
+
"pages": [
|
|
275
|
+
"/v7/features/test-reports",
|
|
276
|
+
"/v7/features/test-analytics",
|
|
277
|
+
"/v7/features/test-cases",
|
|
278
|
+
"/v7/features/test-replays"
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"group": "Reference",
|
|
285
|
+
"icon": "book",
|
|
286
|
+
"pages": [
|
|
287
|
+
{
|
|
288
|
+
"group": "Actions",
|
|
289
|
+
"icon": "bolt",
|
|
290
|
+
"pages": [
|
|
291
|
+
"/v7/api/act",
|
|
292
|
+
"/v7/api/assert",
|
|
293
|
+
"/v7/api/assertions",
|
|
294
|
+
"/v7/api/click",
|
|
295
|
+
"/v7/api/doubleClick",
|
|
296
|
+
"/v7/api/exec",
|
|
297
|
+
"/v7/api/find",
|
|
298
|
+
"/v7/api/focusApplication",
|
|
299
|
+
"/v7/api/hover",
|
|
300
|
+
"/v7/api/mouseDown",
|
|
301
|
+
"/v7/api/mouseUp",
|
|
302
|
+
"/v7/api/pressKeys",
|
|
303
|
+
"/v7/api/rightClick",
|
|
304
|
+
"/v7/api/type",
|
|
305
|
+
"/v7/api/scroll"
|
|
306
|
+
]
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"group": "Client SDK",
|
|
310
|
+
"icon": "code",
|
|
311
|
+
"pages": [
|
|
312
|
+
"/v7/api/client",
|
|
313
|
+
"/v7/api/elements",
|
|
314
|
+
"/v7/api/sandbox",
|
|
315
|
+
"/v7/api/dashcam"
|
|
316
|
+
]
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
|
|
271
323
|
]
|
|
272
|
-
}
|
|
273
|
-
]
|
|
274
324
|
},
|
|
275
325
|
"logo": {
|
|
276
326
|
"light": "/images/template/light.png",
|
|
@@ -307,15 +357,75 @@
|
|
|
307
357
|
"redirects": [
|
|
308
358
|
{
|
|
309
359
|
"source": "/guides/github-actions",
|
|
310
|
-
"destination": "/action/setup"
|
|
360
|
+
"destination": "/v6/action/setup"
|
|
311
361
|
},
|
|
312
362
|
{
|
|
313
363
|
"source": "/reference/test-steps",
|
|
314
|
-
"destination": "/features/selectorless"
|
|
364
|
+
"destination": "/v6/features/selectorless"
|
|
315
365
|
},
|
|
316
366
|
{
|
|
317
367
|
"source": "/guides/debugging-test-runs",
|
|
318
|
-
"destination": "/getting-started/editing"
|
|
368
|
+
"destination": "/v6/getting-started/editing"
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"source": "/overview/:slug*",
|
|
372
|
+
"destination": "/v6/overview/:slug*"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"source": "/features/:slug*",
|
|
376
|
+
"destination": "/v6/features/:slug*"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"source": "/getting-started/:slug*",
|
|
380
|
+
"destination": "/v6/getting-started/:slug*"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"source": "/cli/:slug*",
|
|
384
|
+
"destination": "/v6/cli/:slug*"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"source": "/interactive/:slug*",
|
|
388
|
+
"destination": "/v6/interactive/:slug*"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
"source": "/guide/:slug*",
|
|
392
|
+
"destination": "/v6/guide/:slug*"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"source": "/action/:slug*",
|
|
396
|
+
"destination": "/v6/action/:slug*"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"source": "/account/:slug*",
|
|
400
|
+
"destination": "/v6/account/:slug*"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"source": "/apps/:slug*",
|
|
404
|
+
"destination": "/v6/apps/:slug*"
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"source": "/scenarios/:slug*",
|
|
408
|
+
"destination": "/v6/scenarios/:slug*"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"source": "/integrations/:slug*",
|
|
412
|
+
"destination": "/v6/integrations/:slug*"
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
"source": "/importing/:slug*",
|
|
416
|
+
"destination": "/v6/importing/:slug*"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"source": "/exporting/:slug*",
|
|
420
|
+
"destination": "/v6/exporting/:slug*"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"source": "/bugs/:slug*",
|
|
424
|
+
"destination": "/v6/bugs/:slug*"
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"source": "/commands/:slug*",
|
|
428
|
+
"destination": "/v6/commands/:slug*"
|
|
319
429
|
}
|
|
320
430
|
],
|
|
321
431
|
"integrations": {
|
|
@@ -51,6 +51,30 @@ const button = await testdriver.find('submit button', {
|
|
|
51
51
|
});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
**Use Case - Variables in Test Steps:**
|
|
55
|
+
|
|
56
|
+
Custom cache keys are especially useful when you use variables in your test steps, ensuring consistent caching regardless of the variable values:
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
// Without custom cache key - each variable value creates a new cache entry
|
|
60
|
+
const userName = 'john.doe@example.com';
|
|
61
|
+
await testdriver.find(`input field for ${userName}`); // Cache miss every time
|
|
62
|
+
|
|
63
|
+
// With custom cache key - all values share the same cache
|
|
64
|
+
const userName = 'john.doe@example.com';
|
|
65
|
+
await testdriver.find(`input field for ${userName}`, {
|
|
66
|
+
cacheKey: 'email-input-field' // Same cache key regardless of userName value
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Another example with dynamic data
|
|
70
|
+
const productId = '12345';
|
|
71
|
+
await testdriver.find(`product card for ${productId}`, {
|
|
72
|
+
cacheKey: 'product-card' // Reuses cache for any productId
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This prevents cache pollution and improves cache hit rates when your prompts include dynamic values.
|
|
77
|
+
|
|
54
78
|
### Global Cache Key
|
|
55
79
|
|
|
56
80
|
Enable caching for all finds in your test:
|
package/docs/v7/api/act.mdx
CHANGED
|
@@ -184,7 +184,7 @@ describe('E-commerce Flow with AI', () => {
|
|
|
184
184
|
const cartIcon = await testdriver.find('shopping cart icon');
|
|
185
185
|
await cartIcon.click();
|
|
186
186
|
|
|
187
|
-
const total = await testdriver.
|
|
187
|
+
const total = await testdriver.extract('the cart total amount');
|
|
188
188
|
console.log('Cart total:', total);
|
|
189
189
|
|
|
190
190
|
// Use AI for checkout flow
|
package/docs/v7/api/assert.mdx
CHANGED
|
@@ -98,7 +98,7 @@ await testdriver.assert('the modal dialog is open');
|
|
|
98
98
|
expect(result).toBeTruthy();
|
|
99
99
|
|
|
100
100
|
// Extract for detailed comparison
|
|
101
|
-
const message = await testdriver.
|
|
101
|
+
const message = await testdriver.extract('the success message text');
|
|
102
102
|
expect(message).toContain('successfully');
|
|
103
103
|
```
|
|
104
104
|
</Check>
|
|
@@ -264,9 +264,9 @@ describe('E2E Shopping Flow', () => {
|
|
|
264
264
|
// Verify cart updated
|
|
265
265
|
await testdriver.assert('cart badge shows 1 item');
|
|
266
266
|
|
|
267
|
-
//
|
|
268
|
-
const productName = await testdriver.
|
|
269
|
-
const price = await testdriver.
|
|
267
|
+
// Extract product details
|
|
268
|
+
const productName = await testdriver.extract('the name of the product just added');
|
|
269
|
+
const price = await testdriver.extract('the price of the product');
|
|
270
270
|
|
|
271
271
|
console.log(`Added ${productName} at ${price}`);
|
|
272
272
|
|
|
@@ -302,7 +302,7 @@ describe('E2E Shopping Flow', () => {
|
|
|
302
302
|
await testdriver.assert('success message is shown');
|
|
303
303
|
|
|
304
304
|
// Extract order number
|
|
305
|
-
const orderNumber = await testdriver.
|
|
305
|
+
const orderNumber = await testdriver.extract('the order number');
|
|
306
306
|
console.log('Order placed:', orderNumber);
|
|
307
307
|
expect(orderNumber).toBeTruthy();
|
|
308
308
|
});
|
|
@@ -377,10 +377,10 @@ describe('E2E Shopping Flow', () => {
|
|
|
377
377
|
</Accordion>
|
|
378
378
|
|
|
379
379
|
<Accordion title="Extract before comparing">
|
|
380
|
-
Use `
|
|
380
|
+
Use `extract()` to extract values for detailed comparisons:
|
|
381
381
|
|
|
382
382
|
```javascript
|
|
383
|
-
const actualTotal = await testdriver.
|
|
383
|
+
const actualTotal = await testdriver.extract('the cart total');
|
|
384
384
|
const expectedTotal = '$99.99';
|
|
385
385
|
|
|
386
386
|
expect(actualTotal).toBe(expectedTotal);
|
|
@@ -395,7 +395,7 @@ describe('E2E Shopping Flow', () => {
|
|
|
395
395
|
await testdriver.assert('success message is displayed');
|
|
396
396
|
|
|
397
397
|
// Extract and use traditional assertion for exact values
|
|
398
|
-
const message = await testdriver.
|
|
398
|
+
const message = await testdriver.extract('the success message text');
|
|
399
399
|
expect(message).toContain('successfully');
|
|
400
400
|
expect(message).toMatch(/order #\d+/i);
|
|
401
401
|
```
|
package/docs/v7/api/elements.mdx
CHANGED
|
@@ -418,6 +418,84 @@ if (element.confidence !== null) {
|
|
|
418
418
|
Properties marked with ⚠️ may be `null` depending on what the AI could detect from the screenshot.
|
|
419
419
|
</Note>
|
|
420
420
|
|
|
421
|
+
## JSON Serialization
|
|
422
|
+
|
|
423
|
+
Element objects can be safely serialized using `JSON.stringify()` for logging, debugging, and data storage. Circular references are automatically removed:
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
const element = await testdriver.find('login button');
|
|
427
|
+
|
|
428
|
+
// Safe to stringify - no circular reference errors!
|
|
429
|
+
console.log(JSON.stringify(element, null, 2));
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Serialized output includes:**
|
|
433
|
+
|
|
434
|
+
```json
|
|
435
|
+
{
|
|
436
|
+
"description": "login button",
|
|
437
|
+
"coordinates": { "x": 100, "y": 200, "centerX": 150, "centerY": 225 },
|
|
438
|
+
"found": true,
|
|
439
|
+
"threshold": 0.01,
|
|
440
|
+
"x": 100,
|
|
441
|
+
"y": 200,
|
|
442
|
+
"cache": {
|
|
443
|
+
"hit": true,
|
|
444
|
+
"strategy": "pixel-diff",
|
|
445
|
+
"createdAt": "2025-12-09T10:30:00.000Z",
|
|
446
|
+
"diffPercent": 0.0023,
|
|
447
|
+
"imageUrl": "https://cache.testdriver.ai/..."
|
|
448
|
+
},
|
|
449
|
+
"similarity": 0.98,
|
|
450
|
+
"confidence": 0.95,
|
|
451
|
+
"selector": "button#login",
|
|
452
|
+
"aiResponse": "Found the blue login button in the center of the form..."
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Serialized properties:**
|
|
457
|
+
|
|
458
|
+
| Property | Type | Description |
|
|
459
|
+
|----------|------|-------------|
|
|
460
|
+
| `description` | string | Element search description |
|
|
461
|
+
| `coordinates` | object | Full coordinate object `{x, y, centerX, centerY}` |
|
|
462
|
+
| `found` | boolean | Whether element was located |
|
|
463
|
+
| `threshold` | number | Cache threshold used for this find |
|
|
464
|
+
| `x`, `y` | number | Top-left coordinates |
|
|
465
|
+
| `cache.hit` | boolean | Whether cache was used |
|
|
466
|
+
| `cache.strategy` | string | Cache strategy (e.g., "pixel-diff") |
|
|
467
|
+
| `cache.createdAt` | string | ISO timestamp when cache was created |
|
|
468
|
+
| `cache.diffPercent` | number | Pixel difference from cached image |
|
|
469
|
+
| `cache.imageUrl` | string | URL to cached screenshot |
|
|
470
|
+
| `similarity` | number | Similarity score (0-1) |
|
|
471
|
+
| `confidence` | number | AI confidence score (0-1) |
|
|
472
|
+
| `selector` | string | CSS/XPath selector if available |
|
|
473
|
+
| `aiResponse` | string | AI's explanation of what it found |
|
|
474
|
+
|
|
475
|
+
**Use cases:**
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
// Debugging element detection
|
|
479
|
+
const element = await testdriver.find('submit button');
|
|
480
|
+
if (!element.found()) {
|
|
481
|
+
console.error('Element not found:', JSON.stringify(element, null, 2));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Logging cache performance
|
|
485
|
+
const data = JSON.parse(JSON.stringify(element));
|
|
486
|
+
if (data.cache.hit) {
|
|
487
|
+
console.log(`Cache hit! Diff: ${(data.cache.diffPercent * 100).toFixed(2)}%`);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Sharing element data across processes
|
|
491
|
+
const elementData = JSON.stringify(element);
|
|
492
|
+
// Send to another process, log to file, etc.
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
<Tip>
|
|
496
|
+
Use JSON serialization when you need to log element data or when debugging why an element wasn't found. The serialized output excludes large binary data (screenshots) and circular references.
|
|
497
|
+
</Tip>
|
|
498
|
+
|
|
421
499
|
## Polling for Elements
|
|
422
500
|
|
|
423
501
|
Use polling to wait for elements that may not be immediately visible:
|
package/docs/v7/api/find.mdx
CHANGED
|
@@ -103,6 +103,44 @@ The returned `Element` object provides:
|
|
|
103
103
|
|
|
104
104
|
See [Elements Reference](/v7/api/elements) for complete details.
|
|
105
105
|
|
|
106
|
+
### JSON Serialization
|
|
107
|
+
|
|
108
|
+
Elements can be safely serialized using `JSON.stringify()` for logging and debugging. Circular references are automatically removed:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const element = await testdriver.find('login button');
|
|
112
|
+
|
|
113
|
+
// Safe to stringify - no circular reference errors
|
|
114
|
+
console.log(JSON.stringify(element, null, 2));
|
|
115
|
+
|
|
116
|
+
// Output includes useful debugging info:
|
|
117
|
+
// {
|
|
118
|
+
// "description": "login button",
|
|
119
|
+
// "coordinates": { "x": 100, "y": 200, "centerX": 150, "centerY": 225 },
|
|
120
|
+
// "found": true,
|
|
121
|
+
// "threshold": 0.01,
|
|
122
|
+
// "x": 100,
|
|
123
|
+
// "y": 200,
|
|
124
|
+
// "cache": {
|
|
125
|
+
// "hit": true,
|
|
126
|
+
// "strategy": "pixel-diff",
|
|
127
|
+
// "createdAt": "2025-12-09T10:30:00Z",
|
|
128
|
+
// "diffPercent": 0.0023,
|
|
129
|
+
// "imageUrl": "https://..."
|
|
130
|
+
// },
|
|
131
|
+
// "similarity": 0.98,
|
|
132
|
+
// "confidence": 0.95,
|
|
133
|
+
// "selector": "button#login",
|
|
134
|
+
// "aiResponse": "Found the blue login button..."
|
|
135
|
+
// }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This is useful for:
|
|
139
|
+
- Debugging element detection issues
|
|
140
|
+
- Logging test execution details
|
|
141
|
+
- Sharing element information across processes
|
|
142
|
+
- Analyzing cache performance
|
|
143
|
+
|
|
106
144
|
## Best Practices
|
|
107
145
|
|
|
108
146
|
<Check>
|
|
@@ -113,7 +113,7 @@ await testdriver.focusApplication('Google Chrome');
|
|
|
113
113
|
```javascript
|
|
114
114
|
// Test workflow across multiple apps
|
|
115
115
|
await testdriver.focusApplication('Google Chrome');
|
|
116
|
-
const data = await testdriver.
|
|
116
|
+
const data = await testdriver.extract('the order number');
|
|
117
117
|
|
|
118
118
|
await testdriver.focusApplication('Notepad');
|
|
119
119
|
await testdriver.type(data);
|
|
@@ -221,7 +221,7 @@ describe('Multi-Application Workflow', () => {
|
|
|
221
221
|
await testdriver.focusApplication('Google Chrome');
|
|
222
222
|
|
|
223
223
|
// Get data from web page
|
|
224
|
-
const orderNumber = await testdriver.
|
|
224
|
+
const orderNumber = await testdriver.extract('the order number');
|
|
225
225
|
console.log('Order:', orderNumber);
|
|
226
226
|
|
|
227
227
|
// Open Notepad
|
package/docs/v7/api/hover.mdx
CHANGED
|
@@ -130,7 +130,7 @@ await new Promise(r => setTimeout(r, 1000));
|
|
|
130
130
|
await new Promise(r => setTimeout(r, 1000));
|
|
131
131
|
|
|
132
132
|
// Read tooltip content
|
|
133
|
-
const tooltipText = await testdriver.
|
|
133
|
+
const tooltipText = await testdriver.extract('the tooltip text');
|
|
134
134
|
console.log('Tooltip:', tooltipText);
|
|
135
135
|
```
|
|
136
136
|
</Accordion>
|
|
@@ -225,7 +225,7 @@ describe('Hover Interactions', () => {
|
|
|
225
225
|
await testdriver.assert('tooltip is displayed');
|
|
226
226
|
|
|
227
227
|
// Extract tooltip text
|
|
228
|
-
const tooltipText = await testdriver.
|
|
228
|
+
const tooltipText = await testdriver.extract('the tooltip message');
|
|
229
229
|
console.log('Tooltip says:', tooltipText);
|
|
230
230
|
});
|
|
231
231
|
|