testdriverai 7.0.0 → 7.1.0
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/AGENTS.md +550 -0
- package/CODEOWNERS +0 -1
- package/README.md +126 -0
- package/agent/index.js +43 -18
- package/agent/lib/commands.js +794 -135
- package/agent/lib/redraw.js +124 -39
- package/agent/lib/sandbox.js +10 -1
- package/agent/lib/sdk.js +21 -0
- package/docs/MIGRATION.md +425 -0
- package/docs/PRESETS.md +210 -0
- package/docs/docs.json +91 -37
- package/docs/guide/best-practices-polling.mdx +154 -0
- package/docs/v7/api/dashcam.mdx +497 -0
- package/docs/v7/api/doubleClick.mdx +102 -0
- package/docs/v7/api/mouseDown.mdx +161 -0
- package/docs/v7/api/mouseUp.mdx +164 -0
- package/docs/v7/api/rightClick.mdx +123 -0
- package/docs/v7/getting-started/configuration.mdx +380 -0
- package/docs/v7/getting-started/quickstart.mdx +273 -140
- package/docs/v7/guides/best-practices.mdx +486 -0
- package/docs/v7/guides/caching-ai.mdx +215 -0
- package/docs/v7/guides/caching-selectors.mdx +292 -0
- package/docs/v7/guides/caching.mdx +366 -0
- package/docs/v7/guides/ci-cd/azure.mdx +587 -0
- package/docs/v7/guides/ci-cd/circleci.mdx +523 -0
- package/docs/v7/guides/ci-cd/github-actions.mdx +457 -0
- package/docs/v7/guides/ci-cd/gitlab.mdx +498 -0
- package/docs/v7/guides/ci-cd/jenkins.mdx +664 -0
- package/docs/v7/guides/ci-cd/travis.mdx +438 -0
- package/docs/v7/guides/debugging.mdx +349 -0
- package/docs/v7/guides/faq.mdx +393 -0
- package/docs/v7/guides/performance.mdx +517 -0
- package/docs/v7/guides/troubleshooting.mdx +526 -0
- package/docs/v7/guides/vitest-plugin.mdx +477 -0
- package/docs/v7/guides/vitest.mdx +535 -0
- package/docs/v7/platforms/linux.mdx +308 -0
- package/docs/v7/platforms/macos.mdx +433 -0
- package/docs/v7/platforms/windows.mdx +430 -0
- package/docs/v7/presets/chrome-extension.mdx +223 -0
- package/docs/v7/presets/chrome.mdx +287 -0
- package/docs/v7/presets/electron.mdx +435 -0
- package/docs/v7/presets/vscode.mdx +398 -0
- package/docs/v7/presets/webapp.mdx +396 -0
- package/docs/v7/progressive-apis/CORE.md +459 -0
- package/docs/v7/progressive-apis/HOOKS.md +360 -0
- package/docs/v7/progressive-apis/PROGRESSIVE_DISCLOSURE.md +230 -0
- package/docs/v7/progressive-apis/PROVISION.md +266 -0
- package/interfaces/vitest-plugin.mjs +186 -100
- package/package.json +12 -1
- package/sdk.d.ts +335 -42
- package/sdk.js +756 -95
- package/src/core/Dashcam.js +469 -0
- package/src/core/index.d.ts +150 -0
- package/src/core/index.js +12 -0
- package/src/presets/index.mjs +331 -0
- package/src/vitest/extended.mjs +108 -0
- package/src/vitest/hooks.d.ts +119 -0
- package/src/vitest/hooks.mjs +298 -0
- package/src/vitest/index.mjs +64 -0
- package/src/vitest/lifecycle.mjs +277 -0
- package/src/vitest/utils.mjs +150 -0
- package/test/dashcam.test.js +137 -0
- package/testdriver/acceptance-sdk/assert.test.mjs +13 -31
- package/testdriver/acceptance-sdk/auto-cache-key-demo.test.mjs +56 -0
- package/testdriver/acceptance-sdk/chrome-extension.test.mjs +89 -0
- package/testdriver/acceptance-sdk/drag-and-drop.test.mjs +7 -19
- package/testdriver/acceptance-sdk/element-not-found.test.mjs +6 -19
- package/testdriver/acceptance-sdk/exec-js.test.mjs +6 -18
- package/testdriver/acceptance-sdk/exec-output.test.mjs +8 -20
- package/testdriver/acceptance-sdk/exec-pwsh.test.mjs +13 -25
- package/testdriver/acceptance-sdk/focus-window.test.mjs +8 -20
- package/testdriver/acceptance-sdk/formatted-logging.test.mjs +5 -20
- package/testdriver/acceptance-sdk/hooks-example.test.mjs +38 -0
- package/testdriver/acceptance-sdk/hover-image.test.mjs +10 -19
- package/testdriver/acceptance-sdk/hover-text-with-description.test.mjs +7 -19
- package/testdriver/acceptance-sdk/hover-text.test.mjs +5 -19
- package/testdriver/acceptance-sdk/match-image.test.mjs +7 -19
- package/testdriver/acceptance-sdk/presets-example.test.mjs +87 -0
- package/testdriver/acceptance-sdk/press-keys.test.mjs +5 -19
- package/testdriver/acceptance-sdk/prompt.test.mjs +6 -18
- package/testdriver/acceptance-sdk/scroll-keyboard.test.mjs +6 -20
- package/testdriver/acceptance-sdk/scroll-until-image.test.mjs +6 -18
- package/testdriver/acceptance-sdk/scroll-until-text.test.mjs +9 -23
- package/testdriver/acceptance-sdk/scroll.test.mjs +12 -21
- package/testdriver/acceptance-sdk/setup/testHelpers.mjs +124 -352
- package/testdriver/acceptance-sdk/sully-ai.test.mjs +234 -0
- package/testdriver/acceptance-sdk/test-console-logs.test.mjs +42 -0
- package/testdriver/acceptance-sdk/type.test.mjs +19 -58
- package/vitest.config.mjs +1 -0
- package/.vscode/mcp.json +0 -9
- package/MIGRATION.md +0 -389
- package/PLUGIN_MIGRATION.md +0 -222
- package/PROMPT_CACHE.md +0 -200
- package/SDK_LOGGING.md +0 -222
- package/SDK_MIGRATION.md +0 -474
- package/SDK_README.md +0 -1122
- package/debug-screenshot-1763401388589.png +0 -0
- package/examples/run-tests-with-recording.sh +0 -70
- package/examples/screenshot-example.js +0 -63
- package/examples/sdk-awesome-logs-demo.js +0 -177
- package/examples/sdk-cache-thresholds.js +0 -96
- package/examples/sdk-element-properties.js +0 -155
- package/examples/sdk-simple-example.js +0 -65
- package/examples/test-recording-example.test.js +0 -166
- package/mcp-server/AI_GUIDELINES.md +0 -57
- package/test-find-api.js +0 -73
- package/test-prompt-cache.js +0 -96
- package/test-sandbox-render.js +0 -28
- package/test-sdk-methods.js +0 -15
- package/test-sdk-refactor.js +0 -53
- package/test-stack-trace.mjs +0 -57
- package/testdriver/acceptance-sdk/setup/lifecycleHelpers.mjs +0 -239
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Dashcam"
|
|
3
|
+
sidebarTitle: "Dashcam"
|
|
4
|
+
description: "Record test execution with video and logs"
|
|
5
|
+
icon: "video"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Dashcam provides automatic video recording and log aggregation for your tests. It captures screen recordings, application logs, and test execution details that can be reviewed later.
|
|
11
|
+
|
|
12
|
+
## Basic Usage
|
|
13
|
+
|
|
14
|
+
### With Presets
|
|
15
|
+
|
|
16
|
+
Most presets automatically include Dashcam:
|
|
17
|
+
|
|
18
|
+
```javascript
|
|
19
|
+
import { test } from 'vitest';
|
|
20
|
+
import { chrome } from 'testdriverai/presets';
|
|
21
|
+
|
|
22
|
+
test('my test', async (context) => {
|
|
23
|
+
const { testdriver, dashcam } = await chrome(context, {
|
|
24
|
+
url: 'https://example.com'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Test executes with recording automatically
|
|
28
|
+
await testdriver.find('login button').then(el => el.click());
|
|
29
|
+
|
|
30
|
+
// Dashcam URL available after test
|
|
31
|
+
console.log('Replay:', dashcam.url);
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Manual Setup
|
|
36
|
+
|
|
37
|
+
For more control, create a Dashcam instance directly:
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
import TestDriver from 'testdriverai';
|
|
41
|
+
import Dashcam from 'testdriverai/src/core/Dashcam.js';
|
|
42
|
+
|
|
43
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
44
|
+
const dashcam = new Dashcam(client, {
|
|
45
|
+
apiKey: process.env.DASHCAM_API_KEY
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await dashcam.auth();
|
|
49
|
+
await dashcam.start();
|
|
50
|
+
|
|
51
|
+
// Run your tests
|
|
52
|
+
|
|
53
|
+
const url = await dashcam.stop();
|
|
54
|
+
console.log('Replay URL:', url);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Constructor
|
|
58
|
+
|
|
59
|
+
Create a new Dashcam instance:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
new Dashcam(client, options)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Parameters
|
|
66
|
+
|
|
67
|
+
<ParamField path="client" type="TestDriver" required>
|
|
68
|
+
TestDriver client instance
|
|
69
|
+
</ParamField>
|
|
70
|
+
|
|
71
|
+
<ParamField path="options" type="object">
|
|
72
|
+
Configuration options
|
|
73
|
+
|
|
74
|
+
<Expandable title="options properties">
|
|
75
|
+
<ParamField path="apiKey" type="string" default="4e93d8bf-3886-4d26-a144-116c4063522d">
|
|
76
|
+
Dashcam API key for authentication
|
|
77
|
+
</ParamField>
|
|
78
|
+
|
|
79
|
+
<ParamField path="autoStart" type="boolean" default={false}>
|
|
80
|
+
Automatically start recording after authentication
|
|
81
|
+
</ParamField>
|
|
82
|
+
|
|
83
|
+
<ParamField path="logs" type="array" default={[]}>
|
|
84
|
+
Log configurations to add automatically
|
|
85
|
+
</ParamField>
|
|
86
|
+
</Expandable>
|
|
87
|
+
</ParamField>
|
|
88
|
+
|
|
89
|
+
## Methods
|
|
90
|
+
|
|
91
|
+
### auth()
|
|
92
|
+
|
|
93
|
+
Authenticate with Dashcam service:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
await dashcam.auth(apiKey)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
<ParamField path="apiKey" type="string" optional>
|
|
100
|
+
Override the API key set in constructor
|
|
101
|
+
</ParamField>
|
|
102
|
+
|
|
103
|
+
**Returns:** `Promise<void>`
|
|
104
|
+
|
|
105
|
+
**Example:**
|
|
106
|
+
```javascript
|
|
107
|
+
await dashcam.auth('your-api-key');
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### start()
|
|
111
|
+
|
|
112
|
+
Start recording:
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
await dashcam.start()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Returns:** `Promise<void>`
|
|
119
|
+
|
|
120
|
+
**Example:**
|
|
121
|
+
```javascript
|
|
122
|
+
await dashcam.start();
|
|
123
|
+
console.log('Recording started');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### stop()
|
|
127
|
+
|
|
128
|
+
Stop recording and retrieve replay URL:
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
await dashcam.stop()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Returns:** `Promise<string|null>` - Replay URL if available
|
|
135
|
+
|
|
136
|
+
**Example:**
|
|
137
|
+
```javascript
|
|
138
|
+
const url = await dashcam.stop();
|
|
139
|
+
if (url) {
|
|
140
|
+
console.log('Watch replay:', url);
|
|
141
|
+
} else {
|
|
142
|
+
console.log('No replay URL available');
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### addFileLog()
|
|
147
|
+
|
|
148
|
+
Track a log file in the recording:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
await dashcam.addFileLog(path, name)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
<ParamField path="path" type="string" required>
|
|
155
|
+
Path to the log file
|
|
156
|
+
</ParamField>
|
|
157
|
+
|
|
158
|
+
<ParamField path="name" type="string" required>
|
|
159
|
+
Display name for the log in Dashcam
|
|
160
|
+
</ParamField>
|
|
161
|
+
|
|
162
|
+
**Returns:** `Promise<void>`
|
|
163
|
+
|
|
164
|
+
**Example:**
|
|
165
|
+
```javascript
|
|
166
|
+
// Linux/Mac
|
|
167
|
+
await dashcam.addFileLog('/tmp/app.log', 'Application Log');
|
|
168
|
+
|
|
169
|
+
// Windows
|
|
170
|
+
await dashcam.addFileLog('C:\\logs\\app.log', 'Application Log');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### addApplicationLog()
|
|
174
|
+
|
|
175
|
+
Track application-specific logs:
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
await dashcam.addApplicationLog(application, name)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
<ParamField path="application" type="string" required>
|
|
182
|
+
Application name to track
|
|
183
|
+
</ParamField>
|
|
184
|
+
|
|
185
|
+
<ParamField path="name" type="string" required>
|
|
186
|
+
Display name for the log
|
|
187
|
+
</ParamField>
|
|
188
|
+
|
|
189
|
+
**Returns:** `Promise<void>`
|
|
190
|
+
|
|
191
|
+
**Example:**
|
|
192
|
+
```javascript
|
|
193
|
+
await dashcam.addApplicationLog('Google Chrome', 'Browser Logs');
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### addLog()
|
|
197
|
+
|
|
198
|
+
Generic method to add any type of log:
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
await dashcam.addLog(config)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
<ParamField path="config" type="object" required>
|
|
205
|
+
Log configuration
|
|
206
|
+
|
|
207
|
+
<Expandable title="config properties">
|
|
208
|
+
<ParamField path="name" type="string" required>
|
|
209
|
+
Display name for the log
|
|
210
|
+
</ParamField>
|
|
211
|
+
|
|
212
|
+
<ParamField path="type" type="string" required>
|
|
213
|
+
Log type: `'file'`, `'stdout'`, or `'application'`
|
|
214
|
+
</ParamField>
|
|
215
|
+
|
|
216
|
+
<ParamField path="path" type="string">
|
|
217
|
+
File path (required for type='file')
|
|
218
|
+
</ParamField>
|
|
219
|
+
|
|
220
|
+
<ParamField path="application" type="string">
|
|
221
|
+
Application name (required for type='application')
|
|
222
|
+
</ParamField>
|
|
223
|
+
</Expandable>
|
|
224
|
+
</ParamField>
|
|
225
|
+
|
|
226
|
+
**Returns:** `Promise<void>`
|
|
227
|
+
|
|
228
|
+
**Example:**
|
|
229
|
+
```javascript
|
|
230
|
+
await dashcam.addLog({
|
|
231
|
+
name: 'Test Output',
|
|
232
|
+
type: 'file',
|
|
233
|
+
path: '/tmp/test.log'
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await dashcam.addLog({
|
|
237
|
+
name: 'Chrome Logs',
|
|
238
|
+
type: 'application',
|
|
239
|
+
application: 'Google Chrome'
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### isRecording()
|
|
244
|
+
|
|
245
|
+
Check if currently recording:
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
await dashcam.isRecording()
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Returns:** `Promise<boolean>` - True if recording is active
|
|
252
|
+
|
|
253
|
+
**Example:**
|
|
254
|
+
```javascript
|
|
255
|
+
if (await dashcam.isRecording()) {
|
|
256
|
+
console.log('Recording in progress');
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Properties
|
|
261
|
+
|
|
262
|
+
### recording
|
|
263
|
+
|
|
264
|
+
Current recording state:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
dashcam.recording // boolean
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### apiKey
|
|
271
|
+
|
|
272
|
+
Configured API key:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
dashcam.apiKey // string
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### client
|
|
279
|
+
|
|
280
|
+
Associated TestDriver client:
|
|
281
|
+
|
|
282
|
+
```javascript
|
|
283
|
+
dashcam.client // TestDriver instance
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Complete Examples
|
|
287
|
+
|
|
288
|
+
### Basic Recording
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
import { test } from 'vitest';
|
|
292
|
+
import TestDriver from 'testdriverai';
|
|
293
|
+
import Dashcam from 'testdriverai/src/core/Dashcam.js';
|
|
294
|
+
|
|
295
|
+
test('record test execution', async () => {
|
|
296
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
297
|
+
const dashcam = new Dashcam(client);
|
|
298
|
+
|
|
299
|
+
await dashcam.auth();
|
|
300
|
+
await dashcam.start();
|
|
301
|
+
|
|
302
|
+
// Run your test
|
|
303
|
+
await client.find('button').then(el => el.click());
|
|
304
|
+
|
|
305
|
+
const url = await dashcam.stop();
|
|
306
|
+
console.log('Replay:', url);
|
|
307
|
+
|
|
308
|
+
await client.cleanup();
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### With Log Tracking
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
test('record with logs', async () => {
|
|
316
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
317
|
+
const dashcam = new Dashcam(client);
|
|
318
|
+
|
|
319
|
+
await dashcam.auth();
|
|
320
|
+
|
|
321
|
+
// Add log files before starting
|
|
322
|
+
await dashcam.addFileLog('/tmp/testdriver.log', 'TestDriver Log');
|
|
323
|
+
await dashcam.addFileLog('/tmp/app.log', 'Application Log');
|
|
324
|
+
|
|
325
|
+
await dashcam.start();
|
|
326
|
+
|
|
327
|
+
// Test execution
|
|
328
|
+
await client.find('login button').then(el => el.click());
|
|
329
|
+
|
|
330
|
+
const url = await dashcam.stop();
|
|
331
|
+
console.log('Replay with logs:', url);
|
|
332
|
+
|
|
333
|
+
await client.cleanup();
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Auto-start Configuration
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
test('auto-start recording', async () => {
|
|
341
|
+
const client = await TestDriver.create({ os: 'linux' });
|
|
342
|
+
const dashcam = new Dashcam(client, {
|
|
343
|
+
autoStart: true,
|
|
344
|
+
logs: [
|
|
345
|
+
{
|
|
346
|
+
name: 'App Log',
|
|
347
|
+
type: 'file',
|
|
348
|
+
path: '/tmp/app.log'
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
await dashcam.auth(); // Automatically starts recording
|
|
354
|
+
|
|
355
|
+
// Test execution
|
|
356
|
+
await client.find('submit button').then(el => el.click());
|
|
357
|
+
|
|
358
|
+
const url = await dashcam.stop();
|
|
359
|
+
console.log('Replay:', url);
|
|
360
|
+
|
|
361
|
+
await client.cleanup();
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Using with Presets
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
import { chrome } from 'testdriverai/presets';
|
|
369
|
+
|
|
370
|
+
test('preset with dashcam', async (context) => {
|
|
371
|
+
const { testdriver, dashcam } = await chrome(context, {
|
|
372
|
+
url: 'https://example.com',
|
|
373
|
+
dashcam: true // Enabled by default
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Test runs with automatic recording
|
|
377
|
+
await testdriver.find('button').then(el => el.click());
|
|
378
|
+
|
|
379
|
+
// URL automatically available
|
|
380
|
+
console.log('Replay:', dashcam.url);
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Disabling Dashcam in Presets
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
test('without dashcam', async (context) => {
|
|
388
|
+
const { testdriver } = await chrome(context, {
|
|
389
|
+
url: 'https://example.com',
|
|
390
|
+
dashcam: false // Disable recording
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Test runs without recording (faster)
|
|
394
|
+
await testdriver.find('button').then(el => el.click());
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Platform Differences
|
|
399
|
+
|
|
400
|
+
### Windows
|
|
401
|
+
|
|
402
|
+
On Windows, Dashcam uses PowerShell commands and installs via npm:
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
// Windows-specific paths
|
|
406
|
+
await dashcam.addFileLog(
|
|
407
|
+
'C:\\Users\\testdriver\\Documents\\testdriver.log',
|
|
408
|
+
'TestDriver Log'
|
|
409
|
+
);
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Linux/Mac
|
|
413
|
+
|
|
414
|
+
On Linux/Mac, Dashcam uses shell commands:
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
// Unix-specific paths
|
|
418
|
+
await dashcam.addFileLog('/tmp/testdriver.log', 'TestDriver Log');
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Troubleshooting
|
|
422
|
+
|
|
423
|
+
### No Replay URL Returned
|
|
424
|
+
|
|
425
|
+
If `stop()` returns `null`:
|
|
426
|
+
|
|
427
|
+
1. Check that recording was started with `start()`
|
|
428
|
+
2. Verify authentication succeeded
|
|
429
|
+
3. Ensure dashcam CLI is installed in the environment
|
|
430
|
+
4. Check console output for error messages
|
|
431
|
+
|
|
432
|
+
### Recording Not Starting
|
|
433
|
+
|
|
434
|
+
If recording doesn't start:
|
|
435
|
+
|
|
436
|
+
1. Verify API key is correct
|
|
437
|
+
2. Check `auth()` completed successfully
|
|
438
|
+
3. Ensure dashcam CLI is installed globally
|
|
439
|
+
4. Check `isRecording()` to verify state
|
|
440
|
+
|
|
441
|
+
### Logs Not Appearing
|
|
442
|
+
|
|
443
|
+
If logs aren't visible in replay:
|
|
444
|
+
|
|
445
|
+
1. Add logs before calling `start()`
|
|
446
|
+
2. Verify log file paths are correct
|
|
447
|
+
3. Ensure log files exist and are accessible
|
|
448
|
+
4. Check file permissions
|
|
449
|
+
|
|
450
|
+
## Best Practices
|
|
451
|
+
|
|
452
|
+
<AccordionGroup>
|
|
453
|
+
<Accordion title="Always authenticate before starting">
|
|
454
|
+
```javascript
|
|
455
|
+
await dashcam.auth();
|
|
456
|
+
await dashcam.start();
|
|
457
|
+
```
|
|
458
|
+
</Accordion>
|
|
459
|
+
|
|
460
|
+
<Accordion title="Add logs before starting recording">
|
|
461
|
+
```javascript
|
|
462
|
+
await dashcam.addFileLog('/tmp/app.log', 'App Log');
|
|
463
|
+
await dashcam.start();
|
|
464
|
+
```
|
|
465
|
+
</Accordion>
|
|
466
|
+
|
|
467
|
+
<Accordion title="Always stop recording">
|
|
468
|
+
Use try/finally to ensure recording stops:
|
|
469
|
+
|
|
470
|
+
```javascript
|
|
471
|
+
try {
|
|
472
|
+
await dashcam.start();
|
|
473
|
+
// Test code
|
|
474
|
+
} finally {
|
|
475
|
+
await dashcam.stop();
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
</Accordion>
|
|
479
|
+
|
|
480
|
+
<Accordion title="Check for replay URL">
|
|
481
|
+
```javascript
|
|
482
|
+
const url = await dashcam.stop();
|
|
483
|
+
if (url) {
|
|
484
|
+
console.log('Replay:', url);
|
|
485
|
+
} else {
|
|
486
|
+
console.warn('No replay URL available');
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
</Accordion>
|
|
490
|
+
</AccordionGroup>
|
|
491
|
+
|
|
492
|
+
## See Also
|
|
493
|
+
|
|
494
|
+
- [Chrome Preset](/v7/presets/chrome) - Automatic Dashcam setup for web apps
|
|
495
|
+
- [VS Code Extensions](/v7/presets/vscode) - Dashcam with VS Code testing
|
|
496
|
+
- [Desktop Apps](/v7/presets/electron) - Dashcam with Electron apps
|
|
497
|
+
- [Lifecycle Helpers](/v7/guides/lifecycle) - Prerun/postrun with Dashcam
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "doubleClick"
|
|
3
|
+
description: "Perform a double-click action on an element or at specific coordinates"
|
|
4
|
+
icon: "hand-pointer"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The `doubleClick()` method performs a double-click action on an element. You can either call it on an [`Element`](/v7/core-concepts/elements) instance or use it directly with a selector.
|
|
10
|
+
|
|
11
|
+
## Syntax
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
// Double-click on an element
|
|
15
|
+
await element.doubleClick();
|
|
16
|
+
|
|
17
|
+
// Double-click using a selector
|
|
18
|
+
await ai.doubleClick('selector');
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Parameters
|
|
22
|
+
|
|
23
|
+
When called on an `Element`, no parameters are required.
|
|
24
|
+
|
|
25
|
+
When called directly on the AI client:
|
|
26
|
+
|
|
27
|
+
| Parameter | Type | Description |
|
|
28
|
+
|-----------|------|-------------|
|
|
29
|
+
| `selector` | `string` | The selector describing the element to double-click |
|
|
30
|
+
|
|
31
|
+
## Returns
|
|
32
|
+
|
|
33
|
+
Returns a `Promise<void>` that resolves when the double-click action completes.
|
|
34
|
+
|
|
35
|
+
## Examples
|
|
36
|
+
|
|
37
|
+
### Double-Click on Found Element
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
const fileItem = await ai.find('README.md file');
|
|
41
|
+
await fileItem.doubleClick();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Direct Double-Click with Selector
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
await ai.doubleClick('README.md in the file list');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Opening Files in VS Code
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { test } from 'vitest';
|
|
54
|
+
import { vscode } from '@testdriver/sdk';
|
|
55
|
+
|
|
56
|
+
test('opens a file by double-clicking', async () => {
|
|
57
|
+
const { ai } = await vscode();
|
|
58
|
+
|
|
59
|
+
// Double-click to open a file in the explorer
|
|
60
|
+
await ai.doubleClick('package.json in the file explorer');
|
|
61
|
+
|
|
62
|
+
// Verify the file opened
|
|
63
|
+
const editor = await ai.find('text editor showing package.json');
|
|
64
|
+
expect(editor).toBeTruthy();
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Opening Folders in File Manager
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
import { test } from 'vitest';
|
|
72
|
+
import { chrome } from '@testdriver/sdk';
|
|
73
|
+
|
|
74
|
+
test('navigates folders in Google Drive', async () => {
|
|
75
|
+
const { ai } = await chrome('https://drive.google.com');
|
|
76
|
+
|
|
77
|
+
// Double-click to open a folder
|
|
78
|
+
await ai.doubleClick('Documents folder');
|
|
79
|
+
|
|
80
|
+
// Wait for folder to open
|
|
81
|
+
await ai.find('breadcrumb showing Documents');
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Selecting Text with Double-Click
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
// Double-click to select a word
|
|
89
|
+
await ai.doubleClick('word "TestDriver" in the paragraph');
|
|
90
|
+
|
|
91
|
+
// Verify selection
|
|
92
|
+
const selectedText = await ai.exec('window.getSelection().toString()');
|
|
93
|
+
expect(selectedText).toBe('TestDriver');
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Related Methods
|
|
97
|
+
|
|
98
|
+
- [`click()`](/v7/api/click) - Single click on an element
|
|
99
|
+
- [`rightClick()`](/v7/api/rightClick) - Right-click to open context menu
|
|
100
|
+
- [`mouseDown()`](/v7/api/mouseDown) - Press mouse button without releasing
|
|
101
|
+
- [`mouseUp()`](/v7/api/mouseUp) - Release mouse button
|
|
102
|
+
- [`hover()`](/v7/api/hover) - Move mouse over element without clicking
|