testdriverai 7.2.3 → 7.2.10
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/publish.yaml +15 -7
- package/.github/workflows/testdriver.yml +163 -0
- package/.testdriver/last-sandbox +7 -0
- package/agent/events.js +1 -0
- package/agent/index.js +99 -163
- package/agent/lib/sandbox.js +11 -1
- package/agents.md +393 -0
- package/bin/testdriverai.js +8 -0
- package/debug/01-table-initial.png +0 -0
- package/debug/02-after-ai-explore.png +0 -0
- package/debug/02-after-scroll.png +0 -0
- package/debugger/index.html +37 -0
- package/docs/docs.json +93 -125
- package/docs/v7/_drafts/architecture.mdx +1 -26
- package/docs/v7/_drafts/caching.mdx +2 -2
- package/docs/v7/{getting-started → _drafts}/installation.mdx +0 -66
- package/docs/v7/{features/coverage.mdx → _drafts/powerful.mdx} +1 -90
- package/docs/v7/_drafts/quick-start-test-recording.mdx +0 -1
- package/docs/v7/{features → _drafts}/scalable.mdx +126 -4
- package/docs/v7/_drafts/screenshot.mdx +155 -0
- package/docs/v7/_drafts/test-recording.mdx +0 -6
- package/docs/v7/_drafts/writing-tests.mdx +25 -0
- package/docs/v7/{api/act.mdx → ai.mdx} +28 -27
- package/docs/v7/{api/assert.mdx → assert.mdx} +3 -3
- package/docs/v7/aws-setup.mdx +338 -0
- package/docs/v7/caching.mdx +128 -0
- package/docs/v7/ci-cd.mdx +605 -0
- package/docs/v7/{api/click.mdx → click.mdx} +4 -4
- package/docs/v7/cloud.mdx +120 -0
- package/docs/v7/customizing-devices.mdx +129 -0
- package/docs/v7/{api/doubleClick.mdx → double-click.mdx} +5 -5
- package/docs/v7/enterprise.mdx +135 -0
- package/docs/v7/examples.mdx +5 -0
- package/docs/v7/{api/exec.mdx → exec.mdx} +3 -3
- package/docs/v7/{api/find.mdx → find.mdx} +17 -21
- package/docs/v7/{api/focusApplication.mdx → focus-application.mdx} +3 -3
- package/docs/v7/generating-tests.mdx +32 -0
- package/docs/v7/{api/hover.mdx → hover.mdx} +3 -3
- package/docs/v7/locating-elements.mdx +71 -0
- package/docs/v7/making-assertions.mdx +32 -0
- package/docs/v7/{api/mouseDown.mdx → mouse-down.mdx} +7 -7
- package/docs/v7/{api/mouseUp.mdx → mouse-up.mdx} +8 -8
- package/docs/v7/performing-actions.mdx +51 -0
- package/docs/v7/{api/pressKeys.mdx → press-keys.mdx} +3 -3
- package/docs/v7/quickstart.mdx +162 -0
- package/docs/v7/reusable-code.mdx +240 -0
- package/docs/v7/{api/rightClick.mdx → right-click.mdx} +5 -5
- package/docs/v7/running-tests.mdx +181 -0
- package/docs/v7/{api/scroll.mdx → scroll.mdx} +3 -3
- package/docs/v7/secrets.mdx +115 -0
- package/docs/v7/self-hosted.mdx +66 -0
- package/docs/v7/{api/type.mdx → type.mdx} +3 -3
- package/docs/v7/variables.mdx +111 -0
- package/docs/v7/waiting-for-elements.mdx +66 -0
- package/docs/v7/what-is-testdriver.mdx +54 -0
- package/interfaces/cli/commands/init.js +33 -19
- package/interfaces/cli/lib/base.js +24 -0
- package/interfaces/cli.js +8 -1
- package/interfaces/logger.js +8 -3
- package/interfaces/vitest-plugin.mjs +16 -71
- package/lib/sentry.js +343 -0
- package/lib/vitest/hooks.mjs +81 -81
- package/package.json +4 -3
- package/sdk-log-formatter.js +41 -0
- package/sdk.d.ts +22 -9
- package/sdk.js +344 -100
- package/test/manual/reconnect-provision.test.mjs +49 -0
- package/test/manual/reconnect-signin.test.mjs +41 -0
- package/test/testdriver/act.test.mjs +30 -0
- package/test/testdriver/ai.test.mjs +30 -0
- package/test/testdriver/assert.test.mjs +1 -1
- package/test/testdriver/hover-text.test.mjs +1 -1
- package/test/testdriver/setup/testHelpers.mjs +8 -119
- package/test/testdriver/windows-installer.test.mjs +61 -0
- package/tests/example.test.js +33 -0
- package/tests/login.js +28 -0
- package/tests/table-sort-enrollments.test.mjs +72 -0
- package/tests/table-sort-experiment.test.mjs +42 -0
- package/tests/table-sort-setup.test.mjs +59 -0
- package/vitest.config.mjs +3 -1
- package/agent/lib/cache.js +0 -142
- package/docs/v7/api/assertions.mdx +0 -403
- package/docs/v7/features/ai-native.mdx +0 -413
- package/docs/v7/features/application-logs.mdx +0 -353
- package/docs/v7/features/browser-logs.mdx +0 -414
- package/docs/v7/features/cache-management.mdx +0 -402
- package/docs/v7/features/continuous-testing.mdx +0 -346
- package/docs/v7/features/data-driven-testing.mdx +0 -441
- package/docs/v7/features/easy-to-write.mdx +0 -280
- package/docs/v7/features/enterprise.mdx +0 -656
- package/docs/v7/features/fast.mdx +0 -406
- package/docs/v7/features/managed-sandboxes.mdx +0 -384
- package/docs/v7/features/network-monitoring.mdx +0 -568
- package/docs/v7/features/parallel-execution.mdx +0 -381
- package/docs/v7/features/powerful.mdx +0 -531
- package/docs/v7/features/sandbox-customization.mdx +0 -229
- package/docs/v7/features/stable.mdx +0 -473
- package/docs/v7/features/system-performance.mdx +0 -616
- package/docs/v7/features/test-analytics.mdx +0 -373
- package/docs/v7/features/test-cases.mdx +0 -393
- package/docs/v7/features/test-replays.mdx +0 -408
- package/docs/v7/features/test-reports.mdx +0 -308
- package/docs/v7/getting-started/debugging-tests.mdx +0 -382
- package/docs/v7/getting-started/quickstart.mdx +0 -90
- package/docs/v7/getting-started/running-tests.mdx +0 -173
- package/docs/v7/getting-started/setting-up-in-ci.mdx +0 -612
- package/docs/v7/getting-started/writing-tests.mdx +0 -534
- package/docs/v7/overview/what-is-testdriver.mdx +0 -386
- package/docs/v7/presets/chrome-extension.mdx +0 -248
- package/docs/v7/presets/chrome.mdx +0 -300
- package/docs/v7/presets/electron.mdx +0 -460
- package/docs/v7/presets/vscode.mdx +0 -417
- package/docs/v7/presets/webapp.mdx +0 -393
- /package/docs/v7/{commands → _drafts/commands}/assert.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/exec.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/focus-application.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/hover-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/if.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/match-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/press-keys.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/remember.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/run.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll-until-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/scroll.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/type.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-image.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait-for-text.mdx +0 -0
- /package/docs/v7/{commands → _drafts/commands}/wait.mdx +0 -0
- /package/docs/v7/{getting-started → _drafts}/configuration.mdx +0 -0
- /package/docs/v7/{features → _drafts}/observable.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/linux.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/macos.mdx +0 -0
- /package/docs/v7/{platforms → _drafts/platforms}/windows.mdx +0 -0
- /package/docs/v7/{playwright.mdx → _drafts/playwright.mdx} +0 -0
- /package/docs/v7/{overview → _drafts}/readme.mdx +0 -0
- /package/docs/v7/{features → _drafts}/reports.mdx +0 -0
- /package/docs/v7/{api/client.mdx → client.mdx} +0 -0
- /package/docs/v7/{api/dashcam.mdx → dashcam.mdx} +0 -0
- /package/docs/v7/{api/elements.mdx → elements.mdx} +0 -0
- /package/docs/v7/{api/sandbox.mdx → sandbox.mdx} +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "screenshot()"
|
|
3
|
+
sidebarTitle: "screenshot"
|
|
4
|
+
description: "Capture a screenshot of the current screen"
|
|
5
|
+
icon: "camera"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Capture a screenshot of the current sandbox screen. Returns a base64 encoded PNG, or saves directly to a file and returns the filepath.
|
|
11
|
+
|
|
12
|
+
## Syntax
|
|
13
|
+
|
|
14
|
+
```javascript
|
|
15
|
+
// Options object (recommended)
|
|
16
|
+
await testdriver.screenshot(options)
|
|
17
|
+
|
|
18
|
+
// Legacy positional arguments
|
|
19
|
+
await testdriver.screenshot(scale, silent, mouse)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Parameters
|
|
23
|
+
|
|
24
|
+
<ParamField path="options" type="object">
|
|
25
|
+
Options object for screenshot capture
|
|
26
|
+
</ParamField>
|
|
27
|
+
|
|
28
|
+
<ParamField path="options.scale" type="number" default="1">
|
|
29
|
+
Scale factor for the screenshot (1 = original size, 0.5 = half size, etc.)
|
|
30
|
+
</ParamField>
|
|
31
|
+
|
|
32
|
+
<ParamField path="options.silent" type="boolean" default="false">
|
|
33
|
+
Whether to suppress logging output
|
|
34
|
+
</ParamField>
|
|
35
|
+
|
|
36
|
+
<ParamField path="options.mouse" type="boolean" default="false">
|
|
37
|
+
Whether to include the mouse cursor in the screenshot
|
|
38
|
+
</ParamField>
|
|
39
|
+
|
|
40
|
+
<ParamField path="options.path" type="string">
|
|
41
|
+
File path to save the screenshot. If provided, the screenshot is saved to this file and the filepath is returned instead of base64 data. Directories are created automatically if they don't exist.
|
|
42
|
+
</ParamField>
|
|
43
|
+
|
|
44
|
+
## Returns
|
|
45
|
+
|
|
46
|
+
`Promise<string>` - Base64 encoded PNG screenshot, or the filepath if `options.path` was provided.
|
|
47
|
+
|
|
48
|
+
## Examples
|
|
49
|
+
|
|
50
|
+
### Basic Screenshot (Base64)
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// Capture a screenshot and get base64 data
|
|
54
|
+
const screenshot = await testdriver.screenshot();
|
|
55
|
+
|
|
56
|
+
// Write to file manually
|
|
57
|
+
import fs from 'fs';
|
|
58
|
+
fs.writeFileSync('screenshot.png', Buffer.from(screenshot, 'base64'));
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Save Directly to File
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
// Save screenshot directly to a file (returns filepath)
|
|
65
|
+
const filepath = await testdriver.screenshot({ path: './screenshots/test.png' });
|
|
66
|
+
console.log(`Screenshot saved to: ${filepath}`);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### With Mouse Cursor
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
// Include mouse cursor in screenshot
|
|
73
|
+
const screenshot = await testdriver.screenshot({ mouse: true });
|
|
74
|
+
|
|
75
|
+
// Or save to file with mouse cursor
|
|
76
|
+
const filepath = await testdriver.screenshot({
|
|
77
|
+
path: './debug/with-cursor.png',
|
|
78
|
+
mouse: true
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Scaled Screenshot
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
// Capture at half size (useful for reducing file size)
|
|
86
|
+
const screenshot = await testdriver.screenshot({ scale: 0.5 });
|
|
87
|
+
|
|
88
|
+
// Capture at double size
|
|
89
|
+
const filepath = await testdriver.screenshot({
|
|
90
|
+
path: './hires.png',
|
|
91
|
+
scale: 2
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Silent Mode
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// Capture without logging output
|
|
99
|
+
const screenshot = await testdriver.screenshot({ silent: true });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Legacy Usage
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
// Legacy positional arguments still work
|
|
106
|
+
const screenshot = await testdriver.screenshot(1, false, true);
|
|
107
|
+
// Equivalent to: screenshot({ scale: 1, silent: false, mouse: true })
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Use Cases
|
|
111
|
+
|
|
112
|
+
### Debugging Test Failures
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
it('should complete checkout', async (context) => {
|
|
116
|
+
const testdriver = TestDriver(context, { newSandbox: true });
|
|
117
|
+
await testdriver.provision.chrome({ url: 'https://shop.example.com' });
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await testdriver.find('Checkout button').click();
|
|
121
|
+
await testdriver.assert('Order confirmation is visible');
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// Save screenshot on failure for debugging
|
|
124
|
+
await testdriver.screenshot({ path: './failures/checkout-failed.png' });
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Visual Documentation
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// Capture screenshots at each step for documentation
|
|
134
|
+
await testdriver.screenshot({ path: './docs/step1-login.png' });
|
|
135
|
+
await testdriver.find('Login button').click();
|
|
136
|
+
await testdriver.screenshot({ path: './docs/step2-dashboard.png' });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Comparing States
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// Capture before and after states
|
|
143
|
+
const before = await testdriver.screenshot();
|
|
144
|
+
await testdriver.find('Toggle dark mode').click();
|
|
145
|
+
const after = await testdriver.screenshot();
|
|
146
|
+
|
|
147
|
+
// Both are base64 - can be compared or stored
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Notes
|
|
151
|
+
|
|
152
|
+
- Screenshots are captured from the sandbox's virtual display
|
|
153
|
+
- The base64 string does not include a data URI prefix (raw base64)
|
|
154
|
+
- When using `path`, directories are created automatically if they don't exist
|
|
155
|
+
- File format is always PNG regardless of the file extension used
|
|
@@ -376,12 +376,6 @@ const run2 = await client.createTestRun({
|
|
|
376
376
|
- Associated dashcam replay
|
|
377
377
|
- Timing and duration
|
|
378
378
|
|
|
379
|
-
### TdSandbox
|
|
380
|
-
- VM/sandbox lifecycle tracking
|
|
381
|
-
- Platform and OS information
|
|
382
|
-
- Dashcam integration status
|
|
383
|
-
- Cost and usage metrics
|
|
384
|
-
|
|
385
379
|
### Replay
|
|
386
380
|
- Dashcam recordings
|
|
387
381
|
- Linked to test runs and cases
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Writing Tests"
|
|
3
|
+
description: "Learn how to write effective TestDriver tests with natural language"
|
|
4
|
+
icon: "pencil"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Learn how to write effective TestDriver tests. This section covers everything from generating tests with AI to making assertions.
|
|
8
|
+
|
|
9
|
+
<CardGroup cols={2}>
|
|
10
|
+
<Card title="Generating Tests" icon="wand-magic-sparkles" href="./generating-tests">
|
|
11
|
+
Use AI coding agents and exploration mode to generate tests
|
|
12
|
+
</Card>
|
|
13
|
+
<Card title="Locating Elements" icon="crosshairs" href="./locating-elements">
|
|
14
|
+
Find UI elements using natural language descriptions
|
|
15
|
+
</Card>
|
|
16
|
+
<Card title="Waiting for Elements" icon="clock" href="./waiting-for-elements">
|
|
17
|
+
Handle async operations and prevent flaky tests
|
|
18
|
+
</Card>
|
|
19
|
+
<Card title="Performing Actions" icon="computer-mouse" href="./performing-actions">
|
|
20
|
+
Click, type, hover, scroll and more
|
|
21
|
+
</Card>
|
|
22
|
+
<Card title="Making Assertions" icon="check-double" href="./making-assertions">
|
|
23
|
+
Verify application state with AI-powered assertions
|
|
24
|
+
</Card>
|
|
25
|
+
</CardGroup>
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
sidebarTitle: "
|
|
2
|
+
title: "ai()"
|
|
3
|
+
sidebarTitle: "ai"
|
|
4
4
|
description: "Execute natural language tasks using AI"
|
|
5
5
|
icon: "wand-magic-sparkles"
|
|
6
|
+
tag: beta
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
## Overview
|
|
9
10
|
|
|
10
|
-
The `
|
|
11
|
+
The `ai()` method allows you to execute complex tasks using natural language descriptions. TestDriver's AI will figure out the steps needed to accomplish the task.
|
|
11
12
|
|
|
12
13
|
## Syntax
|
|
13
14
|
|
|
14
15
|
```javascript
|
|
15
|
-
await testdriver.
|
|
16
|
+
await testdriver.ai(task, options)
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
## Parameters
|
|
@@ -41,20 +42,20 @@ await testdriver.act(task, options)
|
|
|
41
42
|
|
|
42
43
|
```javascript
|
|
43
44
|
// Simple task execution
|
|
44
|
-
await testdriver.
|
|
45
|
+
await testdriver.ai('Click the submit button');
|
|
45
46
|
|
|
46
47
|
// Complex multi-step task
|
|
47
|
-
await testdriver.
|
|
48
|
+
await testdriver.ai('Fill out the contact form and submit it');
|
|
48
49
|
|
|
49
50
|
// Navigation task
|
|
50
|
-
await testdriver.
|
|
51
|
+
await testdriver.ai('Go to the settings page and enable notifications');
|
|
51
52
|
```
|
|
52
53
|
|
|
53
54
|
### With Validation
|
|
54
55
|
|
|
55
56
|
```javascript
|
|
56
57
|
// AI will verify the task completed successfully
|
|
57
|
-
const result = await testdriver.
|
|
58
|
+
const result = await testdriver.ai('Complete the checkout process', {
|
|
58
59
|
validateAndLoop: true
|
|
59
60
|
});
|
|
60
61
|
|
|
@@ -65,10 +66,10 @@ console.log('Task result:', result);
|
|
|
65
66
|
|
|
66
67
|
```javascript
|
|
67
68
|
// The AI will break down complex tasks
|
|
68
|
-
await testdriver.
|
|
69
|
+
await testdriver.ai('Search for "laptop", add the first result to cart, and proceed to checkout');
|
|
69
70
|
|
|
70
71
|
// UI exploration
|
|
71
|
-
await testdriver.
|
|
72
|
+
await testdriver.ai('Find and click all menu items to explore the application');
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
## Use Cases
|
|
@@ -78,8 +79,8 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
78
79
|
Use AI to explore unfamiliar applications:
|
|
79
80
|
|
|
80
81
|
```javascript
|
|
81
|
-
await testdriver.
|
|
82
|
-
await testdriver.
|
|
82
|
+
await testdriver.ai('Explore the main navigation menu');
|
|
83
|
+
await testdriver.ai('Try to find the user profile settings');
|
|
83
84
|
```
|
|
84
85
|
</Accordion>
|
|
85
86
|
|
|
@@ -87,8 +88,8 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
87
88
|
Let AI handle multi-step processes:
|
|
88
89
|
|
|
89
90
|
```javascript
|
|
90
|
-
await testdriver.
|
|
91
|
-
await testdriver.
|
|
91
|
+
await testdriver.ai('Complete the multi-step registration form');
|
|
92
|
+
await testdriver.ai('Configure all the advanced settings to default values');
|
|
92
93
|
```
|
|
93
94
|
</Accordion>
|
|
94
95
|
|
|
@@ -96,8 +97,8 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
96
97
|
When exact element locations aren't critical:
|
|
97
98
|
|
|
98
99
|
```javascript
|
|
99
|
-
await testdriver.
|
|
100
|
-
await testdriver.
|
|
100
|
+
await testdriver.ai('Close any popup dialogs');
|
|
101
|
+
await testdriver.ai('Accept the cookie consent if it appears');
|
|
101
102
|
```
|
|
102
103
|
</Accordion>
|
|
103
104
|
</AccordionGroup>
|
|
@@ -109,13 +110,13 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
109
110
|
|
|
110
111
|
```javascript
|
|
111
112
|
// ✅ Good
|
|
112
|
-
await testdriver.
|
|
113
|
+
await testdriver.ai('Add the first product to the shopping cart');
|
|
113
114
|
|
|
114
115
|
// ❌ Too vague
|
|
115
|
-
await testdriver.
|
|
116
|
+
await testdriver.ai('do something');
|
|
116
117
|
|
|
117
118
|
// ❌ Too specific (defeats the purpose)
|
|
118
|
-
await testdriver.
|
|
119
|
+
await testdriver.ai('click at coordinates 500, 300');
|
|
119
120
|
```
|
|
120
121
|
</Check>
|
|
121
122
|
|
|
@@ -124,7 +125,7 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
124
125
|
|
|
125
126
|
```javascript
|
|
126
127
|
// Use AI for setup
|
|
127
|
-
await testdriver.
|
|
128
|
+
await testdriver.ai('Navigate to the login page');
|
|
128
129
|
|
|
129
130
|
// Use explicit methods for critical steps
|
|
130
131
|
const usernameField = await testdriver.find('username input');
|
|
@@ -141,7 +142,7 @@ await testdriver.act('Find and click all menu items to explore the application')
|
|
|
141
142
|
|
|
142
143
|
## When to Use AI vs Explicit Methods
|
|
143
144
|
|
|
144
|
-
### Use `
|
|
145
|
+
### Use `ai()` when:
|
|
145
146
|
- Exploring unfamiliar applications
|
|
146
147
|
- Handling optional UI elements (popups, cookies, etc.)
|
|
147
148
|
- Prototyping tests quickly
|
|
@@ -177,8 +178,8 @@ describe('E-commerce Flow with AI', () => {
|
|
|
177
178
|
await testdriver.focusApplication('Google Chrome');
|
|
178
179
|
|
|
179
180
|
// Use AI for navigation and exploration
|
|
180
|
-
await testdriver.
|
|
181
|
-
await testdriver.
|
|
181
|
+
await testdriver.ai('Browse to the electronics section');
|
|
182
|
+
await testdriver.ai('Find and add a laptop to the cart');
|
|
182
183
|
|
|
183
184
|
// Use explicit methods for critical steps
|
|
184
185
|
const cartIcon = await testdriver.find('shopping cart icon');
|
|
@@ -188,7 +189,7 @@ describe('E-commerce Flow with AI', () => {
|
|
|
188
189
|
console.log('Cart total:', total);
|
|
189
190
|
|
|
190
191
|
// Use AI for checkout flow
|
|
191
|
-
await testdriver.
|
|
192
|
+
await testdriver.ai('Proceed to checkout and fill in shipping details', {
|
|
192
193
|
validateAndLoop: true
|
|
193
194
|
});
|
|
194
195
|
|
|
@@ -200,6 +201,6 @@ describe('E-commerce Flow with AI', () => {
|
|
|
200
201
|
|
|
201
202
|
## Related Methods
|
|
202
203
|
|
|
203
|
-
- [`find()`](/v7/
|
|
204
|
-
- [`assert()`](/v7/
|
|
205
|
-
- [`extract()`](/v7/
|
|
204
|
+
- [`find()`](/v7/find) - Locate specific elements
|
|
205
|
+
- [`assert()`](/v7/assert) - Make assertions
|
|
206
|
+
- [`extract()`](/v7/extract) - Extract information
|
|
@@ -280,6 +280,6 @@ describe('Assertions', () => {
|
|
|
280
280
|
|
|
281
281
|
## Related Methods
|
|
282
282
|
|
|
283
|
-
- [`extract()`](/v7/
|
|
284
|
-
- [`find()`](/v7/
|
|
285
|
-
- [`ai()`](/v7/
|
|
283
|
+
- [`extract()`](/v7/extract) - Extract information for detailed assertions
|
|
284
|
+
- [`find()`](/v7/find) - Locate elements to verify
|
|
285
|
+
- [`ai()`](/v7/ai) - Complex AI-driven tasks
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "AWS Setup Guide"
|
|
3
|
+
sidebarTitle: "AWS Setup"
|
|
4
|
+
description: "Deploy TestDriver on your AWS infrastructure using CloudFormation"
|
|
5
|
+
icon: "aws"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
This guide walks you through setting up self-hosted TestDriver instances on AWS. By the end, you'll have a complete infrastructure that can spawn test environments on-demand and integrate with your CI/CD pipelines.
|
|
9
|
+
|
|
10
|
+
```mermaid
|
|
11
|
+
graph LR
|
|
12
|
+
A[Vitest] <--> B[api.testdriver.ai]
|
|
13
|
+
B <--> C[Your AWS EC2 Instance]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
The setup process involves three main steps:
|
|
19
|
+
|
|
20
|
+
1. **CloudFormation Infrastructure** — Deploy our template to create VPC, security groups, IAM roles, and launch templates
|
|
21
|
+
2. **On-Demand Instance Spawning** — Use `spawn-runner.sh` to launch TestDriver instances when you need to run tests
|
|
22
|
+
3. **CI/CD Integration** — Automate the lifecycle in GitHub Actions: spawn instance → run tests → terminate instance
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
Before you begin, ensure you have:
|
|
27
|
+
|
|
28
|
+
- AWS account with CloudFormation permissions
|
|
29
|
+
- [AWS CLI](https://aws.amazon.com/cli/) installed and configured (`aws configure`)
|
|
30
|
+
- Access to the TestDriver AMI — [Contact us](https://form.typeform.com/to/UECf9rDx?typeform-source=testdriver.ai) with your AWS region
|
|
31
|
+
- A GitHub repository for your tests
|
|
32
|
+
|
|
33
|
+
<Tip>
|
|
34
|
+
The TestDriver Golden Image AMI ID is `ami-086b5b4b86d78987c`. Contact us to get access in your preferred AWS region.
|
|
35
|
+
</Tip>
|
|
36
|
+
|
|
37
|
+
## Step 1: Deploy CloudFormation Stack
|
|
38
|
+
|
|
39
|
+
Our CloudFormation template creates all the AWS infrastructure you need:
|
|
40
|
+
|
|
41
|
+
- Dedicated VPC with public subnet
|
|
42
|
+
- Security group with required port access
|
|
43
|
+
- IAM roles and instance profiles
|
|
44
|
+
- EC2 launch template for instance creation
|
|
45
|
+
|
|
46
|
+
Download the template from the [TestDriver CLI repository](https://github.com/testdriverai/testdriverai/tree/main/setup/aws/cloudformation.yaml), then deploy:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
aws cloudformation deploy \
|
|
50
|
+
--template-file setup/aws/cloudformation.yaml \
|
|
51
|
+
--stack-name testdriver-infrastructure \
|
|
52
|
+
--parameter-overrides \
|
|
53
|
+
ProjectTag=testdriver \
|
|
54
|
+
AllowedIngressCidr=0.0.0.0/0 \
|
|
55
|
+
InstanceType=c5.xlarge \
|
|
56
|
+
CreateKeyPair=true \
|
|
57
|
+
--capabilities CAPABILITY_IAM
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
<Warning>
|
|
61
|
+
**Security**: Replace `AllowedIngressCidr=0.0.0.0/0` with your specific IP ranges to restrict VPC access.
|
|
62
|
+
</Warning>
|
|
63
|
+
|
|
64
|
+
### Get Your Launch Template ID
|
|
65
|
+
|
|
66
|
+
After deployment completes, retrieve the launch template ID:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
aws cloudformation describe-stacks \
|
|
70
|
+
--stack-name testdriver-infrastructure \
|
|
71
|
+
--query 'Stacks[0].Outputs[?OutputKey==`LaunchTemplateId`].OutputValue' \
|
|
72
|
+
--output text
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
<Tip>
|
|
76
|
+
**Save this ID** — you'll need it for spawning instances and CI configuration.
|
|
77
|
+
</Tip>
|
|
78
|
+
|
|
79
|
+
## Step 2: Spawn Test Instances
|
|
80
|
+
|
|
81
|
+
Use the `spawn-runner.sh` script to launch instances on-demand. This script:
|
|
82
|
+
|
|
83
|
+
- Launches a new EC2 instance using your launch template
|
|
84
|
+
- Waits for the instance to be ready
|
|
85
|
+
- Completes the TestDriver handshake
|
|
86
|
+
- Returns instance details for test execution
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Set environment variables
|
|
90
|
+
export AWS_REGION=us-east-2
|
|
91
|
+
export AMI_ID=ami-086b5b4b86d78987c
|
|
92
|
+
export AWS_LAUNCH_TEMPLATE_ID=lt-your-template-id
|
|
93
|
+
export RESOLUTION=1440x900 # Optional, default is 1440x900
|
|
94
|
+
|
|
95
|
+
# Spawn an instance
|
|
96
|
+
./setup/aws/spawn-runner.sh
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Output:
|
|
100
|
+
```
|
|
101
|
+
PUBLIC_IP=1.2.3.4
|
|
102
|
+
INSTANCE_ID=i-1234567890abcdef0
|
|
103
|
+
AWS_REGION=us-east-2
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Run Tests Against Your Instance
|
|
107
|
+
|
|
108
|
+
With Vitest, specify the instance IP using the `TD_VM` environment variable:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
TD_API_KEY=your-api-key TD_VM=1.2.3.4 npx vitest run
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Terminate Instances
|
|
115
|
+
|
|
116
|
+
Always terminate instances after tests complete to avoid unnecessary costs:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
aws ec2 terminate-instances \
|
|
120
|
+
--instance-ids i-1234567890abcdef0 \
|
|
121
|
+
--region us-east-2
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
<Note>
|
|
125
|
+
Instances are tagged with `Name=TestDriverRunner` and your `ProjectTag` for easy identification in the AWS console.
|
|
126
|
+
</Note>
|
|
127
|
+
|
|
128
|
+
## Step 3: GitHub Actions Integration
|
|
129
|
+
|
|
130
|
+
Automate the full lifecycle in your CI/CD pipeline. This workflow spawns an instance, runs tests, and terminates the instance:
|
|
131
|
+
|
|
132
|
+
```yaml .github/workflows/test.yml
|
|
133
|
+
name: TestDriver Self-Hosted
|
|
134
|
+
|
|
135
|
+
on:
|
|
136
|
+
push:
|
|
137
|
+
branches: [main]
|
|
138
|
+
pull_request:
|
|
139
|
+
|
|
140
|
+
# Prevent concurrent runs from competing for resources
|
|
141
|
+
concurrency:
|
|
142
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
143
|
+
cancel-in-progress: true
|
|
144
|
+
|
|
145
|
+
jobs:
|
|
146
|
+
test:
|
|
147
|
+
runs-on: ubuntu-latest
|
|
148
|
+
steps:
|
|
149
|
+
- name: Checkout repository
|
|
150
|
+
uses: actions/checkout@v4
|
|
151
|
+
|
|
152
|
+
- name: Setup Node.js
|
|
153
|
+
uses: actions/setup-node@v4
|
|
154
|
+
with:
|
|
155
|
+
node-version: '20'
|
|
156
|
+
|
|
157
|
+
- name: Install dependencies
|
|
158
|
+
run: npm install
|
|
159
|
+
|
|
160
|
+
- name: Setup AWS Instance
|
|
161
|
+
id: aws-setup
|
|
162
|
+
run: |
|
|
163
|
+
OUTPUT=$(./setup/aws/spawn-runner.sh | tee /dev/stderr)
|
|
164
|
+
PUBLIC_IP=$(echo "$OUTPUT" | grep "PUBLIC_IP=" | cut -d'=' -f2)
|
|
165
|
+
INSTANCE_ID=$(echo "$OUTPUT" | grep "INSTANCE_ID=" | cut -d'=' -f2)
|
|
166
|
+
echo "public-ip=$PUBLIC_IP" >> $GITHUB_OUTPUT
|
|
167
|
+
echo "instance-id=$INSTANCE_ID" >> $GITHUB_OUTPUT
|
|
168
|
+
env:
|
|
169
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
170
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
171
|
+
AWS_REGION: ${{ secrets.AWS_REGION }}
|
|
172
|
+
AWS_LAUNCH_TEMPLATE_ID: ${{ secrets.AWS_LAUNCH_TEMPLATE_ID }}
|
|
173
|
+
AMI_ID: ${{ secrets.AMI_ID }}
|
|
174
|
+
|
|
175
|
+
- name: Run Tests
|
|
176
|
+
run: npx vitest run
|
|
177
|
+
env:
|
|
178
|
+
TD_API_KEY: ${{ secrets.TD_API_KEY }}
|
|
179
|
+
TD_VM: ${{ steps.aws-setup.outputs.public-ip }}
|
|
180
|
+
|
|
181
|
+
- name: Shutdown AWS Instance
|
|
182
|
+
if: always()
|
|
183
|
+
run: |
|
|
184
|
+
aws ec2 terminate-instances \
|
|
185
|
+
--region ${{ secrets.AWS_REGION }} \
|
|
186
|
+
--instance-ids ${{ steps.aws-setup.outputs.instance-id }}
|
|
187
|
+
env:
|
|
188
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
189
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
190
|
+
AWS_REGION: ${{ secrets.AWS_REGION }}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Required GitHub Secrets
|
|
194
|
+
|
|
195
|
+
| Secret | Description | Example |
|
|
196
|
+
|--------|-------------|---------|
|
|
197
|
+
| `AWS_ACCESS_KEY_ID` | AWS access key | `AKIAIOSFODNN7EXAMPLE` |
|
|
198
|
+
| `AWS_SECRET_ACCESS_KEY` | AWS secret key | `wJalrXUtnFEMI/K7MDENG...` |
|
|
199
|
+
| `AWS_REGION` | AWS region | `us-east-2` |
|
|
200
|
+
| `AWS_LAUNCH_TEMPLATE_ID` | From CloudFormation output | `lt-07c53ce8349b958d1` |
|
|
201
|
+
| `AMI_ID` | TestDriver AMI ID | `ami-086b5b4b86d78987c` |
|
|
202
|
+
| `TD_API_KEY` | Your TestDriver API key | From [console.testdriver.ai](https://console.testdriver.ai) |
|
|
203
|
+
|
|
204
|
+
## AMI Customization
|
|
205
|
+
|
|
206
|
+
The TestDriver Golden Image comes pre-configured with:
|
|
207
|
+
|
|
208
|
+
- Windows Server with desktop environment
|
|
209
|
+
- VNC + web server for remote access
|
|
210
|
+
- Python, Node.js, Git
|
|
211
|
+
- TestDriver agent and dependencies
|
|
212
|
+
|
|
213
|
+
### Creating a Custom AMI
|
|
214
|
+
|
|
215
|
+
You can customize the AMI to include additional software or configurations:
|
|
216
|
+
|
|
217
|
+
<Steps>
|
|
218
|
+
<Step title="Connect via RDP">
|
|
219
|
+
Use the default credentials:
|
|
220
|
+
- **Username**: `testdriver`
|
|
221
|
+
- **Password**: `changemeABC123`
|
|
222
|
+
</Step>
|
|
223
|
+
|
|
224
|
+
<Step title="Change the Password">
|
|
225
|
+
**Critical**: Run the password rotation script immediately:
|
|
226
|
+
```powershell
|
|
227
|
+
C:\testdriver\RotateLocalPasswords.ps1
|
|
228
|
+
```
|
|
229
|
+
Save the new password securely.
|
|
230
|
+
</Step>
|
|
231
|
+
|
|
232
|
+
<Step title="Install Your Software">
|
|
233
|
+
Install any additional dependencies, configure settings, or modify the environment as needed.
|
|
234
|
+
</Step>
|
|
235
|
+
|
|
236
|
+
<Step title="Create New AMI">
|
|
237
|
+
Use the AWS console or CLI to create an AMI from your modified instance. Update your workflow to use the new AMI ID.
|
|
238
|
+
</Step>
|
|
239
|
+
</Steps>
|
|
240
|
+
|
|
241
|
+
<Warning>
|
|
242
|
+
**Security**: Never use the default password in production. Always rotate passwords before creating custom AMIs.
|
|
243
|
+
</Warning>
|
|
244
|
+
|
|
245
|
+
### Changing Screen Resolution
|
|
246
|
+
|
|
247
|
+
Set resolution via environment variable when spawning:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
export RESOLUTION=1920x1080
|
|
251
|
+
./setup/aws/spawn-runner.sh
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Or in a lifecycle provision script:
|
|
255
|
+
|
|
256
|
+
```yaml lifecycle/provision.yaml
|
|
257
|
+
version: 7.0.0
|
|
258
|
+
steps:
|
|
259
|
+
- prompt: set screen resolution
|
|
260
|
+
commands:
|
|
261
|
+
- command: exec
|
|
262
|
+
lang: pwsh
|
|
263
|
+
code: |
|
|
264
|
+
C:\testdriver\SetResolution.ps1 -Width 1920 -Height 1080
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Security Best Practices
|
|
268
|
+
|
|
269
|
+
### Network Security
|
|
270
|
+
|
|
271
|
+
- **Restrict CIDR blocks** — Only allow access from known IP ranges
|
|
272
|
+
- **Use VPC endpoints** — For private AWS service communication
|
|
273
|
+
- **Enable VPC Flow Logs** — For network monitoring
|
|
274
|
+
|
|
275
|
+
### AWS Authentication
|
|
276
|
+
|
|
277
|
+
Use OIDC instead of long-term credentials for GitHub Actions:
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
permissions:
|
|
281
|
+
id-token: write
|
|
282
|
+
contents: read
|
|
283
|
+
|
|
284
|
+
steps:
|
|
285
|
+
- name: Configure AWS credentials
|
|
286
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
287
|
+
with:
|
|
288
|
+
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
|
|
289
|
+
aws-region: us-east-2
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
See [GitHub's OIDC documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) for setup instructions.
|
|
293
|
+
|
|
294
|
+
### Instance Security
|
|
295
|
+
|
|
296
|
+
- **Terminate immediately** after tests complete
|
|
297
|
+
- **Monitor costs** with AWS billing alerts
|
|
298
|
+
- **Use least-privilege IAM roles**
|
|
299
|
+
- **Enable CloudTrail** for audit logging
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
### Instance Not Responding
|
|
304
|
+
|
|
305
|
+
- **Check security groups** — Verify required ports are open (RDP 3389, VNC 5900, TestDriver ports)
|
|
306
|
+
- **Verify status checks** — Ensure instance has passed AWS status checks
|
|
307
|
+
- **Check AMI compatibility** — Some instance types don't support certain AMIs
|
|
308
|
+
|
|
309
|
+
### Connection Timeouts
|
|
310
|
+
|
|
311
|
+
- Verify network connectivity from CI runner to instance
|
|
312
|
+
- Check VPC routing and internet gateway configuration
|
|
313
|
+
- Confirm instance is in the correct subnet
|
|
314
|
+
|
|
315
|
+
### AWS CLI Errors
|
|
316
|
+
|
|
317
|
+
- Validate credentials and permissions
|
|
318
|
+
- Check service quotas and limits
|
|
319
|
+
- Verify region consistency across all resources
|
|
320
|
+
|
|
321
|
+
## Getting Help
|
|
322
|
+
|
|
323
|
+
<CardGroup cols={2}>
|
|
324
|
+
<Card
|
|
325
|
+
title="Contact Support"
|
|
326
|
+
icon="envelope"
|
|
327
|
+
href="https://calendly.com/d/cq23-qyn-3v6/testdriver-ai-demo"
|
|
328
|
+
>
|
|
329
|
+
Get help with self-hosted setup and configuration
|
|
330
|
+
</Card>
|
|
331
|
+
<Card
|
|
332
|
+
title="Self-Hosted Overview"
|
|
333
|
+
icon="server"
|
|
334
|
+
href="/v7/self-hosted"
|
|
335
|
+
>
|
|
336
|
+
Learn more about self-hosted benefits and pricing
|
|
337
|
+
</Card>
|
|
338
|
+
</CardGroup>
|