testdriverai 7.2.10 → 7.2.12
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/docs/docs.json +85 -92
- package/docs/v7/aws-setup.mdx +1 -1
- package/docs/v7/dashcam.mdx +0 -78
- package/docs/v7/device-config.mdx +320 -0
- package/docs/v7/elements.mdx +1 -54
- package/docs/v7/enterprise.mdx +0 -19
- package/docs/v7/generating-tests.mdx +6 -2
- package/package.json +1 -1
- package/docs/v7/sandbox.mdx +0 -404
package/docs/docs.json
CHANGED
|
@@ -13,6 +13,91 @@
|
|
|
13
13
|
"favicon": "/images/template/icon.png",
|
|
14
14
|
"navigation": {
|
|
15
15
|
"versions": [
|
|
16
|
+
{
|
|
17
|
+
"version": "v7",
|
|
18
|
+
"groups": [
|
|
19
|
+
{
|
|
20
|
+
"group": "Overview",
|
|
21
|
+
"pages": [
|
|
22
|
+
"/v7/what-is-testdriver",
|
|
23
|
+
"/v7/quickstart",
|
|
24
|
+
"/v7/examples",
|
|
25
|
+
{
|
|
26
|
+
"group": "Plans & Pricing",
|
|
27
|
+
"icon": "server",
|
|
28
|
+
"pages": [
|
|
29
|
+
"/v7/cloud",
|
|
30
|
+
"/v7/self-hosted",
|
|
31
|
+
"/v7/enterprise"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"group": "Creating Tests",
|
|
38
|
+
"pages": [
|
|
39
|
+
"/v7/generating-tests",
|
|
40
|
+
"/v7/device-config",
|
|
41
|
+
"/v7/locating-elements",
|
|
42
|
+
"/v7/waiting-for-elements",
|
|
43
|
+
"/v7/performing-actions",
|
|
44
|
+
"/v7/making-assertions"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"group": "Running Tests",
|
|
49
|
+
"pages": [
|
|
50
|
+
"/v7/running-tests",
|
|
51
|
+
"/v7/caching",
|
|
52
|
+
"/v7/ci-cd"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"group": "Scaling",
|
|
57
|
+
"pages": [
|
|
58
|
+
"/v7/variables",
|
|
59
|
+
"/v7/secrets",
|
|
60
|
+
"/v7/reusable-code",
|
|
61
|
+
{
|
|
62
|
+
"group": "Self-Hosting Setup",
|
|
63
|
+
"icon": "server",
|
|
64
|
+
"pages": [
|
|
65
|
+
"/v7/aws-setup"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"group": "Actions",
|
|
72
|
+
"pages": [
|
|
73
|
+
"/v7/ai",
|
|
74
|
+
"/v7/assert",
|
|
75
|
+
"/v7/click",
|
|
76
|
+
"/v7/double-click",
|
|
77
|
+
"/v7/exec",
|
|
78
|
+
"/v7/find",
|
|
79
|
+
"/v7/focus-application",
|
|
80
|
+
"/v7/hover",
|
|
81
|
+
"/v7/mouse-down",
|
|
82
|
+
"/v7/mouse-up",
|
|
83
|
+
"/v7/press-keys",
|
|
84
|
+
"/v7/right-click",
|
|
85
|
+
"/v7/type",
|
|
86
|
+
"/v7/scroll"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"group": "SDK",
|
|
91
|
+
"pages":
|
|
92
|
+
[
|
|
93
|
+
"/v7/elements",
|
|
94
|
+
"/v7/client",
|
|
95
|
+
"/v7/dashcam"
|
|
96
|
+
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
16
101
|
{
|
|
17
102
|
"version": "v6",
|
|
18
103
|
"groups": [
|
|
@@ -186,98 +271,6 @@
|
|
|
186
271
|
]
|
|
187
272
|
}
|
|
188
273
|
]
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
"version": "v7",
|
|
192
|
-
"groups": [
|
|
193
|
-
{
|
|
194
|
-
"group": "Overview",
|
|
195
|
-
"pages": [
|
|
196
|
-
"/v7/what-is-testdriver",
|
|
197
|
-
"/v7/quickstart",
|
|
198
|
-
"/v7/examples",
|
|
199
|
-
{
|
|
200
|
-
"group": "Plans & Pricing",
|
|
201
|
-
"icon": "server",
|
|
202
|
-
"pages": [
|
|
203
|
-
"/v7/cloud",
|
|
204
|
-
{
|
|
205
|
-
"group": "Self-Hosted",
|
|
206
|
-
"icon": "server",
|
|
207
|
-
"pages": [
|
|
208
|
-
"/v7/self-hosted",
|
|
209
|
-
"/v7/aws-setup"
|
|
210
|
-
]
|
|
211
|
-
},
|
|
212
|
-
"/v7/enterprise"
|
|
213
|
-
]
|
|
214
|
-
}
|
|
215
|
-
]
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"group": "Creating Tests",
|
|
219
|
-
"pages": [
|
|
220
|
-
"/v7/generating-tests",
|
|
221
|
-
"/v7/locating-elements",
|
|
222
|
-
"/v7/waiting-for-elements",
|
|
223
|
-
"/v7/performing-actions",
|
|
224
|
-
"/v7/making-assertions"
|
|
225
|
-
]
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"group": "Running Tests",
|
|
229
|
-
"pages": [
|
|
230
|
-
"/v7/running-tests",
|
|
231
|
-
"/v7/caching",
|
|
232
|
-
"/v7/ci-cd"
|
|
233
|
-
]
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
"group": "Scaling",
|
|
237
|
-
"pages": [
|
|
238
|
-
"/v7/variables",
|
|
239
|
-
"/v7/secrets",
|
|
240
|
-
"/v7/reusable-code",
|
|
241
|
-
"/v7/customizing-devices"
|
|
242
|
-
]
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"group": "Reference",
|
|
246
|
-
"icon": "book",
|
|
247
|
-
"pages": [
|
|
248
|
-
{
|
|
249
|
-
"group": "Actions",
|
|
250
|
-
"icon": "bolt",
|
|
251
|
-
"pages": [
|
|
252
|
-
"/v7/ai",
|
|
253
|
-
"/v7/assert",
|
|
254
|
-
"/v7/click",
|
|
255
|
-
"/v7/double-click",
|
|
256
|
-
"/v7/exec",
|
|
257
|
-
"/v7/find",
|
|
258
|
-
"/v7/focus-application",
|
|
259
|
-
"/v7/hover",
|
|
260
|
-
"/v7/mouse-down",
|
|
261
|
-
"/v7/mouse-up",
|
|
262
|
-
"/v7/press-keys",
|
|
263
|
-
"/v7/right-click",
|
|
264
|
-
"/v7/type",
|
|
265
|
-
"/v7/scroll"
|
|
266
|
-
]
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
"group": "Client SDK",
|
|
270
|
-
"icon": "code",
|
|
271
|
-
"pages": [
|
|
272
|
-
"/v7/client",
|
|
273
|
-
"/v7/elements",
|
|
274
|
-
"/v7/sandbox",
|
|
275
|
-
"/v7/dashcam"
|
|
276
|
-
]
|
|
277
|
-
}
|
|
278
|
-
]
|
|
279
|
-
}
|
|
280
|
-
]
|
|
281
274
|
}
|
|
282
275
|
]
|
|
283
276
|
},
|
package/docs/v7/aws-setup.mdx
CHANGED
package/docs/v7/dashcam.mdx
CHANGED
|
@@ -417,81 +417,3 @@ On Linux/Mac, Dashcam uses shell commands:
|
|
|
417
417
|
// Unix-specific paths
|
|
418
418
|
await dashcam.addFileLog('/tmp/testdriver.log', 'TestDriver Log');
|
|
419
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,320 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Configuring the Device"
|
|
3
|
+
description: "Launch browsers, desktop apps, and extensions in your TestDriver sandbox"
|
|
4
|
+
icon: "wrench"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Provision methods are the starting point for most tests. They launch applications in your sandbox and prepare the environment for testing.
|
|
8
|
+
|
|
9
|
+
## Chrome Browser
|
|
10
|
+
|
|
11
|
+
The most common starting point for web testing. Launches Chrome browser and navigates to a URL.
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
await testdriver.provision.chrome({
|
|
15
|
+
url: 'https://example.com',
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Options
|
|
20
|
+
|
|
21
|
+
| Option | Type | Default | Description |
|
|
22
|
+
|--------|------|---------|-------------|
|
|
23
|
+
| `url` | string | `'http://testdriver-sandbox.vercel.app/'` | URL to navigate to |
|
|
24
|
+
| `maximized` | boolean | `true` | Start browser maximized |
|
|
25
|
+
| `guest` | boolean | `false` | Use guest mode (no profile) |
|
|
26
|
+
|
|
27
|
+
### Example: Basic Web Test
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import { describe, expect, it } from "vitest";
|
|
31
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
32
|
+
|
|
33
|
+
describe("Login Flow", () => {
|
|
34
|
+
it("should log in successfully", async (context) => {
|
|
35
|
+
const testdriver = TestDriver(context, { newSandbox: true });
|
|
36
|
+
|
|
37
|
+
await testdriver.provision.chrome({
|
|
38
|
+
url: 'https://myapp.com/login',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await testdriver.find("Email input").click();
|
|
42
|
+
await testdriver.type("user@example.com");
|
|
43
|
+
|
|
44
|
+
await testdriver.find("Password input").click();
|
|
45
|
+
await testdriver.type("password123");
|
|
46
|
+
|
|
47
|
+
await testdriver.find("Sign In button").click();
|
|
48
|
+
|
|
49
|
+
const result = await testdriver.assert("the dashboard is visible");
|
|
50
|
+
expect(result).toBeTruthy();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
<Info>
|
|
56
|
+
`provision.chrome()` automatically starts Dashcam recording and waits for Chrome to be ready before returning.
|
|
57
|
+
</Info>
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Chrome Extensions
|
|
62
|
+
|
|
63
|
+
Launch Chrome with a custom extension loaded. Supports both local extensions and Chrome Web Store extensions.
|
|
64
|
+
|
|
65
|
+
### Load from Local Path
|
|
66
|
+
|
|
67
|
+
Clone or create an extension locally, then load it:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
// First, get the extension onto the sandbox
|
|
71
|
+
await testdriver.exec(
|
|
72
|
+
'sh',
|
|
73
|
+
'git clone https://github.com/user/my-extension.git /tmp/my-extension',
|
|
74
|
+
60000
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Launch Chrome with the extension
|
|
78
|
+
await testdriver.provision.chromeExtension({
|
|
79
|
+
extensionPath: '/tmp/my-extension',
|
|
80
|
+
url: 'https://example.com'
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Load from Chrome Web Store
|
|
85
|
+
|
|
86
|
+
Load any published extension by its Chrome Web Store ID:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
await testdriver.provision.chromeExtension({
|
|
90
|
+
extensionId: 'cjpalhdlnbpafiamejdnhcphjbkeiagm', // uBlock Origin
|
|
91
|
+
url: 'https://example.com'
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
<Tip>
|
|
96
|
+
Find the extension ID in the Chrome Web Store URL. For example, `https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm` → ID is `cjpalhdlnbpafiamejdnhcphjbkeiagm`
|
|
97
|
+
</Tip>
|
|
98
|
+
|
|
99
|
+
### Options
|
|
100
|
+
|
|
101
|
+
| Option | Type | Default | Description |
|
|
102
|
+
|--------|------|---------|-------------|
|
|
103
|
+
| `extensionPath` | string | - | Local path to unpacked extension directory |
|
|
104
|
+
| `extensionId` | string | - | Chrome Web Store extension ID |
|
|
105
|
+
| `url` | string | - | URL to navigate to after launch |
|
|
106
|
+
| `maximized` | boolean | `true` | Start browser maximized |
|
|
107
|
+
|
|
108
|
+
<Warning>
|
|
109
|
+
You must provide either `extensionPath` or `extensionId`, but not both.
|
|
110
|
+
</Warning>
|
|
111
|
+
|
|
112
|
+
### Example: Testing a Chrome Extension
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
import { describe, expect, it } from "vitest";
|
|
116
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
117
|
+
|
|
118
|
+
describe("Chrome Extension Test", () => {
|
|
119
|
+
it("should load and interact with extension", async (context) => {
|
|
120
|
+
const testdriver = TestDriver(context, { newSandbox: true });
|
|
121
|
+
|
|
122
|
+
// Clone extension from GitHub
|
|
123
|
+
await testdriver.ready();
|
|
124
|
+
await testdriver.exec(
|
|
125
|
+
'sh',
|
|
126
|
+
'git clone https://github.com/user/my-extension.git /tmp/my-extension',
|
|
127
|
+
60000,
|
|
128
|
+
true
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Launch Chrome with extension loaded
|
|
132
|
+
await testdriver.provision.chromeExtension({
|
|
133
|
+
extensionPath: '/tmp/my-extension',
|
|
134
|
+
url: 'https://testdriver.ai'
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Click extensions puzzle icon
|
|
138
|
+
const extensionsButton = await testdriver.find("puzzle-shaped icon in Chrome toolbar");
|
|
139
|
+
await extensionsButton.click();
|
|
140
|
+
|
|
141
|
+
// Interact with your extension
|
|
142
|
+
const myExtension = await testdriver.find("My Extension in the dropdown");
|
|
143
|
+
await myExtension.click();
|
|
144
|
+
|
|
145
|
+
const result = await testdriver.assert("extension popup is visible");
|
|
146
|
+
expect(result).toBeTruthy();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Desktop Apps
|
|
154
|
+
|
|
155
|
+
Download and install desktop applications. Supports `.deb`, `.rpm`, `.msi`, `.exe`, `.AppImage`, `.dmg`, `.pkg`, and shell scripts.
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
const filePath = await testdriver.provision.installer({
|
|
159
|
+
url: 'https://example.com/app.deb',
|
|
160
|
+
appName: 'MyApp', // Focus this app after install
|
|
161
|
+
launch: true, // Auto-launch after install
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Options
|
|
166
|
+
|
|
167
|
+
| Option | Type | Default | Description |
|
|
168
|
+
|--------|------|---------|-------------|
|
|
169
|
+
| `url` | string | **required** | URL to download the installer from |
|
|
170
|
+
| `filename` | string | auto-detected | Filename to save as |
|
|
171
|
+
| `appName` | string | - | Application name to focus after install |
|
|
172
|
+
| `launch` | boolean | `true` | Launch the app after installation |
|
|
173
|
+
|
|
174
|
+
### Supported File Types
|
|
175
|
+
|
|
176
|
+
| Extension | OS | Install Method |
|
|
177
|
+
|-----------|-----|----------------|
|
|
178
|
+
| `.deb` | Linux | `dpkg -i` + `apt-get install -f` |
|
|
179
|
+
| `.rpm` | Linux | `rpm -i` |
|
|
180
|
+
| `.AppImage` | Linux | `chmod +x` |
|
|
181
|
+
| `.sh` | Linux | `chmod +x` + execute |
|
|
182
|
+
| `.msi` | Windows | `msiexec /i /quiet` |
|
|
183
|
+
| `.exe` | Windows | Silent install (`/S`) |
|
|
184
|
+
| `.dmg` | macOS | Mount + copy to Applications |
|
|
185
|
+
| `.pkg` | macOS | `installer -pkg` |
|
|
186
|
+
|
|
187
|
+
### Example: Install and Test a Desktop App
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
import { describe, expect, it } from "vitest";
|
|
191
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
192
|
+
|
|
193
|
+
describe("Desktop App Test", () => {
|
|
194
|
+
it("should install and launch app", async (context) => {
|
|
195
|
+
const testdriver = TestDriver(context, { newSandbox: true });
|
|
196
|
+
|
|
197
|
+
// Download and install
|
|
198
|
+
const installerPath = await testdriver.provision.installer({
|
|
199
|
+
url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb',
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Verify installation
|
|
203
|
+
const output = await testdriver.exec('sh', 'bat --version', 5000);
|
|
204
|
+
expect(output).toContain('bat');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Example: Windows Installer
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
import { describe, expect, it } from "vitest";
|
|
213
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
214
|
+
|
|
215
|
+
describe("Windows App Test", () => {
|
|
216
|
+
it("should install on Windows", async (context) => {
|
|
217
|
+
const testdriver = TestDriver(context, {
|
|
218
|
+
newSandbox: true,
|
|
219
|
+
os: 'windows'
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Download MSI installer
|
|
223
|
+
const installerPath = await testdriver.provision.installer({
|
|
224
|
+
url: 'https://example.com/app.msi',
|
|
225
|
+
launch: false, // Don't auto-launch
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Custom installation if needed
|
|
229
|
+
await testdriver.exec(
|
|
230
|
+
'pwsh',
|
|
231
|
+
`Start-Process msiexec.exe -ArgumentList "/i", "${installerPath}", "/qn" -Wait`,
|
|
232
|
+
120000
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
// Verify installation
|
|
236
|
+
const result = await testdriver.assert("application is installed");
|
|
237
|
+
expect(result).toBeTruthy();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Manual Installation
|
|
243
|
+
|
|
244
|
+
Set `launch: false` to download without auto-installing:
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
const filePath = await testdriver.provision.installer({
|
|
248
|
+
url: 'https://example.com/custom-script.sh',
|
|
249
|
+
launch: false,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Run custom install commands
|
|
253
|
+
await testdriver.exec('sh', `chmod +x "${filePath}"`, 5000);
|
|
254
|
+
await testdriver.exec('sh', `"${filePath}" --custom-flag`, 60000);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## VS Code
|
|
260
|
+
|
|
261
|
+
Launch Visual Studio Code with optional workspace and extensions.
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
await testdriver.provision.vscode({
|
|
265
|
+
workspace: '/home/testdriver/my-project',
|
|
266
|
+
extensions: ['ms-python.python', 'esbenp.prettier-vscode'],
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Options
|
|
271
|
+
|
|
272
|
+
| Option | Type | Default | Description |
|
|
273
|
+
|--------|------|---------|-------------|
|
|
274
|
+
| `workspace` | string | - | Workspace folder to open |
|
|
275
|
+
| `extensions` | string[] | `[]` | Extensions to install (by ID) |
|
|
276
|
+
|
|
277
|
+
### Example: VS Code Extension Test
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
import { describe, expect, it } from "vitest";
|
|
281
|
+
import { TestDriver } from "testdriverai/lib/vitest/hooks.mjs";
|
|
282
|
+
|
|
283
|
+
describe("VS Code Test", () => {
|
|
284
|
+
it("should open workspace with extensions", async (context) => {
|
|
285
|
+
const testdriver = TestDriver(context, { newSandbox: true });
|
|
286
|
+
|
|
287
|
+
// Create a test project
|
|
288
|
+
await testdriver.ready();
|
|
289
|
+
await testdriver.exec('sh', 'mkdir -p /tmp/test-project && echo "print(1)" > /tmp/test-project/test.py', 10000);
|
|
290
|
+
|
|
291
|
+
// Launch VS Code
|
|
292
|
+
await testdriver.provision.vscode({
|
|
293
|
+
workspace: '/tmp/test-project',
|
|
294
|
+
extensions: ['ms-python.python'],
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Verify VS Code is ready
|
|
298
|
+
const result = await testdriver.assert("VS Code is open with the project");
|
|
299
|
+
expect(result).toBeTruthy();
|
|
300
|
+
|
|
301
|
+
// Open the Python file
|
|
302
|
+
await testdriver.find("test.py in the explorer").click();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Choosing the Right Provision Method
|
|
310
|
+
|
|
311
|
+
| Use Case | Method |
|
|
312
|
+
|----------|--------|
|
|
313
|
+
| Testing a website | `provision.chrome` |
|
|
314
|
+
| Testing a Chrome extension | `provision.chromeExtension` |
|
|
315
|
+
| Testing a desktop app (needs installation) | `provision.installer` |
|
|
316
|
+
| Testing VS Code or VS Code extensions | `provision.vscode` |
|
|
317
|
+
|
|
318
|
+
<Tip>
|
|
319
|
+
All provision methods automatically start Dashcam recording and wait for the application to be ready before returning. You don't need to call `dashcam.start()` manually.
|
|
320
|
+
</Tip>
|
package/docs/v7/elements.mdx
CHANGED
|
@@ -496,47 +496,6 @@ const elementData = JSON.stringify(element);
|
|
|
496
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
497
|
</Tip>
|
|
498
498
|
|
|
499
|
-
## Polling for Elements
|
|
500
|
-
|
|
501
|
-
Use polling to wait for elements that may not be immediately visible:
|
|
502
|
-
|
|
503
|
-
```javascript
|
|
504
|
-
// Poll until element appears
|
|
505
|
-
let loginButton;
|
|
506
|
-
const maxAttempts = 30;
|
|
507
|
-
|
|
508
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
509
|
-
loginButton = await testdriver.find('login button');
|
|
510
|
-
if (loginButton.found()) break;
|
|
511
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
if (loginButton.found()) {
|
|
515
|
-
await loginButton.click();
|
|
516
|
-
} else {
|
|
517
|
-
throw new Error('Login button never appeared');
|
|
518
|
-
}
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
**Helper function for polling:**
|
|
522
|
-
```javascript
|
|
523
|
-
async function waitForElement(testdriver, description, timeout = 30000) {
|
|
524
|
-
const startTime = Date.now();
|
|
525
|
-
|
|
526
|
-
while (Date.now() - startTime < timeout) {
|
|
527
|
-
const element = await testdriver.find(description);
|
|
528
|
-
if (element.found()) return element;
|
|
529
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
throw new Error(`Element "${description}" not found after ${timeout}ms`);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Usage
|
|
536
|
-
const button = await waitForElement(testdriver, 'submit button', 10000);
|
|
537
|
-
await button.click();
|
|
538
|
-
```
|
|
539
|
-
|
|
540
499
|
## Examples
|
|
541
500
|
|
|
542
501
|
### Basic Element Interaction
|
|
@@ -627,19 +586,7 @@ if (notification.found()) {
|
|
|
627
586
|
await element.click();
|
|
628
587
|
```
|
|
629
588
|
</Accordion>
|
|
630
|
-
|
|
631
|
-
<Accordion title="Use polling for dynamic content">
|
|
632
|
-
Don't assume elements are immediately visible:
|
|
633
|
-
|
|
634
|
-
```javascript
|
|
635
|
-
let element;
|
|
636
|
-
for (let i = 0; i < 30; i++) {
|
|
637
|
-
element = await testdriver.find('loading complete message');
|
|
638
|
-
if (element.found()) break;
|
|
639
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
640
|
-
}
|
|
641
|
-
```
|
|
642
|
-
</Accordion>
|
|
589
|
+
|
|
643
590
|
|
|
644
591
|
<Accordion title="Reuse element references when possible">
|
|
645
592
|
If you need to interact with the same element multiple times, reuse the reference:
|
package/docs/v7/enterprise.mdx
CHANGED
|
@@ -114,22 +114,3 @@ Enterprise deployments support:
|
|
|
114
114
|
>
|
|
115
115
|
Discuss your requirements with our team and get a custom proposal for your Enterprise deployment.
|
|
116
116
|
</Card>
|
|
117
|
-
|
|
118
|
-
## Related
|
|
119
|
-
|
|
120
|
-
<CardGroup cols={2}>
|
|
121
|
-
<Card
|
|
122
|
-
title="Cloud"
|
|
123
|
-
icon="cloud"
|
|
124
|
-
href="/v7/cloud"
|
|
125
|
-
>
|
|
126
|
-
Zero-setup testing with device-seconds billing
|
|
127
|
-
</Card>
|
|
128
|
-
<Card
|
|
129
|
-
title="Self-Hosted"
|
|
130
|
-
icon="server"
|
|
131
|
-
href="/v7/self-hosted"
|
|
132
|
-
>
|
|
133
|
-
Flat-rate licensing with your AWS infrastructure
|
|
134
|
-
</Card>
|
|
135
|
-
</CardGroup>
|
|
@@ -6,9 +6,13 @@ icon: "wand-magic-sparkles"
|
|
|
6
6
|
|
|
7
7
|
## Instructions for Coding Agents
|
|
8
8
|
|
|
9
|
-
We recommend starting with [our quickstart](./quickstart) then supplying your coding agent with our
|
|
9
|
+
We recommend starting with [our quickstart](./quickstart) then supplying your coding agent with our agents.md file.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
<Card title="Agents.md" icon="link" arrow="true" horizontal href="https://github.com/testdriverai/testdriverai/blob/main/agents.md?plain=1">
|
|
12
|
+
Copy the current version of agents.md to provide your coding agent with up-to-date instructions on how to generate TestDriver tests.
|
|
13
|
+
</Card>
|
|
14
|
+
|
|
15
|
+
Then, you can prompt your coding agent to generate tests. Here is an example prompt:
|
|
12
16
|
|
|
13
17
|
```md
|
|
14
18
|
Make me a TestDriver test that does the following steps:
|
package/package.json
CHANGED
package/docs/v7/sandbox.mdx
DELETED
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Sandbox Management"
|
|
3
|
-
sidebarTitle: "Sandbox"
|
|
4
|
-
description: "Execute scripts and manage the sandbox environment"
|
|
5
|
-
icon: "server"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
The sandbox is a virtual machine where your tests run. You can execute shell commands, JavaScript, and manage applications within the sandbox environment.
|
|
11
|
-
|
|
12
|
-
## Code Execution
|
|
13
|
-
|
|
14
|
-
### exec()
|
|
15
|
-
|
|
16
|
-
Execute code or shell commands in the sandbox.
|
|
17
|
-
|
|
18
|
-
```javascript
|
|
19
|
-
await testdriver.exec(language, code, timeout, silent)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Parameters:**
|
|
23
|
-
- `language` (string) - Language to execute: `'js'` (JavaScript) or `'pwsh'` (PowerShell)
|
|
24
|
-
- `code` (string) - Code or command to execute
|
|
25
|
-
- `timeout` (number) - Timeout in milliseconds
|
|
26
|
-
- `silent` (boolean, optional) - Suppress output if `true`
|
|
27
|
-
|
|
28
|
-
**Returns:** `Promise<string>` - Command output
|
|
29
|
-
|
|
30
|
-
### JavaScript Execution
|
|
31
|
-
|
|
32
|
-
Execute JavaScript code in the browser context (Windows sandbox only).
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
// Execute JavaScript in the browser
|
|
36
|
-
const result = await testdriver.exec('js', 'document.title', 5000);
|
|
37
|
-
console.log('Page title:', result);
|
|
38
|
-
|
|
39
|
-
// Manipulate the DOM
|
|
40
|
-
await testdriver.exec('js', `
|
|
41
|
-
document.querySelector('#username').value = 'testuser';
|
|
42
|
-
`, 5000);
|
|
43
|
-
|
|
44
|
-
// Return data from the page
|
|
45
|
-
const elementText = await testdriver.exec('js', `
|
|
46
|
-
document.querySelector('.message').textContent
|
|
47
|
-
`, 5000);
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### PowerShell Execution
|
|
51
|
-
|
|
52
|
-
Execute PowerShell commands in the Windows sandbox.
|
|
53
|
-
|
|
54
|
-
```javascript
|
|
55
|
-
// Run a simple command
|
|
56
|
-
const output = await testdriver.exec('pwsh', 'Get-Process chrome', 5000);
|
|
57
|
-
console.log('Chrome processes:', output);
|
|
58
|
-
|
|
59
|
-
// Install software
|
|
60
|
-
await testdriver.exec('pwsh', 'npm install -g dashcam@beta', 10000);
|
|
61
|
-
|
|
62
|
-
// Start an application
|
|
63
|
-
await testdriver.exec('pwsh', `
|
|
64
|
-
Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "https://example.com"
|
|
65
|
-
`, 10000);
|
|
66
|
-
|
|
67
|
-
// File operations
|
|
68
|
-
await testdriver.exec('pwsh', 'New-Item -Path "C:\\test.txt" -ItemType File', 5000);
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Silent Execution
|
|
72
|
-
|
|
73
|
-
Use the `silent` parameter to suppress output for background operations:
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
// Silent installation
|
|
77
|
-
await testdriver.exec('pwsh', 'npm install -g some-package', 10000, true);
|
|
78
|
-
|
|
79
|
-
// Start background process
|
|
80
|
-
await testdriver.exec('pwsh', 'Start-Process notepad', 5000, true);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Application Management
|
|
84
|
-
|
|
85
|
-
### focusApplication()
|
|
86
|
-
|
|
87
|
-
Bring an application window to the foreground.
|
|
88
|
-
|
|
89
|
-
```javascript
|
|
90
|
-
await testdriver.focusApplication(name)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**Parameters:**
|
|
94
|
-
- `name` (string) - Application name (e.g., `'Google Chrome'`, `'Microsoft Edge'`, `'Notepad'`)
|
|
95
|
-
|
|
96
|
-
**Returns:** `Promise<string>` - Result message
|
|
97
|
-
|
|
98
|
-
**Example:**
|
|
99
|
-
```javascript
|
|
100
|
-
// Focus Chrome browser
|
|
101
|
-
await testdriver.focusApplication('Google Chrome');
|
|
102
|
-
|
|
103
|
-
// Focus Edge
|
|
104
|
-
await testdriver.focusApplication('Microsoft Edge');
|
|
105
|
-
|
|
106
|
-
// Focus Notepad
|
|
107
|
-
await testdriver.focusApplication('Notepad');
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
<Tip>
|
|
111
|
-
Call `focusApplication()` before interacting with UI elements to ensure the correct window is active.
|
|
112
|
-
</Tip>
|
|
113
|
-
|
|
114
|
-
## Common Sandbox Operations
|
|
115
|
-
|
|
116
|
-
### Installing Software
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
// Install npm package globally
|
|
120
|
-
await testdriver.exec('pwsh', 'npm install -g package-name', 30000);
|
|
121
|
-
|
|
122
|
-
// Install via Chocolatey (if available)
|
|
123
|
-
await testdriver.exec('pwsh', 'choco install firefox -y', 60000);
|
|
124
|
-
|
|
125
|
-
// Download and install
|
|
126
|
-
await testdriver.exec('pwsh', `
|
|
127
|
-
Invoke-WebRequest -Uri "https://example.com/installer.exe" -OutFile "C:\\installer.exe"
|
|
128
|
-
Start-Process -FilePath "C:\\installer.exe" -ArgumentList "/S" -Wait
|
|
129
|
-
`, 120000);
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### File Operations
|
|
133
|
-
|
|
134
|
-
```javascript
|
|
135
|
-
// Create a file
|
|
136
|
-
await testdriver.exec('pwsh', `
|
|
137
|
-
Set-Content -Path "C:\\test.txt" -Value "Hello World"
|
|
138
|
-
`, 5000);
|
|
139
|
-
|
|
140
|
-
// Read a file
|
|
141
|
-
const content = await testdriver.exec('pwsh', 'Get-Content -Path "C:\\test.txt"', 5000);
|
|
142
|
-
|
|
143
|
-
// Copy files
|
|
144
|
-
await testdriver.exec('pwsh', 'Copy-Item -Path "C:\\source.txt" -Destination "C:\\dest.txt"', 5000);
|
|
145
|
-
|
|
146
|
-
// Delete files
|
|
147
|
-
await testdriver.exec('pwsh', 'Remove-Item -Path "C:\\test.txt"', 5000);
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Environment Variables
|
|
151
|
-
|
|
152
|
-
```javascript
|
|
153
|
-
// Set environment variable
|
|
154
|
-
await testdriver.exec('pwsh', '$env:MY_VAR = "value"', 5000);
|
|
155
|
-
|
|
156
|
-
// Get environment variable
|
|
157
|
-
const value = await testdriver.exec('pwsh', '$env:MY_VAR', 5000);
|
|
158
|
-
|
|
159
|
-
// Set persistent environment variable
|
|
160
|
-
await testdriver.exec('pwsh', '[Environment]::SetEnvironmentVariable("MY_VAR", "value", "User")', 5000);
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Network Operations
|
|
164
|
-
|
|
165
|
-
```javascript
|
|
166
|
-
// Test connectivity
|
|
167
|
-
const pingResult = await testdriver.exec('pwsh', 'Test-NetConnection google.com', 10000);
|
|
168
|
-
|
|
169
|
-
// Download file
|
|
170
|
-
await testdriver.exec('pwsh', `
|
|
171
|
-
Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "C:\\Downloads\\file.zip"
|
|
172
|
-
`, 30000);
|
|
173
|
-
|
|
174
|
-
// Check if port is open
|
|
175
|
-
const portCheck = await testdriver.exec('pwsh', 'Test-NetConnection -ComputerName localhost -Port 3000', 5000);
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Process Management
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
// List running processes
|
|
182
|
-
const processes = await testdriver.exec('pwsh', 'Get-Process', 5000);
|
|
183
|
-
|
|
184
|
-
// Kill a process
|
|
185
|
-
await testdriver.exec('pwsh', 'Stop-Process -Name "chrome" -Force', 5000);
|
|
186
|
-
|
|
187
|
-
// Start a process and wait for it
|
|
188
|
-
await testdriver.exec('pwsh', 'Start-Process notepad -Wait', 30000);
|
|
189
|
-
|
|
190
|
-
// Start process with arguments
|
|
191
|
-
await testdriver.exec('pwsh', `
|
|
192
|
-
Start-Process "chrome.exe" -ArgumentList "--incognito", "https://example.com"
|
|
193
|
-
`, 5000);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Browser Automation with JavaScript
|
|
197
|
-
|
|
198
|
-
### DOM Manipulation
|
|
199
|
-
|
|
200
|
-
```javascript
|
|
201
|
-
// Click an element
|
|
202
|
-
await testdriver.exec('js', `
|
|
203
|
-
document.querySelector('#submit-button').click();
|
|
204
|
-
`, 5000);
|
|
205
|
-
|
|
206
|
-
// Fill a form
|
|
207
|
-
await testdriver.exec('js', `
|
|
208
|
-
document.querySelector('#username').value = 'user@example.com';
|
|
209
|
-
document.querySelector('#password').value = 'secret';
|
|
210
|
-
document.querySelector('#login-form').submit();
|
|
211
|
-
`, 5000);
|
|
212
|
-
|
|
213
|
-
// Scroll to element
|
|
214
|
-
await testdriver.exec('js', `
|
|
215
|
-
document.querySelector('#footer').scrollIntoView();
|
|
216
|
-
`, 5000);
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Reading Page Data
|
|
220
|
-
|
|
221
|
-
```javascript
|
|
222
|
-
// Get page title
|
|
223
|
-
const title = await testdriver.exec('js', 'document.title', 5000);
|
|
224
|
-
|
|
225
|
-
// Get all links
|
|
226
|
-
const links = await testdriver.exec('js', `
|
|
227
|
-
Array.from(document.querySelectorAll('a')).map(a => a.href).join('\\n')
|
|
228
|
-
`, 5000);
|
|
229
|
-
|
|
230
|
-
// Check if element exists
|
|
231
|
-
const exists = await testdriver.exec('js', `
|
|
232
|
-
document.querySelector('.error-message') !== null
|
|
233
|
-
`, 5000);
|
|
234
|
-
|
|
235
|
-
// Get element text
|
|
236
|
-
const text = await testdriver.exec('js', `
|
|
237
|
-
document.querySelector('.notification').textContent
|
|
238
|
-
`, 5000);
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Waiting for Conditions
|
|
242
|
-
|
|
243
|
-
```javascript
|
|
244
|
-
// Wait for element to appear (using polling)
|
|
245
|
-
await testdriver.exec('js', `
|
|
246
|
-
await new Promise((resolve) => {
|
|
247
|
-
const interval = setInterval(() => {
|
|
248
|
-
if (document.querySelector('.loaded')) {
|
|
249
|
-
clearInterval(interval);
|
|
250
|
-
resolve();
|
|
251
|
-
}
|
|
252
|
-
}, 100);
|
|
253
|
-
});
|
|
254
|
-
`, 30000);
|
|
255
|
-
|
|
256
|
-
// Wait for page load
|
|
257
|
-
await testdriver.exec('js', `
|
|
258
|
-
if (document.readyState !== 'complete') {
|
|
259
|
-
await new Promise(resolve => window.addEventListener('load', resolve));
|
|
260
|
-
}
|
|
261
|
-
`, 10000);
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Complete Example
|
|
265
|
-
|
|
266
|
-
```javascript
|
|
267
|
-
import { beforeAll, afterAll, describe, it } from 'vitest';
|
|
268
|
-
import TestDriver from 'testdriverai';
|
|
269
|
-
|
|
270
|
-
describe('Sandbox Operations', () => {
|
|
271
|
-
let testdriver;
|
|
272
|
-
|
|
273
|
-
beforeAll(async () => {
|
|
274
|
-
client = new TestDriver(process.env.TD_API_KEY, {
|
|
275
|
-
os: 'windows',
|
|
276
|
-
resolution: '1366x768'
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
await testdriver.auth();
|
|
280
|
-
await testdriver.connect({ newSandbox: true });
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
afterAll(async () => {
|
|
284
|
-
await testdriver.disconnect();
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it('should install and use a tool', async () => {
|
|
288
|
-
// Install a tool
|
|
289
|
-
await testdriver.exec('pwsh', 'npm install -g http-server', 30000, true);
|
|
290
|
-
|
|
291
|
-
// Create a simple HTML file
|
|
292
|
-
await testdriver.exec('pwsh', `
|
|
293
|
-
Set-Content -Path "C:\\index.html" -Value "<h1>Hello World</h1>"
|
|
294
|
-
`, 5000);
|
|
295
|
-
|
|
296
|
-
// Start HTTP server (background process)
|
|
297
|
-
await testdriver.exec('pwsh', `
|
|
298
|
-
Start-Process pwsh -ArgumentList "-Command", "http-server C:\\ -p 8080"
|
|
299
|
-
`, 5000, true);
|
|
300
|
-
|
|
301
|
-
// Wait for server to start
|
|
302
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
303
|
-
|
|
304
|
-
// Launch browser to view the page
|
|
305
|
-
await testdriver.exec('pwsh', `
|
|
306
|
-
Start-Process chrome -ArgumentList "http://localhost:8080"
|
|
307
|
-
`, 5000);
|
|
308
|
-
|
|
309
|
-
// Focus the browser
|
|
310
|
-
await testdriver.focusApplication('Google Chrome');
|
|
311
|
-
|
|
312
|
-
// Verify the page loaded
|
|
313
|
-
const pageText = await testdriver.exec('js', 'document.body.textContent', 5000);
|
|
314
|
-
expect(pageText).toContain('Hello World');
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
it('should manage files and processes', async () => {
|
|
318
|
-
// Create test file
|
|
319
|
-
await testdriver.exec('pwsh', `
|
|
320
|
-
"Test content" | Out-File -FilePath "C:\\test.txt"
|
|
321
|
-
`, 5000);
|
|
322
|
-
|
|
323
|
-
// Open file in notepad
|
|
324
|
-
await testdriver.exec('pwsh', 'Start-Process notepad C:\\test.txt', 5000);
|
|
325
|
-
|
|
326
|
-
// Focus notepad
|
|
327
|
-
await testdriver.focusApplication('Notepad');
|
|
328
|
-
|
|
329
|
-
// Wait a moment
|
|
330
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
331
|
-
|
|
332
|
-
// Close notepad
|
|
333
|
-
await testdriver.exec('pwsh', 'Stop-Process -Name notepad -Force', 5000);
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
## Best Practices
|
|
339
|
-
|
|
340
|
-
<AccordionGroup>
|
|
341
|
-
<Accordion title="Use appropriate timeouts">
|
|
342
|
-
Set realistic timeouts based on the operation:
|
|
343
|
-
|
|
344
|
-
```javascript
|
|
345
|
-
// Quick operations: 5000ms
|
|
346
|
-
await testdriver.exec('js', 'document.title', 5000);
|
|
347
|
-
|
|
348
|
-
// Installations: 30000-60000ms
|
|
349
|
-
await testdriver.exec('pwsh', 'npm install -g package', 30000);
|
|
350
|
-
|
|
351
|
-
// Downloads or complex operations: 60000-120000ms
|
|
352
|
-
await testdriver.exec('pwsh', 'Install-Module Something', 120000);
|
|
353
|
-
```
|
|
354
|
-
</Accordion>
|
|
355
|
-
|
|
356
|
-
<Accordion title="Handle errors gracefully">
|
|
357
|
-
Wrap exec calls in try-catch for better error handling:
|
|
358
|
-
|
|
359
|
-
```javascript
|
|
360
|
-
try {
|
|
361
|
-
await testdriver.exec('pwsh', 'Some-Command', 5000);
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error('Command failed:', error.message);
|
|
364
|
-
// Fall back or retry
|
|
365
|
-
}
|
|
366
|
-
```
|
|
367
|
-
</Accordion>
|
|
368
|
-
|
|
369
|
-
<Accordion title="Use silent mode for background operations">
|
|
370
|
-
Suppress output for installation and background tasks:
|
|
371
|
-
|
|
372
|
-
```javascript
|
|
373
|
-
// Silent install
|
|
374
|
-
await testdriver.exec('pwsh', 'npm install -g tool', 30000, true);
|
|
375
|
-
|
|
376
|
-
// Background process
|
|
377
|
-
await testdriver.exec('pwsh', 'Start-Process app', 5000, true);
|
|
378
|
-
```
|
|
379
|
-
</Accordion>
|
|
380
|
-
|
|
381
|
-
<Accordion title="Focus applications before interaction">
|
|
382
|
-
Always focus the target application before UI interactions:
|
|
383
|
-
|
|
384
|
-
```javascript
|
|
385
|
-
await testdriver.focusApplication('Google Chrome');
|
|
386
|
-
const button = await testdriver.find('submit button');
|
|
387
|
-
await button.click();
|
|
388
|
-
```
|
|
389
|
-
</Accordion>
|
|
390
|
-
|
|
391
|
-
<Accordion title="Escape strings properly in PowerShell">
|
|
392
|
-
Use proper escaping for special characters:
|
|
393
|
-
|
|
394
|
-
```javascript
|
|
395
|
-
// Use backticks for newlines in PowerShell strings
|
|
396
|
-
await testdriver.exec('pwsh', `
|
|
397
|
-
Write-Host "Line 1\`nLine 2"
|
|
398
|
-
`, 5000);
|
|
399
|
-
|
|
400
|
-
// Use single quotes to avoid variable expansion
|
|
401
|
-
await testdriver.exec('pwsh', "Write-Host 'Text with $special chars'", 5000);
|
|
402
|
-
```
|
|
403
|
-
</Accordion>
|
|
404
|
-
</AccordionGroup>
|