@testdriverai/agent 7.11.229-test → 7.11.232-test
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/_data/examples-manifest.json +16 -16
- package/docs/_scripts/generate-examples.js +38 -45
- package/docs/agent.mdx +174 -93
- package/docs/assert.mdx +73 -269
- package/docs/aws-setup.mdx +196 -314
- package/docs/bring-your-own-machine.mdx +139 -206
- package/docs/cache.mdx +144 -151
- package/docs/caching.mdx +99 -89
- package/docs/captcha.mdx +126 -111
- package/docs/ci-cd.mdx +154 -543
- package/docs/click.mdx +74 -229
- package/docs/client.mdx +177 -231
- package/docs/copilot/auto-healing.mdx +86 -370
- package/docs/copilot/running-tests.mdx +121 -930
- package/docs/customizing-devices.mdx +74 -251
- package/docs/dashcam.mdx +72 -405
- package/docs/debugging-with-screenshots.mdx +105 -371
- package/docs/docs.json +79 -22
- package/docs/double-click.mdx +48 -68
- package/docs/errors.mdx +102 -176
- package/docs/events.mdx +170 -327
- package/docs/examples/{hover-text-with-description.mdx → add-to-cart.mdx} +30 -35
- package/docs/examples/assert.mdx +28 -41
- package/docs/examples/click-button.mdx +71 -0
- package/docs/examples/{hover-image.mdx → click-icon.mdx} +32 -28
- package/docs/examples/element-not-found.mdx +27 -26
- package/docs/examples/findall-coffee-icons.mdx +28 -32
- package/docs/examples/installer.mdx +61 -25
- package/docs/examples/launch-vscode-linux.mdx +28 -51
- package/docs/examples/navigate-and-scroll.mdx +82 -0
- package/docs/examples/parse.mdx +24 -28
- package/docs/examples/press-keys.mdx +28 -25
- package/docs/examples/scroll.mdx +25 -27
- package/docs/examples/type.mdx +26 -21
- package/docs/exec.mdx +92 -256
- package/docs/extract.mdx +69 -170
- package/docs/find.mdx +140 -736
- package/docs/focus-application.mdx +69 -246
- package/docs/generating-tests.mdx +103 -137
- package/docs/guide/best-practices-polling.mdx +65 -141
- package/docs/hosted.mdx +80 -144
- package/docs/hover.mdx +62 -235
- package/docs/locating-elements.mdx +74 -369
- package/docs/making-assertions.mdx +116 -74
- package/docs/mcp-setup.mdx +80 -63
- package/docs/mouse-down.mdx +48 -125
- package/docs/mouse-up.mdx +47 -129
- package/docs/options.mdx +75 -48
- package/docs/parse.mdx +95 -184
- package/docs/performing-actions.mdx +104 -94
- package/docs/press-keys.mdx +59 -299
- package/docs/provision.mdx +137 -182
- package/docs/quickstart-claude.mdx +85 -0
- package/docs/quickstart-github.mdx +62 -32
- package/docs/quickstart-manual.mdx +60 -33
- package/docs/quickstart-vscode.mdx +97 -0
- package/docs/quickstart.mdx +26 -9
- package/docs/redraw.mdx +101 -165
- package/docs/reusable-code.mdx +97 -200
- package/docs/right-click.mdx +47 -89
- package/docs/screenshot.mdx +47 -201
- package/docs/screenshots.mdx +87 -137
- package/docs/scroll.mdx +71 -154
- package/docs/secrets.mdx +96 -91
- package/docs/self-hosted.mdx +83 -142
- package/docs/snippets/enterprise.mdx +15 -0
- package/docs/styles.css +68 -0
- package/docs/test-results-json.mdx +167 -204
- package/docs/type.mdx +56 -304
- package/docs/variables.mdx +121 -81
- package/docs/wait.mdx +33 -31
- package/docs/what-is-testdriver.mdx +80 -32
- package/examples/{hover-text-with-description.test.mjs → add-to-cart.test.mjs} +4 -5
- package/examples/assert.test.mjs +3 -20
- package/examples/{hover-text.test.mjs → click-button.test.mjs} +3 -4
- package/examples/{hover-image.test.mjs → click-icon.test.mjs} +5 -6
- package/examples/element-not-found.test.mjs +3 -5
- package/examples/findall-coffee-icons.test.mjs +3 -3
- package/examples/installer.test.mjs +1 -1
- package/examples/launch-vscode-linux.test.mjs +6 -33
- package/examples/{scroll-keyboard.test.mjs → navigate-and-scroll.test.mjs} +4 -5
- package/examples/parse.test.mjs +1 -2
- package/examples/press-keys.test.mjs +4 -4
- package/examples/scroll.test.mjs +3 -6
- package/examples/type.test.mjs +5 -2
- package/lib/provision.js +6 -2
- package/package.json +1 -1
- package/sdk.d.ts +4 -2
- package/sdk.js +1 -1
- package/docs/claude-mcp-plugin.mdx +0 -244
- package/docs/elements.mdx +0 -606
- package/docs/examples/ai.mdx +0 -78
- package/docs/examples/captcha-api.mdx +0 -92
- package/docs/examples/chrome-extension.mdx +0 -156
- package/docs/examples/drag-and-drop.mdx +0 -100
- package/docs/examples/formatted-logging.mdx +0 -74
- package/docs/examples/hover-text.mdx +0 -70
- package/docs/examples/match-image.mdx +0 -97
- package/docs/examples/scroll-keyboard.mdx +0 -80
- package/docs/examples/scroll-until-text.mdx +0 -109
|
@@ -1,1010 +1,201 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
sidebarTitle: "Running
|
|
4
|
-
description: "
|
|
2
|
+
title: "Run tests"
|
|
3
|
+
sidebarTitle: "Running tests"
|
|
4
|
+
description: "Run tests from the terminal or VS Code, in parallel, and watch them live."
|
|
5
5
|
icon: "play"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
If you haven't written tests yet, start with [Explore](/generating-tests) to generate your first tests and [Learn](/caching) to make them fast and reliable.
|
|
11
|
-
|
|
12
|
-
## Setup
|
|
13
|
-
|
|
14
|
-
TestDriver integrates with AI coding assistants through the VS Code extension and MCP server. The same MCP server works with GitHub Copilot, Cursor, Claude Desktop, and any other MCP-capable assistant. This section walks you through the complete setup.
|
|
15
|
-
|
|
16
|
-
### Prerequisites
|
|
17
|
-
|
|
18
|
-
Before you begin, you'll need:
|
|
19
|
-
|
|
20
|
-
- **An MCP-capable AI assistant** — Such as GitHub Copilot, Cursor, or Claude Desktop. For Copilot, a [free tier](https://github.com/features/copilot/plans) is available.
|
|
21
|
-
- **TestDriver Account** — Create a free account at [console.testdriver.ai](https://console.testdriver.ai/settings) to get your API key. 60 free device minutes, no credit card required.
|
|
22
|
-
- **VS Code** — The TestDriver extension provides the best experience with live preview and integrated test running.
|
|
23
|
-
|
|
24
|
-
### Setup Steps
|
|
25
|
-
|
|
26
|
-
<Steps>
|
|
27
|
-
<Step title="Install the TestDriver Extension">
|
|
28
|
-
<Card
|
|
29
|
-
horizontal
|
|
30
|
-
title="Install TestDriver for VS Code"
|
|
31
|
-
arrow
|
|
32
|
-
href="vscode:extension/testdriver.testdriver"
|
|
33
|
-
icon="/images/content/extension/vscode.svg"
|
|
34
|
-
></Card>
|
|
35
|
-
|
|
36
|
-
The extension provides:
|
|
37
|
-
- One-click sign-in and project initialization
|
|
38
|
-
- Live preview panel for watching tests execute
|
|
39
|
-
- MCP server configuration
|
|
40
|
-
</Step>
|
|
41
|
-
|
|
42
|
-
<Step title="Sign Into TestDriver">
|
|
43
|
-
Sign in to connect your account and API key.
|
|
44
|
-
|
|
45
|
-
1. Open the command palette (`Cmd+Shift+P` or `Ctrl+Shift+P`)
|
|
46
|
-
2. Run **TestDriver: Login**
|
|
47
|
-
3. Your browser will open to the TestDriver sign-in page
|
|
48
|
-
4. Sign in (or create an account)
|
|
49
|
-
5. You'll be redirected back to VS Code, now signed in
|
|
50
|
-
|
|
51
|
-
<Tip>
|
|
52
|
-
The extension automatically saves your API key to VS Code's secure storage and your workspace `.env` file.
|
|
53
|
-
</Tip>
|
|
54
|
-
</Step>
|
|
55
|
-
|
|
56
|
-
<Step title="Initialize Your Project">
|
|
57
|
-
Set up TestDriver in your project with a single command.
|
|
58
|
-
|
|
59
|
-
1. Open the command palette (`Cmd+Shift+P` or `Ctrl+Shift+P`)
|
|
60
|
-
2. Run **TestDriver: Init Project**
|
|
61
|
-
|
|
62
|
-
This command:
|
|
63
|
-
- Creates a `package.json` with TestDriver and Vitest dependencies
|
|
64
|
-
- Generates a `vitest.config.mjs` with proper timeout settings
|
|
65
|
-
- Creates example test files in `tests/`
|
|
66
|
-
- Sets up `.env` with your API key
|
|
67
|
-
- Creates the TestDriver agent file at `.github/agents/testdriver.agent.md`
|
|
68
|
-
- Configures the MCP server
|
|
69
|
-
|
|
70
|
-
<Note>
|
|
71
|
-
If you already have a `package.json`, the command will add the necessary dependencies to it.
|
|
72
|
-
</Note>
|
|
73
|
-
</Step>
|
|
74
|
-
|
|
75
|
-
<Step title="Start the MCP Server">
|
|
76
|
-
The MCP server enables your AI assistant to control TestDriver sandboxes.
|
|
77
|
-
|
|
78
|
-
After initialization, the MCP configuration is created at `.vscode/mcp.json`:
|
|
79
|
-
|
|
80
|
-
```json .vscode/mcp.json
|
|
81
|
-
{
|
|
82
|
-
"servers": {
|
|
83
|
-
"testdriver": {
|
|
84
|
-
"command": "npx",
|
|
85
|
-
"args": ["-p", "testdriverai", "testdriverai-mcp"],
|
|
86
|
-
"env": {
|
|
87
|
-
"TD_PREVIEW": "ide",
|
|
88
|
-
"TD_API_KEY": "your-api-key"
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**To start the MCP server:**
|
|
96
|
-
|
|
97
|
-
1. Open the command palette (`Cmd+Shift+P` or `Ctrl+Shift+P`)
|
|
98
|
-
2. Run **MCP: List Servers**
|
|
99
|
-
3. Click on the **testdriver** server
|
|
100
|
-
4. Select **Start Server**
|
|
101
|
-
|
|
102
|
-
You can also click the MCP icon in the status bar to manage servers.
|
|
103
|
-
|
|
104
|
-
<Tip>
|
|
105
|
-
See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more details on managing MCP servers.
|
|
106
|
-
</Tip>
|
|
107
|
-
|
|
108
|
-
<Warning>
|
|
109
|
-
Make sure your API key is set. The extension uses the key from your sign-in, but you can also set it via the `TD_API_KEY` environment variable.
|
|
110
|
-
</Warning>
|
|
111
|
-
</Step>
|
|
112
|
-
|
|
113
|
-
<Step title="Install Vitest Extension (Recommended)">
|
|
114
|
-
For the best experience running tests, install the Vitest extension:
|
|
115
|
-
|
|
116
|
-
<Card
|
|
117
|
-
horizontal
|
|
118
|
-
title="Vitest Extension"
|
|
119
|
-
arrow
|
|
120
|
-
href="vscode:extension/vitest.explorer"
|
|
121
|
-
icon="flask-vial"
|
|
122
|
-
>
|
|
123
|
-
Run tests with GUI mode from the Test Explorer
|
|
124
|
-
</Card>
|
|
8
|
+
TestDriver tests are ordinary [Vitest](https://vitest.dev) files. You run them with Vitest, on your machine and in CI.
|
|
125
9
|
|
|
126
|
-
|
|
127
|
-
</Step>
|
|
128
|
-
</Steps>
|
|
10
|
+
Each test:
|
|
129
11
|
|
|
130
|
-
|
|
12
|
+
- Starts its own cloud sandbox.
|
|
13
|
+
- Runs its steps.
|
|
14
|
+
- Prints a link to a full report with a recording of the run.
|
|
131
15
|
|
|
132
|
-
|
|
16
|
+
## Before you begin
|
|
133
17
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
- ✅ Signed in
|
|
137
|
-
- ✅ MCP server configured
|
|
138
|
-
- ✅ Project initialized
|
|
18
|
+
- **A project with TestDriver installed**, with your API key in `.env` as `TD_API_KEY`. See [Set up a project](/quickstart-manual).
|
|
19
|
+
- **At least one test**, which you can [generate with AI](/generating-tests) or write by hand.
|
|
139
20
|
|
|
140
|
-
|
|
21
|
+
## Run tests from the terminal
|
|
141
22
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
The agent has access to tools like:
|
|
145
|
-
- `session_start` — Launch a sandbox with Chrome or other apps
|
|
146
|
-
- `find` / `click` / `type` — Interact with elements on screen
|
|
147
|
-
- `assert` — Verify conditions using AI vision
|
|
148
|
-
- `screenshot` — Capture the current screen state
|
|
149
|
-
|
|
150
|
-
## Configuring the Device
|
|
151
|
-
|
|
152
|
-
Provision methods are the starting point for most tests. They launch applications in your sandbox and prepare the environment for testing — a browser, a desktop app, a Chrome extension, or VS Code.
|
|
153
|
-
|
|
154
|
-
### Chrome Browser
|
|
155
|
-
|
|
156
|
-
The most common starting point for web testing. Launches Chrome browser and navigates to a URL.
|
|
157
|
-
|
|
158
|
-
```javascript
|
|
159
|
-
await testdriver.provision.chrome({
|
|
160
|
-
url: 'https://example.com',
|
|
161
|
-
});
|
|
162
|
-
```
|
|
23
|
+
Run every test in the project:
|
|
163
24
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
| Option | Type | Default | Description |
|
|
167
|
-
|--------|------|---------|-------------|
|
|
168
|
-
| `url` | string | `'http://testdriver-sandbox.vercel.app/'` | URL to navigate to |
|
|
169
|
-
| `maximized` | boolean | `true` | Start browser maximized |
|
|
170
|
-
| `guest` | boolean | `false` | Use guest mode (no profile) |
|
|
171
|
-
|
|
172
|
-
#### Example: Basic Web Test
|
|
173
|
-
|
|
174
|
-
```javascript
|
|
175
|
-
import { describe, expect, it } from "vitest";
|
|
176
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
177
|
-
|
|
178
|
-
describe("Login Flow", () => {
|
|
179
|
-
it("should log in successfully", async (context) => {
|
|
180
|
-
const testdriver = TestDriver(context);
|
|
181
|
-
|
|
182
|
-
await testdriver.provision.chrome({
|
|
183
|
-
url: 'https://myapp.com/login',
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
await testdriver.find("Email input").click();
|
|
187
|
-
await testdriver.type("user@example.com");
|
|
188
|
-
|
|
189
|
-
await testdriver.find("Password input").click();
|
|
190
|
-
await testdriver.type("password123");
|
|
191
|
-
|
|
192
|
-
await testdriver.find("Sign In button").click();
|
|
193
|
-
|
|
194
|
-
const result = await testdriver.assert("the dashboard is visible");
|
|
195
|
-
expect(result).toBeTruthy();
|
|
196
|
-
});
|
|
197
|
-
});
|
|
25
|
+
```bash
|
|
26
|
+
npx vitest run
|
|
198
27
|
```
|
|
199
28
|
|
|
200
|
-
|
|
201
|
-
`provision.chrome()` automatically starts Dashcam recording and waits for Chrome to be ready before returning.
|
|
202
|
-
</Info>
|
|
203
|
-
|
|
204
|
-
### Chrome Extensions
|
|
29
|
+
Vitest finds files whose names end in `.test` or `.spec` plus a JavaScript or TypeScript extension, such as `tests/login.test.mjs`.
|
|
205
30
|
|
|
206
|
-
|
|
31
|
+
To run part of your suite, pass files, folders, or a name filter:
|
|
207
32
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
```javascript
|
|
213
|
-
// First, get the extension onto the sandbox
|
|
214
|
-
await testdriver.exec(
|
|
215
|
-
'sh',
|
|
216
|
-
'git clone https://github.com/user/my-extension.git /tmp/my-extension',
|
|
217
|
-
60000
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
// Launch Chrome with the extension
|
|
221
|
-
await testdriver.provision.chromeExtension({
|
|
222
|
-
extensionPath: '/tmp/my-extension',
|
|
223
|
-
url: 'https://example.com'
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
#### Load from Chrome Web Store
|
|
33
|
+
```bash
|
|
34
|
+
# One file
|
|
35
|
+
npx vitest run tests/login.test.mjs
|
|
228
36
|
|
|
229
|
-
|
|
37
|
+
# Every test in a folder
|
|
38
|
+
npx vitest run tests/checkout/
|
|
230
39
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
extensionId: 'cjpalhdlnbpafiamejdnhcphjbkeiagm', // uBlock Origin
|
|
234
|
-
url: 'https://example.com'
|
|
235
|
-
});
|
|
40
|
+
# Only tests whose name matches
|
|
41
|
+
npx vitest run -t "login"
|
|
236
42
|
```
|
|
237
43
|
|
|
238
|
-
|
|
239
|
-
Find the extension ID in the Chrome Web Store URL. For example, `https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm` → ID is `cjpalhdlnbpafiamejdnhcphjbkeiagm`
|
|
240
|
-
</Tip>
|
|
44
|
+
Use `npx vitest` (without `run`) for watch mode. It reruns tests when you save a file.
|
|
241
45
|
|
|
242
|
-
|
|
46
|
+
## Run tests from VS Code
|
|
243
47
|
|
|
244
|
-
|
|
245
|
-
|--------|------|---------|-------------|
|
|
246
|
-
| `extensionPath` | string | - | Local path to unpacked extension directory |
|
|
247
|
-
| `extensionId` | string | - | Chrome Web Store extension ID |
|
|
248
|
-
| `url` | string | - | URL to navigate to after launch |
|
|
249
|
-
| `maximized` | boolean | `true` | Start browser maximized |
|
|
48
|
+
Install the [Vitest extension](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) to run tests from the **Testing** view. Click the run button next to a file or test. The result appears inline next to the code.
|
|
250
49
|
|
|
251
|
-
|
|
252
|
-
You must provide either `extensionPath` or `extensionId`, but not both.
|
|
253
|
-
</Warning>
|
|
254
|
-
|
|
255
|
-
#### Example: Testing a Chrome Extension
|
|
256
|
-
|
|
257
|
-
```javascript
|
|
258
|
-
import { describe, expect, it } from "vitest";
|
|
259
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
260
|
-
|
|
261
|
-
describe("Chrome Extension Test", () => {
|
|
262
|
-
it("should load and interact with extension", async (context) => {
|
|
263
|
-
const testdriver = TestDriver(context);
|
|
264
|
-
|
|
265
|
-
// Clone extension from GitHub
|
|
266
|
-
await testdriver.exec(
|
|
267
|
-
'sh',
|
|
268
|
-
'git clone https://github.com/user/my-extension.git /tmp/my-extension',
|
|
269
|
-
60000,
|
|
270
|
-
true
|
|
271
|
-
);
|
|
272
|
-
|
|
273
|
-
// Launch Chrome with extension loaded
|
|
274
|
-
await testdriver.provision.chromeExtension({
|
|
275
|
-
extensionPath: '/tmp/my-extension',
|
|
276
|
-
url: 'https://testdriver.ai'
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
// Click extensions puzzle icon
|
|
280
|
-
const extensionsButton = await testdriver.find("puzzle-shaped icon in Chrome toolbar");
|
|
281
|
-
await extensionsButton.click();
|
|
282
|
-
|
|
283
|
-
// Interact with your extension
|
|
284
|
-
const myExtension = await testdriver.find("My Extension in the dropdown");
|
|
285
|
-
await myExtension.click();
|
|
50
|
+
To watch the sandbox in a panel beside your code, install the [TestDriver extension](/quickstart-vscode) and use the `ide` preview mode below.
|
|
286
51
|
|
|
287
|
-
|
|
288
|
-
expect(result).toBeTruthy();
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
```
|
|
52
|
+
## Watch a test run
|
|
292
53
|
|
|
293
|
-
|
|
54
|
+
TestDriver shows each run live. Choose where with the `preview` option or the `TD_PREVIEW` environment variable:
|
|
294
55
|
|
|
295
|
-
|
|
56
|
+
| Mode | Where the run appears |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `"browser"` (default) | A live view in your web browser |
|
|
59
|
+
| `"ide"` | A panel in VS Code or Cursor (requires the TestDriver extension) |
|
|
60
|
+
| `"none"` | Nowhere, for CI and other headless runs |
|
|
296
61
|
|
|
297
62
|
```javascript
|
|
298
|
-
const
|
|
299
|
-
url: 'https://example.com/app.deb',
|
|
300
|
-
appName: 'MyApp', // Focus this app after install
|
|
301
|
-
launch: true, // Auto-launch after install
|
|
302
|
-
});
|
|
63
|
+
const testdriver = TestDriver(context, { preview: 'ide' });
|
|
303
64
|
```
|
|
304
65
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
| Option | Type | Default | Description |
|
|
308
|
-
|--------|------|---------|-------------|
|
|
309
|
-
| `url` | string | **required** | URL to download the installer from |
|
|
310
|
-
| `filename` | string | auto-detected | Filename to save as |
|
|
311
|
-
| `appName` | string | - | Application name to focus after install |
|
|
312
|
-
| `launch` | boolean | `true` | Launch the app after installation |
|
|
313
|
-
|
|
314
|
-
#### Supported File Types
|
|
315
|
-
|
|
316
|
-
| Extension | OS | Install Method |
|
|
317
|
-
|-----------|-----|----------------|
|
|
318
|
-
| `.deb` | Linux | `dpkg -i` + `apt-get install -f` |
|
|
319
|
-
| `.rpm` | Linux | `rpm -i` |
|
|
320
|
-
| `.AppImage` | Linux | `chmod +x` |
|
|
321
|
-
| `.sh` | Linux | `chmod +x` + execute |
|
|
322
|
-
| `.msi` | Windows | `msiexec /i /quiet` |
|
|
323
|
-
| `.exe` | Windows | Silent install (`/S`) |
|
|
324
|
-
| `.dmg` | macOS | Mount + copy to Applications |
|
|
325
|
-
| `.pkg` | macOS | `installer -pkg` |
|
|
66
|
+
## Open the test report
|
|
326
67
|
|
|
327
|
-
|
|
68
|
+
When a test finishes, TestDriver prints a link to its report:
|
|
328
69
|
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
332
|
-
|
|
333
|
-
describe("Desktop App Test", () => {
|
|
334
|
-
it("should install and launch app", async (context) => {
|
|
335
|
-
const testdriver = TestDriver(context);
|
|
336
|
-
|
|
337
|
-
// Download and install
|
|
338
|
-
const installerPath = await testdriver.provision.installer({
|
|
339
|
-
url: 'https://github.com/sharkdp/bat/releases/download/v0.24.0/bat_0.24.0_amd64.deb',
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// Verify installation
|
|
343
|
-
const output = await testdriver.exec('sh', 'bat --version', 5000);
|
|
344
|
-
expect(output).toContain('bat');
|
|
345
|
-
});
|
|
346
|
-
});
|
|
70
|
+
```text
|
|
71
|
+
TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/abc123
|
|
347
72
|
```
|
|
348
73
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
```javascript
|
|
352
|
-
import { describe, expect, it } from "vitest";
|
|
353
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
74
|
+
The report includes the run's recording, screenshots, and logs. Every past run is in the [TestDriver console](https://console.testdriver.ai).
|
|
354
75
|
|
|
355
|
-
|
|
356
|
-
it("should install on Windows", async (context) => {
|
|
357
|
-
const testdriver = TestDriver(context, {
|
|
358
|
-
os: 'windows'
|
|
359
|
-
});
|
|
76
|
+
## Run tests in parallel
|
|
360
77
|
|
|
361
|
-
|
|
362
|
-
const installerPath = await testdriver.provision.installer({
|
|
363
|
-
url: 'https://example.com/app.msi',
|
|
364
|
-
launch: false, // Don't auto-launch
|
|
365
|
-
});
|
|
78
|
+
Vitest runs test files in parallel, and each running test gets its own sandbox. Your plan sets how many sandboxes can run at once.
|
|
366
79
|
|
|
367
|
-
|
|
368
|
-
await testdriver.exec(
|
|
369
|
-
'pwsh',
|
|
370
|
-
`Start-Process msiexec.exe -ArgumentList "/i", "${installerPath}", "/qn" -Wait`,
|
|
371
|
-
120000
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
// Verify installation
|
|
375
|
-
const result = await testdriver.assert("application is installed");
|
|
376
|
-
expect(result).toBeTruthy();
|
|
377
|
-
});
|
|
378
|
-
});
|
|
379
|
-
```
|
|
80
|
+
At the limit, a new test waits for a free slot instead of failing. By default, the SDK retries every 10 seconds for up to 60 seconds.
|
|
380
81
|
|
|
381
|
-
|
|
82
|
+
Set `TD_CONCURRENCY_MAX_WAIT` (in seconds) to wait longer, or to `0` to fail immediately.
|
|
382
83
|
|
|
383
|
-
|
|
84
|
+
To cap how many test files run at once on your machine, limit Vitest's workers:
|
|
384
85
|
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
url: 'https://example.com/custom-script.sh',
|
|
388
|
-
launch: false,
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
// Run custom install commands
|
|
392
|
-
await testdriver.exec('sh', `chmod +x "${filePath}"`, 5000);
|
|
393
|
-
await testdriver.exec('sh', `"${filePath}" --custom-flag`, 60000);
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
### VS Code
|
|
397
|
-
|
|
398
|
-
Launch Visual Studio Code with optional workspace and extensions.
|
|
399
|
-
|
|
400
|
-
```javascript
|
|
401
|
-
await testdriver.provision.vscode({
|
|
402
|
-
workspace: '/home/testdriver/my-project',
|
|
403
|
-
extensions: ['ms-python.python', 'esbenp.prettier-vscode'],
|
|
404
|
-
});
|
|
86
|
+
```bash
|
|
87
|
+
npx vitest run --maxWorkers=5
|
|
405
88
|
```
|
|
406
89
|
|
|
407
|
-
|
|
90
|
+
For CI setups and parallel job matrices, see [Run tests in CI/CD](/ci-cd#concurrency-limits).
|
|
408
91
|
|
|
409
|
-
|
|
410
|
-
|--------|------|---------|-------------|
|
|
411
|
-
| `workspace` | string | - | Workspace folder to open |
|
|
412
|
-
| `extensions` | string[] | `[]` | Extensions to install (by ID) |
|
|
92
|
+
## Reuse a sandbox while you iterate
|
|
413
93
|
|
|
414
|
-
|
|
94
|
+
Each test normally starts a fresh sandbox, which takes time to boot, especially on Windows.
|
|
415
95
|
|
|
416
|
-
|
|
417
|
-
import { describe, expect, it } from "vitest";
|
|
418
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
96
|
+
While you work on a long flow, keep the sandbox running between runs and reconnect to it. Then you only rerun the steps you're changing.
|
|
419
97
|
|
|
420
|
-
|
|
421
|
-
it("should open workspace with extensions", async (context) => {
|
|
422
|
-
const testdriver = TestDriver(context);
|
|
98
|
+
1. Run the steps that already work with a longer `keepAlive`. It keeps the sandbox running for that many milliseconds after the test ends (60 seconds by default, up to 30 minutes):
|
|
423
99
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
// Launch VS Code
|
|
428
|
-
await testdriver.provision.vscode({
|
|
429
|
-
workspace: '/tmp/test-project',
|
|
430
|
-
extensions: ['ms-python.python'],
|
|
100
|
+
```javascript tests/setup-cart.test.mjs
|
|
101
|
+
const testdriver = TestDriver(context, {
|
|
102
|
+
keepAlive: 10 * 60 * 1000, // 10 minutes
|
|
431
103
|
});
|
|
432
104
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
// Open the Python file
|
|
438
|
-
await testdriver.find("test.py in the explorer").click();
|
|
439
|
-
});
|
|
440
|
-
});
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### Choosing the Right Provision Method
|
|
444
|
-
|
|
445
|
-
| Use Case | Method |
|
|
446
|
-
|----------|--------|
|
|
447
|
-
| Testing a website | `provision.chrome` |
|
|
448
|
-
| Testing a Chrome extension | `provision.chromeExtension` |
|
|
449
|
-
| Testing a desktop app (needs installation) | `provision.installer` |
|
|
450
|
-
| Testing VS Code or VS Code extensions | `provision.vscode` |
|
|
451
|
-
|
|
452
|
-
<Tip>
|
|
453
|
-
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.
|
|
454
|
-
</Tip>
|
|
455
|
-
|
|
456
|
-
## Configuring the Machine
|
|
457
|
-
|
|
458
|
-
TestDriver provisions a fresh cloud VM for every test by default. This section covers how to configure Linux and Windows machines, reduce startup time by keeping machines alive between runs, use provision scripts for repeatable setup, and install custom software on the fly.
|
|
459
|
-
|
|
460
|
-
### Linux Machines
|
|
461
|
-
|
|
462
|
-
Linux is the default operating system. No extra configuration is required.
|
|
463
|
-
|
|
464
|
-
```javascript
|
|
465
|
-
import { describe, expect, it } from "vitest";
|
|
466
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
467
|
-
|
|
468
|
-
describe("My Test", () => {
|
|
469
|
-
it("runs on Linux", async (context) => {
|
|
470
|
-
const testdriver = TestDriver(context);
|
|
471
|
-
|
|
472
|
-
await testdriver.provision.chrome({ url: "https://example.com" });
|
|
473
|
-
|
|
474
|
-
const result = await testdriver.assert("the page loaded successfully");
|
|
475
|
-
expect(result).toBeTruthy();
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
#### Common Linux Options
|
|
481
|
-
|
|
482
|
-
| Option | Type | Default | Description |
|
|
483
|
-
|--------|------|---------|-------------|
|
|
484
|
-
| `os` | string | `"linux"` | Operating system |
|
|
485
|
-
| `resolution` | string | `"1366x768"` | Screen resolution (Enterprise only) |
|
|
486
|
-
| `e2bTemplateId` | string | — | Custom E2B template ID (see [Self-Hosted](/self-hosted)) |
|
|
487
|
-
| `keepAlive` | number | `60000` | Ms to keep VM alive after disconnect |
|
|
488
|
-
| `reconnect` | boolean | `false` | Reconnect to last used sandbox |
|
|
489
|
-
|
|
490
|
-
```javascript
|
|
491
|
-
const testdriver = TestDriver(context, {
|
|
492
|
-
os: "linux",
|
|
493
|
-
resolution: "1920x1080",
|
|
494
|
-
keepAlive: 5 * 60 * 1000, // keep alive 5 minutes
|
|
495
|
-
});
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
### Windows Machines
|
|
499
|
-
|
|
500
|
-
Set `os: "windows"` to provision a Windows VM instead. Everything else works the same way.
|
|
501
|
-
|
|
502
|
-
```javascript
|
|
503
|
-
const testdriver = TestDriver(context, {
|
|
504
|
-
os: "windows",
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
await testdriver.provision.chrome({ url: "https://example.com" });
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
Windows sandboxes use EC2 instances and take longer to boot than Linux (E2B) sandboxes — typically 1–3 minutes for a cold start. See [Keeping Machines Alive](#keeping-machines-alive-between-runs) below to avoid this cost on repeated runs.
|
|
511
|
-
|
|
512
|
-
#### Common Windows Options
|
|
513
|
-
|
|
514
|
-
| Option | Type | Default | Description |
|
|
515
|
-
|--------|------|---------|-------------|
|
|
516
|
-
| `os` | string | — | Set to `"windows"` |
|
|
517
|
-
| `resolution` | string | `"1366x768"` | Screen resolution (Enterprise only) |
|
|
518
|
-
| `sandboxAmi` | string | — | Custom AMI ID (self-hosted) |
|
|
519
|
-
| `sandboxInstance` | string | — | EC2 instance type (self-hosted) |
|
|
520
|
-
| `keepAlive` | number | `60000` | Ms to keep VM alive after disconnect |
|
|
521
|
-
| `reconnect` | boolean | `false` | Reconnect to last used sandbox |
|
|
522
|
-
|
|
523
|
-
```javascript
|
|
524
|
-
const testdriver = TestDriver(context, {
|
|
525
|
-
os: "windows",
|
|
526
|
-
resolution: "1920x1080",
|
|
527
|
-
keepAlive: 10 * 60 * 1000, // keep alive 10 minutes
|
|
528
|
-
});
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
### Keeping Machines Alive Between Runs
|
|
532
|
-
|
|
533
|
-
Windows (and Linux) cold starts can be expensive if you're iterating quickly. Use `keepAlive` + `reconnect` to reuse the same VM across multiple test runs.
|
|
534
|
-
|
|
535
|
-
#### How it works
|
|
536
|
-
|
|
537
|
-
Every time the SDK successfully connects to a sandbox, it records the sandbox id in `.testdriver/last-sandbox` inside your project directory. The next test that opts in with `reconnect: true` reads that file and reattaches automatically — no manual id tracking required.
|
|
538
|
-
|
|
539
|
-
Provision calls (`testdriver.provision.chrome(...)`, `vscode(...)`, etc.) are **skipped** when reconnecting, because the application is already running inside the sandbox from the previous run.
|
|
540
|
-
|
|
541
|
-
<Note>
|
|
542
|
-
`.testdriver/last-sandbox` is already covered by the default TestDriver `.gitignore`. Don't commit it.
|
|
543
|
-
</Note>
|
|
544
|
-
|
|
545
|
-
#### Step 1 — Start the machine with a long `keepAlive`
|
|
546
|
-
|
|
547
|
-
```javascript
|
|
548
|
-
// first.test.mjs
|
|
549
|
-
const testdriver = TestDriver(context, {
|
|
550
|
-
os: "windows",
|
|
551
|
-
keepAlive: 30 * 60 * 1000, // keep alive 30 minutes after this test ends
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
await testdriver.provision.chrome({ url: "https://example.com" });
|
|
555
|
-
// ... your test steps
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
When this test finishes, the sandbox stays running for 30 minutes instead of being terminated immediately.
|
|
559
|
-
|
|
560
|
-
#### Step 2 — Reattach automatically with `reconnect: true`
|
|
561
|
-
|
|
562
|
-
```javascript
|
|
563
|
-
// second.test.mjs
|
|
564
|
-
const testdriver = TestDriver(context, {
|
|
565
|
-
os: "windows",
|
|
566
|
-
reconnect: true, // ← reads .testdriver/last-sandbox
|
|
567
|
-
keepAlive: 30 * 60 * 1000,
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
// No provision call — Chrome is already open from the previous run.
|
|
571
|
-
await testdriver.find("Sign In button").click();
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
#### Step 2 (alternative) — Reattach to an explicit id
|
|
575
|
-
|
|
576
|
-
If you need to pin to a specific sandbox (CI matrix, multiple chains in parallel, etc.) pass the id directly:
|
|
577
|
-
|
|
578
|
-
```javascript
|
|
579
|
-
await testdriver.connect({ sandboxId: "sandbox-abc123" });
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
When reattaching to a sandbox:
|
|
583
|
-
- You reuse a specific running machine directly
|
|
584
|
-
- You continue from the app state created in the earlier run
|
|
585
|
-
- You must run within the previous test's `keepAlive` window
|
|
586
|
-
|
|
587
|
-
<Tip>
|
|
588
|
-
Use `testdriver.getLastSandboxId()` to read the recorded sandbox id (and optional metadata) for scripting purposes.
|
|
589
|
-
</Tip>
|
|
590
|
-
|
|
591
|
-
#### Chaining describe blocks within one test file
|
|
105
|
+
await testdriver.provision.chrome({ url: 'https://testdriver-sandbox.vercel.app/login' });
|
|
106
|
+
// ...steps that log in and fill the cart
|
|
107
|
+
```
|
|
592
108
|
|
|
593
|
-
|
|
109
|
+
2. In the file you're working on, set `reconnect: true`. TestDriver reattaches to the last sandbox it used, recorded in `.testdriver/last-sandbox`. It skips `provision` calls because the app is already open:
|
|
594
110
|
|
|
595
|
-
```javascript
|
|
596
|
-
import { describe, expect, it } from "vitest";
|
|
597
|
-
import { TestDriver } from "testdriverai/vitest/hooks";
|
|
598
|
-
|
|
599
|
-
const KEEP_ALIVE_MS = 5 * 60 * 1000;
|
|
600
|
-
|
|
601
|
-
describe("step 1 — log in", () => {
|
|
602
|
-
it("signs in and lands on the dashboard", async (context) => {
|
|
603
|
-
const testdriver = TestDriver(context, { keepAlive: KEEP_ALIVE_MS });
|
|
604
|
-
await testdriver.provision.chrome({ url: "https://example.com/login" });
|
|
605
|
-
await testdriver.find("username input").click();
|
|
606
|
-
await testdriver.type("standard_user");
|
|
607
|
-
await testdriver.pressKeys(["tab"]);
|
|
608
|
-
await testdriver.type("secret_sauce", { secret: true });
|
|
609
|
-
await testdriver.pressKeys(["enter"]);
|
|
610
|
-
expect(await testdriver.assert("the dashboard is visible")).toBeTruthy();
|
|
611
|
-
});
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
describe("step 2 — add to cart", () => {
|
|
615
|
-
it("reuses the logged-in sandbox", async (context) => {
|
|
111
|
+
```javascript tests/checkout.test.mjs
|
|
616
112
|
const testdriver = TestDriver(context, {
|
|
617
|
-
reconnect: true,
|
|
618
|
-
keepAlive:
|
|
113
|
+
reconnect: true,
|
|
114
|
+
keepAlive: 10 * 60 * 1000,
|
|
619
115
|
});
|
|
620
|
-
await testdriver.find("Add to cart").click();
|
|
621
|
-
await testdriver.find("cart icon").click();
|
|
622
|
-
expect(await testdriver.assert("the cart has an item")).toBeTruthy();
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
describe("step 3 — check out", () => {
|
|
627
|
-
it("continues from the cart state", async (context) => {
|
|
628
|
-
const testdriver = TestDriver(context, { reconnect: true, keepAlive: 30_000 });
|
|
629
|
-
await testdriver.find("Checkout").click();
|
|
630
|
-
expect(await testdriver.assert("the checkout form is visible")).toBeTruthy();
|
|
631
|
-
});
|
|
632
|
-
});
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
A runnable copy of this pattern lives at [`examples/reconnect-sequential.test.mjs`](https://github.com/testdriverai/mono/blob/main/sdk/examples/reconnect-sequential.test.mjs).
|
|
636
116
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
#### How `keepAlive` works
|
|
642
|
-
|
|
643
|
-
`keepAlive` is a duration in milliseconds. After the SDK disconnects, the server keeps the VM running for that long before terminating it. The default is `60000` (1 minute). Note: `keepAlive: 0` currently falls back to the default disconnect grace period rather than terminating immediately, so use a positive duration when you want to control the grace window explicitly.
|
|
644
|
-
|
|
645
|
-
```javascript
|
|
646
|
-
const testdriver = TestDriver(context, {
|
|
647
|
-
keepAlive: 0, // currently uses the default 1 minute grace period
|
|
648
|
-
// keepAlive: 60000, // default — 1 minute
|
|
649
|
-
// keepAlive: 600000, // 10 minutes
|
|
650
|
-
// keepAlive: 3600000, // 1 hour
|
|
651
|
-
});
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
<Warning>
|
|
655
|
-
Machines kept alive beyond your test session continue to consume credits. Always set a `keepAlive` value appropriate for your workflow.
|
|
656
|
-
</Warning>
|
|
657
|
-
|
|
658
|
-
### Using Provision Scripts
|
|
659
|
-
|
|
660
|
-
Provision scripts let you run arbitrary setup steps before your test starts — downloading fixtures, seeding a database, configuring environment variables, and more. Use `testdriver.exec()` to run shell or PowerShell commands directly in the sandbox.
|
|
661
|
-
|
|
662
|
-
<Card
|
|
663
|
-
title="exec() Reference"
|
|
664
|
-
icon="terminal"
|
|
665
|
-
href="/exec"
|
|
666
|
-
>
|
|
667
|
-
Full reference for running shell and PowerShell commands in the sandbox.
|
|
668
|
-
</Card>
|
|
669
|
-
|
|
670
|
-
#### Linux setup script
|
|
671
|
-
|
|
672
|
-
```javascript
|
|
673
|
-
await testdriver.provision.chrome({ url: "https://myapp.com" });
|
|
674
|
-
|
|
675
|
-
// Run a setup script from your repo
|
|
676
|
-
await testdriver.exec("sh", `
|
|
677
|
-
curl -s https://myapp.com/api/reset-test-db -X POST
|
|
678
|
-
echo "Test DB reset"
|
|
679
|
-
`, 30000);
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
#### Windows setup script (PowerShell)
|
|
683
|
-
|
|
684
|
-
```javascript
|
|
685
|
-
await testdriver.provision.chrome({ url: "https://myapp.com" });
|
|
686
|
-
|
|
687
|
-
await testdriver.exec("pwsh", `
|
|
688
|
-
$env:API_URL = "https://staging.myapp.com"
|
|
689
|
-
Write-Host "Environment configured"
|
|
690
|
-
`, 15000);
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
#### Clone a repo and run a script
|
|
694
|
-
|
|
695
|
-
```javascript
|
|
696
|
-
await testdriver.exec("sh", `
|
|
697
|
-
git clone https://github.com/myorg/test-fixtures.git /tmp/fixtures
|
|
698
|
-
bash /tmp/fixtures/seed.sh
|
|
699
|
-
`, 120000);
|
|
700
|
-
```
|
|
701
|
-
|
|
702
|
-
### Installing Custom Software
|
|
703
|
-
|
|
704
|
-
You can install software at the start of a test using `exec()`. This works for any package available via `apt`, `brew`, `choco`, `winget`, npm, pip, or direct download.
|
|
705
|
-
|
|
706
|
-
#### Linux — apt packages
|
|
707
|
-
|
|
708
|
-
```javascript
|
|
709
|
-
await testdriver.exec("sh", `
|
|
710
|
-
sudo apt-get update -qq
|
|
711
|
-
sudo apt-get install -y ffmpeg imagemagick
|
|
712
|
-
`, 120000);
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
#### Linux — Node.js tools
|
|
716
|
-
|
|
717
|
-
```javascript
|
|
718
|
-
await testdriver.exec("sh", "npm install -g @playwright/test", 60000);
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
#### Windows — winget
|
|
722
|
-
|
|
723
|
-
```javascript
|
|
724
|
-
await testdriver.exec("pwsh", `
|
|
725
|
-
winget install --id=7zip.7zip -e --silent
|
|
726
|
-
`, 120000);
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
#### Windows — Chocolatey
|
|
730
|
-
|
|
731
|
-
```javascript
|
|
732
|
-
await testdriver.exec("pwsh", `
|
|
733
|
-
choco install googlechrome --yes --no-progress
|
|
734
|
-
`, 180000);
|
|
735
|
-
```
|
|
736
|
-
|
|
737
|
-
#### Download and run an installer
|
|
738
|
-
|
|
739
|
-
```javascript
|
|
740
|
-
// Linux
|
|
741
|
-
await testdriver.exec("sh", `
|
|
742
|
-
curl -L https://example.com/installer.sh -o /tmp/installer.sh
|
|
743
|
-
chmod +x /tmp/installer.sh
|
|
744
|
-
/tmp/installer.sh --silent
|
|
745
|
-
`, 300000);
|
|
746
|
-
|
|
747
|
-
// Windows
|
|
748
|
-
await testdriver.exec("pwsh", `
|
|
749
|
-
Invoke-WebRequest -Uri "https://example.com/installer.exe" -OutFile "$env:TEMP\\installer.exe"
|
|
750
|
-
Start-Process "$env:TEMP\\installer.exe" -ArgumentList "/S" -Wait
|
|
751
|
-
`, 300000);
|
|
752
|
-
```
|
|
753
|
-
|
|
754
|
-
<Note>
|
|
755
|
-
Installing software at test start adds to your test duration. For software you use in every test, consider preloading it into a custom VM image via the Enterprise self-hosted plan.
|
|
756
|
-
</Note>
|
|
757
|
-
|
|
758
|
-
#### Want Software Pre-Installed on Every Machine?
|
|
759
|
-
|
|
760
|
-
Installing packages at runtime works well for occasional or lightweight dependencies. But if you're installing the same 5-minute setup on every test run, you're wasting time and credits.
|
|
761
|
-
|
|
762
|
-
With the **Self-Hosted Enterprise plan** you get access to our golden VM base image and Packer scripts, so you can bake your applications, dependencies, and configuration directly into a custom AMI. Tests spin up with everything already installed — zero setup time.
|
|
763
|
-
|
|
764
|
-
<Card
|
|
765
|
-
title="Self-Hosted Enterprise"
|
|
766
|
-
icon="server"
|
|
767
|
-
href="/self-hosted"
|
|
768
|
-
>
|
|
769
|
-
Preload software, configure custom hardware, and run unlimited tests with a flat license fee. Our team assists with deployment and setup.
|
|
770
|
-
</Card>
|
|
771
|
-
|
|
772
|
-
## Running Tests
|
|
773
|
-
|
|
774
|
-
After creating tests with the TestDriver agent, you can re-run them without starting a new MCP session. Tests are saved as standard Vitest files that run independently — the same way on your machine and in CI.
|
|
775
|
-
|
|
776
|
-
### Running from Terminal
|
|
777
|
-
|
|
778
|
-
TestDriver works with [Vitest's](https://vitest.dev) test runner. Use Vitest to run your tests from the command line to see full output:
|
|
779
|
-
|
|
780
|
-
```bash
|
|
781
|
-
# Run all tests
|
|
782
|
-
vitest run
|
|
783
|
-
|
|
784
|
-
# Run a specific test file
|
|
785
|
-
vitest run tests/login.test.mjs
|
|
786
|
-
|
|
787
|
-
# Run in watch mode (re-runs on file changes)
|
|
788
|
-
vitest
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
<Info>
|
|
792
|
-
Install Vitest globally for best results: `npm install vitest -g`
|
|
793
|
-
</Info>
|
|
794
|
-
|
|
795
|
-
Vitest automatically discovers files matching patterns like `*.test.js`, `*.test.mjs`, or `*.spec.js`.
|
|
796
|
-
|
|
797
|
-
#### Common CLI options
|
|
798
|
-
|
|
799
|
-
```bash
|
|
800
|
-
# Run multiple specific files
|
|
801
|
-
vitest run login.test.mjs checkout.test.mjs
|
|
802
|
-
|
|
803
|
-
# Run every test in a folder
|
|
804
|
-
vitest run tests/e2e/
|
|
805
|
-
|
|
806
|
-
# Filter tests by name (supports regex)
|
|
807
|
-
vitest run --grep "login"
|
|
808
|
-
|
|
809
|
-
# Generate a coverage report
|
|
810
|
-
vitest run --coverage
|
|
811
|
-
```
|
|
812
|
-
|
|
813
|
-
<Info>
|
|
814
|
-
Coverage requires the `@vitest/coverage-v8` package. Install it with `npm install -D @vitest/coverage-v8`.
|
|
815
|
-
</Info>
|
|
816
|
-
|
|
817
|
-
#### Vitest UI
|
|
818
|
-
|
|
819
|
-
For interactive debugging, launch the web-based UI (starts in watch mode):
|
|
820
|
-
|
|
821
|
-
```bash
|
|
822
|
-
vitest --ui
|
|
823
|
-
```
|
|
824
|
-
|
|
825
|
-
Open http://localhost:51204 to browse your test tree, see pass/fail states and timing, view inline console output, and re-run individual tests.
|
|
826
|
-
|
|
827
|
-
<Tip>
|
|
828
|
-
Combine with `--open` to open the UI in your browser automatically: `vitest --ui --open`
|
|
829
|
-
</Tip>
|
|
830
|
-
|
|
831
|
-
### Running from VS Code (GUI Mode)
|
|
832
|
-
|
|
833
|
-
For a visual testing experience, use the **Vitest extension**:
|
|
834
|
-
|
|
835
|
-
<Steps>
|
|
836
|
-
<Step title="Open Test Explorer">
|
|
837
|
-
Click the **beaker icon** in the VS Code sidebar to open the Test Explorer. This shows all your test files and test cases.
|
|
838
|
-
</Step>
|
|
839
|
-
|
|
840
|
-
<Step title="Run Tests">
|
|
841
|
-
Click the **play button** next to any test file or individual test to run it. You can also:
|
|
842
|
-
- Run all tests with the "Run All" button
|
|
843
|
-
- Debug tests with the "Debug" button
|
|
844
|
-
</Step>
|
|
845
|
-
|
|
846
|
-
<Step title="View Results">
|
|
847
|
-
Test results appear inline:
|
|
848
|
-
- ✅ Green checkmark for passing tests
|
|
849
|
-
- ❌ Red X for failing tests
|
|
850
|
-
- Click on a failing test to see error details
|
|
851
|
-
</Step>
|
|
852
|
-
</Steps>
|
|
853
|
-
|
|
854
|
-
<Warning>
|
|
855
|
-
VS Code's Test Explorer only shows output for **failing tests**. To see output from passing tests (including screenshots and console logs), run tests from the terminal instead.
|
|
856
|
-
</Warning>
|
|
857
|
-
|
|
858
|
-
### Test Configuration
|
|
859
|
-
|
|
860
|
-
#### Timeouts
|
|
861
|
-
|
|
862
|
-
TestDriver tests require longer timeouts than typical unit tests. Your `vitest.config.mjs` should have:
|
|
863
|
-
|
|
864
|
-
```javascript vitest.config.mjs
|
|
865
|
-
import { defineConfig } from "vitest/config";
|
|
866
|
-
|
|
867
|
-
export default defineConfig({
|
|
868
|
-
test: {
|
|
869
|
-
testTimeout: 900000, // 15 minutes
|
|
870
|
-
hookTimeout: 900000, // 15 minutes for setup/teardown
|
|
871
|
-
},
|
|
872
|
-
});
|
|
873
|
-
```
|
|
874
|
-
|
|
875
|
-
#### Environment Variables
|
|
876
|
-
|
|
877
|
-
Tests use the `TD_API_KEY` environment variable. Set it in your `.env` file:
|
|
878
|
-
|
|
879
|
-
```env .env
|
|
880
|
-
TD_API_KEY=your-api-key-here
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
Or pass it when running tests:
|
|
884
|
-
|
|
885
|
-
```bash
|
|
886
|
-
TD_API_KEY=your-key vitest run
|
|
887
|
-
```
|
|
888
|
-
|
|
889
|
-
### Parallel Execution
|
|
890
|
-
|
|
891
|
-
TestDriver runs each test in its own cloud sandbox, enabling true parallel execution. Run your entire test suite in minutes instead of hours.
|
|
892
|
-
|
|
893
|
-
Your TestDriver plan includes a set number of **license slots** that determine how many tests can run simultaneously. Each running test occupies one slot — when the test completes and the sandbox is destroyed, the slot is immediately freed for the next test.
|
|
894
|
-
|
|
895
|
-
Set `maxConcurrency` in your Vitest config to match your license slot limit:
|
|
896
|
-
|
|
897
|
-
```javascript vitest.config.mjs
|
|
898
|
-
import { defineConfig } from 'vitest/config';
|
|
899
|
-
import TestDriver from 'testdriverai/vitest';
|
|
900
|
-
|
|
901
|
-
export default defineConfig({
|
|
902
|
-
test: {
|
|
903
|
-
testTimeout: 900000,
|
|
904
|
-
hookTimeout: 900000,
|
|
905
|
-
maxConcurrency: 5, // Match your license slot limit
|
|
906
|
-
reporters: ['default', TestDriver()],
|
|
907
|
-
setupFiles: ['testdriverai/vitest/setup'],
|
|
908
|
-
},
|
|
909
|
-
});
|
|
910
|
-
```
|
|
911
|
-
|
|
912
|
-
You can also cap concurrency from the CLI:
|
|
117
|
+
// No provision call: Chrome is still open from the previous run
|
|
118
|
+
const checkoutButton = await testdriver.find('Checkout button');
|
|
119
|
+
await checkoutButton.click();
|
|
120
|
+
```
|
|
913
121
|
|
|
914
|
-
|
|
915
|
-
vitest run --maxConcurrency=5
|
|
916
|
-
```
|
|
122
|
+
Run the second file within the first file's `keepAlive` window. Reconnecting fails if the sandbox has already shut down.
|
|
917
123
|
|
|
918
124
|
<Warning>
|
|
919
|
-
|
|
125
|
+
A kept-alive sandbox uses your plan's testing minutes until it shuts down. Use a `keepAlive` no longer than you need.
|
|
920
126
|
</Warning>
|
|
921
127
|
|
|
922
|
-
|
|
923
|
-
|------------|--------------------|--------------------|---------------------|
|
|
924
|
-
| 10 tests @ 2min each | 20 min | 4 min | 2 min |
|
|
925
|
-
| 50 tests @ 2min each | 100 min | 20 min | 10 min |
|
|
926
|
-
| 100 tests @ 2min each | 200 min | 40 min | 20 min |
|
|
927
|
-
|
|
928
|
-
<Info>
|
|
929
|
-
View your available slots at [console.testdriver.ai](https://console.testdriver.ai). Upgrade anytime to increase parallelization.
|
|
930
|
-
</Info>
|
|
128
|
+
To connect to a specific sandbox instead, or for more sandbox options, see [Customize devices](/customizing-devices#keep-a-sandbox-alive).
|
|
931
129
|
|
|
932
|
-
|
|
130
|
+
## Fix a failing test
|
|
933
131
|
|
|
934
|
-
|
|
132
|
+
When the app changes and a test no longer matches it, ask the TestDriver agent to update the test. It reruns the flow in a sandbox and sees the current screen:
|
|
935
133
|
|
|
936
|
-
```
|
|
937
|
-
|
|
134
|
+
```text
|
|
135
|
+
The login test is failing because the form layout changed. Update tests/login.test.mjs to match the new design.
|
|
938
136
|
```
|
|
939
137
|
|
|
940
|
-
|
|
941
|
-
- Video recording of the test
|
|
942
|
-
- Screenshots at each step
|
|
943
|
-
- Network logs and performance metrics
|
|
944
|
-
- Console output and errors
|
|
138
|
+
For small changes, such as an updated `find()` description or assertion, edit the test file directly.
|
|
945
139
|
|
|
946
|
-
|
|
947
|
-
title="View Test Reports"
|
|
948
|
-
icon="chart-line"
|
|
949
|
-
href="https://console.testdriver.ai"
|
|
950
|
-
>
|
|
951
|
-
Access all your test runs and recordings in the TestDriver console
|
|
952
|
-
</Card>
|
|
140
|
+
To dig into what went wrong in a run, see [Debug with screenshots](/debugging-with-screenshots).
|
|
953
141
|
|
|
954
|
-
|
|
142
|
+
## Troubleshooting
|
|
955
143
|
|
|
956
|
-
|
|
144
|
+
<AccordionGroup>
|
|
145
|
+
<Accordion title="Tests fail with a Vitest timeout">
|
|
957
146
|
|
|
958
|
-
|
|
147
|
+
Tests that drive a real machine take longer than Vitest's 5-second default. Set `testTimeout` and `hookTimeout` in `vitest.config.mjs`.
|
|
959
148
|
|
|
960
|
-
|
|
149
|
+
`npx testdriverai init` sets both to 5 minutes:
|
|
961
150
|
|
|
962
|
-
```
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
```
|
|
151
|
+
```javascript vitest.config.mjs
|
|
152
|
+
import { defineConfig } from 'vitest/config';
|
|
153
|
+
import TestDriver from 'testdriverai/vitest';
|
|
966
154
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
155
|
+
export default defineConfig({
|
|
156
|
+
test: {
|
|
157
|
+
testTimeout: 300000,
|
|
158
|
+
hookTimeout: 300000,
|
|
159
|
+
reporters: ['default', TestDriver()],
|
|
160
|
+
setupFiles: ['testdriverai/vitest/setup'],
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
```
|
|
972
164
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
- You need to see what's currently on screen
|
|
976
|
-
- The failure reason isn't obvious from the error message
|
|
165
|
+
</Accordion>
|
|
166
|
+
<Accordion title="TestDriver can't find my API key">
|
|
977
167
|
|
|
978
|
-
|
|
168
|
+
The SDK reads `TD_API_KEY` from the environment. It loads `.env` in your project root automatically.
|
|
979
169
|
|
|
980
|
-
|
|
170
|
+
Check that `.env` contains `TD_API_KEY=...`, or set the variable for one run:
|
|
981
171
|
|
|
982
|
-
```
|
|
983
|
-
|
|
984
|
-
|
|
172
|
+
```bash
|
|
173
|
+
TD_API_KEY=your_api_key npx vitest run
|
|
174
|
+
```
|
|
985
175
|
|
|
986
|
-
|
|
987
|
-
|
|
176
|
+
</Accordion>
|
|
177
|
+
<Accordion title="Tests wait a long time before starting">
|
|
988
178
|
|
|
989
|
-
|
|
990
|
-
const result = await testdriver.assert("order confirmation shows order ID");
|
|
991
|
-
```
|
|
179
|
+
You're probably at your plan's sandbox limit, and tests are waiting for a free slot.
|
|
992
180
|
|
|
993
|
-
|
|
994
|
-
- Updating text strings
|
|
995
|
-
- Adjusting timeouts
|
|
996
|
-
- Fixing typos
|
|
181
|
+
Run fewer files at once with `--maxWorkers`, or check your plan in the [TestDriver console](https://console.testdriver.ai).
|
|
997
182
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
</Tip>
|
|
183
|
+
</Accordion>
|
|
184
|
+
</AccordionGroup>
|
|
1001
185
|
|
|
1002
|
-
## Next
|
|
186
|
+
## Next steps
|
|
1003
187
|
|
|
1004
|
-
<
|
|
1005
|
-
title="
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
>
|
|
1009
|
-
|
|
1010
|
-
</Card>
|
|
188
|
+
<CardGroup cols={2}>
|
|
189
|
+
<Card title="Make assertions" icon="circle-check" href="/making-assertions">
|
|
190
|
+
Write checks that catch the regressions you care about.
|
|
191
|
+
</Card>
|
|
192
|
+
<Card title="Debug with screenshots" icon="bug" href="/debugging-with-screenshots">
|
|
193
|
+
See what the sandbox showed at each step of a run.
|
|
194
|
+
</Card>
|
|
195
|
+
<Card title="Run in CI/CD" icon="code-branch" href="/ci-cd">
|
|
196
|
+
Run your tests on every push and pull request.
|
|
197
|
+
</Card>
|
|
198
|
+
<Card title="Launch apps" icon="rocket" href="/provision">
|
|
199
|
+
Start Chrome, extensions, VS Code, or desktop apps in the sandbox.
|
|
200
|
+
</Card>
|
|
201
|
+
</CardGroup>
|