@testdriverai/agent 7.11.239-test → 7.11.241-canary

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.
Files changed (52) hide show
  1. package/ai/skills/testdriver-agent/SKILL.md +174 -91
  2. package/ai/skills/testdriver-assert/SKILL.md +73 -269
  3. package/ai/skills/testdriver-aws-setup/SKILL.md +194 -312
  4. package/ai/skills/testdriver-bring-your-own-machine/SKILL.md +137 -204
  5. package/ai/skills/testdriver-cache/SKILL.md +142 -149
  6. package/ai/skills/testdriver-caching/SKILL.md +97 -87
  7. package/ai/skills/testdriver-captcha/SKILL.md +126 -111
  8. package/ai/skills/testdriver-ci-cd/SKILL.md +153 -542
  9. package/ai/skills/testdriver-click/SKILL.md +74 -229
  10. package/ai/skills/testdriver-client/SKILL.md +175 -229
  11. package/ai/skills/testdriver-customizing-devices/SKILL.md +72 -250
  12. package/ai/skills/testdriver-dashcam/SKILL.md +71 -404
  13. package/ai/skills/testdriver-debugging-with-screenshots/SKILL.md +103 -369
  14. package/ai/skills/testdriver-double-click/SKILL.md +46 -67
  15. package/ai/skills/testdriver-errors/SKILL.md +102 -176
  16. package/ai/skills/testdriver-events/SKILL.md +170 -327
  17. package/ai/skills/testdriver-exec/SKILL.md +92 -256
  18. package/ai/skills/testdriver-extract/SKILL.md +69 -170
  19. package/ai/skills/testdriver-find/SKILL.md +140 -736
  20. package/ai/skills/testdriver-focus-application/SKILL.md +69 -246
  21. package/ai/skills/testdriver-generating-tests/SKILL.md +102 -136
  22. package/ai/skills/testdriver-hosted/SKILL.md +79 -143
  23. package/ai/skills/testdriver-hover/SKILL.md +62 -235
  24. package/ai/skills/testdriver-locating-elements/SKILL.md +71 -366
  25. package/ai/skills/testdriver-making-assertions/SKILL.md +114 -72
  26. package/ai/skills/testdriver-mcp-setup/SKILL.md +79 -62
  27. package/ai/skills/testdriver-mouse-down/SKILL.md +46 -124
  28. package/ai/skills/testdriver-mouse-up/SKILL.md +45 -128
  29. package/ai/skills/testdriver-options/SKILL.md +73 -46
  30. package/ai/skills/testdriver-parse/SKILL.md +95 -184
  31. package/ai/skills/testdriver-performing-actions/SKILL.md +101 -91
  32. package/ai/skills/testdriver-press-keys/SKILL.md +59 -299
  33. package/ai/skills/testdriver-provision/SKILL.md +135 -179
  34. package/ai/skills/testdriver-quickstart/SKILL.md +24 -8
  35. package/ai/skills/testdriver-quickstart-claude/SKILL.md +84 -0
  36. package/ai/skills/testdriver-quickstart-github/SKILL.md +62 -32
  37. package/ai/skills/testdriver-quickstart-manual/SKILL.md +59 -32
  38. package/ai/skills/testdriver-quickstart-vscode/SKILL.md +96 -0
  39. package/ai/skills/testdriver-redraw/SKILL.md +100 -164
  40. package/ai/skills/testdriver-reusable-code/SKILL.md +95 -199
  41. package/ai/skills/testdriver-right-click/SKILL.md +45 -88
  42. package/ai/skills/testdriver-screenshot/SKILL.md +47 -201
  43. package/ai/skills/testdriver-screenshots/SKILL.md +86 -136
  44. package/ai/skills/testdriver-scroll/SKILL.md +71 -154
  45. package/ai/skills/testdriver-secrets/SKILL.md +94 -90
  46. package/ai/skills/testdriver-self-hosted/SKILL.md +82 -140
  47. package/ai/skills/testdriver-test-results-json/SKILL.md +165 -202
  48. package/ai/skills/testdriver-type/SKILL.md +56 -304
  49. package/ai/skills/testdriver-variables/SKILL.md +119 -80
  50. package/ai/skills/testdriver-wait/SKILL.md +31 -29
  51. package/ai/skills/testdriver-what-is-testdriver/SKILL.md +80 -32
  52. package/package.json +1 -1
@@ -1,111 +1,89 @@
1
1
  ---
2
2
  name: testdriver:bring-your-own-machine
3
- description: Run the TestDriver runner on a laptop, desktop, or VM you control and drive it from your tests.
3
+ description: Run the TestDriver runner on a laptop, desktop, or VM you control, and point your tests at it.
4
4
  ---
5
5
  <!-- Generated from bring-your-own-machine.mdx. DO NOT EDIT. -->
6
6
 
7
- TestDriver normally provisions a cloud sandbox for you. You can instead run the **runner** on a machine you own: a developer laptop, an office Mac, a lab Windows box, or a VM in your own data center. Your tests then drive that machine instead of a cloud sandbox.
7
+ import { EnterpriseBadge, EnterpriseCta } from '/snippets/enterprise.mdx';
8
8
 
9
- This is useful when the machine under test cannot be replicated in the cloud: specific hardware, a licensed desktop application, a device plugged into USB, or an app that only reaches an internal network.
9
+ Run your tests on a machine you control instead of a cloud sandbox. It can be a laptop, a lab machine, or a VM in your own data center.
10
10
 
11
- ```mermaid
12
- graph LR
13
- A[Your Test] --> B[TestDriver API]
14
- B --> C[Ably Channel]
15
- C --> D[Runner on your machine]
16
- D --> C
17
- ```
11
+ Use it when the cloud can't reproduce the machine under test, for example:
18
12
 
19
- <Note>
20
- The runner only makes **outbound** connections, to the TestDriver API and to Ably. You do not need to open an inbound port or expose the machine to the internet.
21
- </Note>
13
+ - Specific hardware, or a device plugged in over USB.
14
+ - A licensed desktop app.
15
+ - An app that only reaches your internal network.
22
16
 
23
- ## Choose your path
17
+ The machine runs the TestDriver **runner**. Your test sends commands to it through the TestDriver API.
24
18
 
25
- | Your machine | Use |
26
- |---|---|
27
- | Windows EC2 instance in your AWS account | [AWS Setup Guide](/aws-setup). Instances are spawned and provisioned automatically. |
28
- | Any other machine (macOS, Linux, Windows, on-prem VM) | This guide. You start the runner yourself. |
19
+ <EnterpriseCta feature="Running tests on your own machines" />
20
+
21
+ <Note>
22
+ The runner only makes outbound connections, to the TestDriver API and to Ably for realtime messages. You don't need to open an inbound port.
23
+ </Note>
29
24
 
30
- <Tip>
31
- If you want unlimited execution, assisted setup, and custom VM images, see [Self-Hosted (Enterprise)](/self-hosted).
32
- </Tip>
25
+ For Windows EC2 instances that start and stop automatically, use the [AWS setup](/aws-setup) instead.
33
26
 
34
- ## Prerequisites
27
+ ## Before you begin
35
28
 
36
- Every machine that runs the runner needs:
29
+ The machine needs:
37
30
 
38
- - **Node.js 18 or newer**
39
- - **Python 3** with `pyautogui` and `Pillow`
40
- - **A real, unlocked desktop session.** The runner drives the mouse and keyboard, so the screen must be awake and not locked. Disable screen savers, sleep, and lock timers.
41
- - **Google Chrome** on the `PATH`, if your tests launch a browser
42
- - Outbound HTTPS and WebSocket access to `api.testdriver.ai` and `*.ably.io`
31
+ - **Node.js 18 or newer.**
32
+ - **Python 3** with `pyautogui` and `Pillow`. The runner uses them for the mouse, keyboard, and screenshots.
33
+ - **An unlocked desktop session.** The runner drives the real screen, so turn off sleep, screen savers, and lock timers.
34
+ - **Outbound HTTPS and WebSocket access** to `api.testdriver.ai` and `*.ably.io`.
35
+ - **`curl` and `jq`**, to register the machine in step 2.
43
36
 
44
- Install the Python dependencies:
37
+ You also need your TestDriver API key in `TD_API_KEY`. Copy it from the [API keys page](https://console.testdriver.ai/team/api-keys).
45
38
 
46
39
  <Tabs>
47
40
  <Tab title="macOS">
41
+
48
42
  ```bash
49
- brew install python
50
43
  pip3 install pyautogui Pillow
51
44
  ```
45
+
46
+ macOS blocks synthetic input and screen capture until you allow them. Open **System Settings → Privacy & Security** and add the terminal app that starts the runner to both lists:
47
+
48
+ - **Accessibility**, so the runner can move the mouse and type.
49
+ - **Screen Recording**, so the runner can take screenshots.
50
+
51
+ Quit and reopen the terminal after you change these settings.
52
+
52
53
  </Tab>
53
54
  <Tab title="Linux">
55
+
54
56
  ```bash
55
57
  sudo apt-get install -y python3-pip python3-xlib
56
58
  pip3 install pyautogui Pillow
57
59
  ```
58
- </Tab>
59
- <Tab title="Windows">
60
- ```powershell
61
- pip install pyautogui Pillow
62
- ```
63
- </Tab>
64
- </Tabs>
65
60
 
66
- ### Platform notes
67
-
68
- <AccordionGroup>
69
- <Accordion title="macOS: grant Accessibility and Screen Recording permissions">
70
- macOS blocks synthetic input and screen capture until you allow it explicitly. Without this the runner connects but every click and screenshot silently fails.
71
-
72
- Open **System Settings → Privacy & Security** and add your terminal application (Terminal, iTerm, or whichever app starts the runner) to **both**:
73
-
74
- - **Accessibility** (lets the runner move the mouse and type)
75
- - **Screen Recording** (lets the runner take screenshots)
76
-
77
- Quit and reopen the terminal after granting permissions, otherwise the old process keeps the old denial.
78
-
79
- On Retina displays, screenshots are captured at physical pixels and downscaled to logical points so that coordinates returned by the AI line up with where clicks actually land. No configuration is needed.
80
- </Accordion>
81
-
82
- <Accordion title="Linux: provide a display">
83
- The runner needs an X11 display. On a desktop machine, set `DISPLAY` to your existing session. On a headless server, start a virtual framebuffer first:
61
+ The runner needs an X11 display. It uses `:0` unless `DISPLAY` is set. On a server without a desktop, start a virtual display first:
84
62
 
85
63
  ```bash
86
- sudo apt-get install -y xvfb xfce4 xfce4-terminal dbus-x11 wmctrl
64
+ sudo apt-get install -y xvfb xfce4 dbus-x11
87
65
  Xvfb :0 -screen 0 1366x768x24 &
88
- export DISPLAY=:0
66
+ DISPLAY=:0 startxfce4 &
89
67
  ```
90
68
 
91
- To watch the session, add a VNC server and noVNC:
69
+ Turn off screen blanking so the desktop stays visible:
92
70
 
93
71
  ```bash
94
- sudo apt-get install -y x11vnc novnc websockify
95
- x11vnc -display :0 -forever -shared &
72
+ export DISPLAY=:0
73
+ xset s off && xset s noblank && xset -dpms
96
74
  ```
97
75
 
98
- Disable screen blanking so the desktop stays visible:
76
+ </Tab>
77
+ <Tab title="Windows">
99
78
 
100
- ```bash
101
- xset s off && xset s noblank && xset -dpms
79
+ ```powershell
80
+ pip install pyautogui Pillow
102
81
  ```
103
- </Accordion>
104
82
 
105
- <Accordion title="Windows: keep the console session active">
106
- Run the runner in a console or RDP session that stays signed in. If the session locks or disconnects, the desktop is torn down and automation stops. Configure the machine to auto-logon and disable the lock screen timeout.
107
- </Accordion>
108
- </AccordionGroup>
83
+ Run the runner in a console or RDP session that stays signed in. If the session locks or disconnects, Windows tears down the desktop and automation stops. Set the machine to sign in automatically and turn off the lock screen.
84
+
85
+ </Tab>
86
+ </Tabs>
109
87
 
110
88
  ## Step 1: Install the runner
111
89
 
@@ -113,208 +91,163 @@ Install the Python dependencies:
113
91
  npm install -g @testdriverai/runner
114
92
  ```
115
93
 
116
- This installs two commands. You use `testdriver-sandbox-agent`, which connects your machine to a TestDriver session.
117
-
118
- Verify the install:
119
-
120
- ```bash
121
- testdriver-sandbox-agent --help || echo "installed"
122
- ```
94
+ This installs the `testdriver-sandbox-agent` command, which connects the machine to a TestDriver session.
123
95
 
124
96
  ## Step 2: Register the machine
125
97
 
126
- Ask the API for a session bound to your machine's IP address:
98
+ Ask the API for a session on this machine. Replace `192.168.1.50` with the machine's IP address, and set `os` to `windows` on a Windows machine:
127
99
 
128
100
  ```bash
129
- curl -X POST https://api.testdriver.ai/api/v7/sandbox/authenticate \
101
+ curl -sS -X POST https://api.testdriver.ai/api/v7/sandbox/authenticate \
130
102
  -H "Content-Type: application/json" \
131
- -d '{
132
- "apiKey": "your_api_key",
133
- "ip": "192.168.1.50",
134
- "os": "linux",
135
- "keepAlive": 900000
136
- }'
103
+ -d "{
104
+ \"apiKey\": \"$TD_API_KEY\",
105
+ \"apiRoot\": \"https://api.testdriver.ai\",
106
+ \"ip\": \"192.168.1.50\",
107
+ \"os\": \"linux\",
108
+ \"keepAlive\": 900000
109
+ }" > td-session.json
137
110
  ```
138
111
 
139
- The response contains the sandbox ID and the Ably credentials the runner needs:
140
-
141
- ```json
142
- {
143
- "success": true,
144
- "sandboxId": "sb-69cce96e-1e0",
145
- "agent": {
146
- "token": {
147
- "token": "aFC5YQ.Ki9G9...",
148
- "keyName": "aFC5YQ.ZIdTww",
149
- "issued": 1791908438832,
150
- "expires": 1791930038832,
151
- "capability": "{\"testdriver:...:sb-69cce96e-1e0\":[\"history\",\"presence\",\"publish\",\"subscribe\"]}",
152
- "clientId": "agent-sb-69cce96e-1e0"
153
- },
154
- "channel": "testdriver:...:sb-69cce96e-1e0"
155
- }
156
- }
157
- ```
112
+ The response includes a sandbox ID and an `agentConfig` object with everything the runner needs. Write `agentConfig` to the runner's config file, and print the sandbox ID:
158
113
 
159
- <Note>
160
- Pass `os: "linux"` on macOS. The value only describes the session to the API; the runner detects the real platform itself.
161
- </Note>
162
-
163
- ### Write the config file
164
-
165
- The runner reads its credentials from a JSON file on disk. Copy `sandboxId` and the whole `agent` block into it:
166
-
167
- | Platform | Config file path |
168
- |---|---|
169
- | macOS / Linux | `/tmp/testdriver-agent.json` |
170
- | Windows | `C:\Windows\Temp\testdriver-agent.json` |
171
-
172
- ```json /tmp/testdriver-agent.json
173
- {
174
- "sandboxId": "sb-69cce96e-1e0",
175
- "apiRoot": "https://api.testdriver.ai",
176
- "apiKey": "your_api_key",
177
- "ably": {
178
- "token": {
179
- "token": "aFC5YQ.Ki9G9...",
180
- "keyName": "aFC5YQ.ZIdTww",
181
- "issued": 1791908438832,
182
- "expires": 1791930038832,
183
- "capability": "{\"testdriver:...:sb-69cce96e-1e0\":[\"history\",\"presence\",\"publish\",\"subscribe\"]}",
184
- "clientId": "agent-sb-69cce96e-1e0"
185
- },
186
- "channel": "testdriver:...:sb-69cce96e-1e0"
187
- }
188
- }
114
+ ```bash
115
+ jq '.agentConfig' td-session.json > /tmp/testdriver-agent.json
116
+ chmod 600 /tmp/testdriver-agent.json
117
+ jq -r '.sandboxId' td-session.json
189
118
  ```
190
119
 
191
- | Field | Source | Purpose |
192
- |---|---|---|
193
- | `sandboxId` | `sandboxId` from the response | Identifies this session. Your test attaches to it. |
194
- | `apiRoot` | The API you called | Where the runner uploads screenshots |
195
- | `apiKey` | Your team API key | Authenticates those uploads |
196
- | `ably.token` | `agent.token` from the response, copied verbatim | Realtime credentials |
197
- | `ably.channel` | `agent.channel` from the response | Channel the runner listens on |
120
+ On Windows, run these commands in Git Bash and write the file to `/c/Windows/Temp/testdriver-agent.json` instead.
198
121
 
199
- To put the file somewhere else, set `CONFIG_PATH` to its full path before starting the runner.
122
+ Save the sandbox ID, such as `sb-69cce96e-1e0`, for step 4.
200
123
 
201
124
  <Warning>
202
- This file holds a session token and your API key. Keep it readable only by the user running the runner, do not commit it, and delete it when the machine is no longer in use.
125
+ The config file contains your API key and a session token. Keep it readable only by the user who runs the runner, and never commit it.
203
126
  </Warning>
204
127
 
128
+ To keep the config file somewhere else, set `CONFIG_PATH` to its full path before you start the runner.
129
+
130
+ A registered machine uses one of your plan's concurrency slots while its session is open.
131
+
205
132
  ## Step 3: Start the runner
206
133
 
207
134
  ```bash
208
135
  testdriver-sandbox-agent
209
136
  ```
210
137
 
211
- You should see the runner connect and announce itself:
138
+ The runner reads the config file, connects, and waits for commands:
212
139
 
140
+ ```text
141
+ [2026-10-21T15:04:05.000Z] TestDriver Sandbox Agent starting...
142
+ [2026-10-21T15:04:05.100Z] Sandbox ID: sb-69cce96e-1e0
143
+ [2026-10-21T15:04:05.100Z] Transport: Ably
144
+ [2026-10-21T15:04:06.200Z] Automation module initialized
145
+ [2026-10-21T15:04:07.300Z] Agent ready — listening for commands via Ably
213
146
  ```
214
- [agent] TestDriver Sandbox Agent starting...
215
- [agent] Sandbox ID: sb-69cce96e-1e0
216
- [agent] Transport: Ably
217
- [agent] Automation module initialized
218
- [realtime] Publishing control: type=runner.ready
219
- [agent] Agent ready — listening for commands via Ably
220
- ```
221
-
222
- Leave this process running. On Linux, set `DISPLAY` first:
223
147
 
224
- ```bash
225
- DISPLAY=:0 testdriver-sandbox-agent
226
- ```
148
+ Leave it running. If the config file doesn't exist yet, the runner waits up to 5 minutes for it.
227
149
 
228
150
  ## Step 4: Point your test at the machine
229
151
 
230
- Pass the machine's `ip` and the sandbox ID from step 2:
152
+ Pass the machine's `ip` and the `sandboxId` from step 2 to `TestDriver()`. Setting `sandboxId` stops TestDriver from creating a cloud sandbox.
231
153
 
232
154
  ```javascript tests/my-machine.test.mjs
233
- import { describe, expect, it } from "vitest";
234
- import { TestDriver } from "testdriverai/vitest/hooks";
155
+ import { describe, it } from 'vitest';
156
+ import { TestDriver } from 'testdriverai/vitest/hooks';
235
157
 
236
- describe("My machine", () => {
237
- it("runs against my own hardware", async (context) => {
238
- const testdriver = TestDriver(context, { newSandbox: false });
239
-
240
- await testdriver.connect({
158
+ describe('My machine', () => {
159
+ it('signs in to the desktop app', async (context) => {
160
+ const testdriver = TestDriver(context, {
241
161
  ip: process.env.TD_MACHINE_IP,
242
162
  sandboxId: process.env.TD_SANDBOX_ID,
243
163
  });
244
164
 
245
- const button = await testdriver.find("Sign In button");
246
- await button.click();
247
-
248
- const result = await testdriver.assert("the dashboard is visible");
249
- expect(result).toBeTruthy();
165
+ await testdriver.find('Sign in button').click();
166
+ await testdriver.assert('the dashboard is visible');
250
167
  });
251
168
  });
252
169
  ```
253
170
 
254
- Run it:
171
+ On a Windows machine, also pass `os: 'windows'`.
172
+
173
+ <Warning>
174
+ Run these tests with the `CI` environment variable unset. When `CI` is set, TestDriver always requests a new sandbox and ignores `sandboxId`, so the test waits for a runner that never connects.
175
+ </Warning>
176
+
177
+ Run the test from any computer:
255
178
 
256
179
  ```bash
257
- TD_MACHINE_IP=192.168.1.50 TD_SANDBOX_ID=sb-69cce96e-1e0 vitest run
180
+ TD_MACHINE_IP=192.168.1.50 TD_SANDBOX_ID=sb-69cce96e-1e0 npx vitest run
258
181
  ```
259
182
 
260
- <Note>
261
- `newSandbox: false` stops the SDK from provisioning a cloud sandbox. Without it, your test runs in the cloud and ignores your machine.
262
- </Note>
263
-
264
- <Note>
265
- Each config file covers one session. The Ably token in it expires (see its `expires` field), so repeat steps 2 and 3 to get fresh credentials before the next run.
266
- </Note>
183
+ Each registration covers one session. When the test disconnects, the session ends. Repeat steps 2 and 3 before the next run.
267
184
 
268
185
  ## Logs
269
186
 
270
187
  | Platform | Runner log |
271
- |---|---|
272
- | macOS / Linux | `/tmp/testdriver-agent.log` |
188
+ | --- | --- |
189
+ | macOS and Linux | `/tmp/testdriver-agent.log` |
273
190
  | Windows | `C:\Windows\Temp\testdriver-agent.log` |
274
191
 
275
- The runner also writes a status file next to the log (`testdriver-agent-status.json`) with the sandbox ID, process ID, detected IP, and start time.
192
+ The runner also writes `testdriver-agent-status.json` in the same folder, with the sandbox ID, process ID, IP address, and start time.
276
193
 
277
194
  ## Security
278
195
 
279
- - **Use a dedicated machine or user account.** The runner can click anything on the desktop and run shell commands sent by your tests. Do not point it at a machine holding personal credentials or production access.
280
- - **Treat the config file as a secret.** It contains a session token and your API key.
281
- - **Do not expose VNC to the internet.** If you add VNC for debugging, bind it to localhost or your VPN and tunnel in over SSH.
282
- - **Rotate your API key** if a machine is decommissioned or shared.
196
+ - **Use a dedicated machine or user account.** The runner can click anything on the desktop and run shell commands sent by your tests.
197
+ - **Treat the config file as a secret.** It contains your API key and a session token.
198
+ - **Keep VNC private.** If you add a VNC server for debugging, expose it only on localhost or your VPN.
199
+ - **Rotate your API key** on the [API keys page](https://console.testdriver.ai/team/api-keys) when you retire or share a machine.
283
200
 
284
201
  ## Troubleshooting
285
202
 
286
203
  <AccordionGroup>
287
204
  <Accordion title="Sandbox has expired and is no longer available">
288
- The session ended, which happens when the runner stops or your test disconnects. Repeat step 2 to get a fresh sandbox ID and token, update the config file, restart the runner, and use the new ID in your test.
289
- </Accordion>
290
205
 
291
- <Accordion title="Runner starts but clicks and screenshots do nothing (macOS)">
292
- Accessibility or Screen Recording permission is missing. Add your terminal application to both lists under **System Settings → Privacy & Security**, then fully quit and reopen the terminal.
206
+ The session ended, which happens after a test disconnects or the session's `keepAlive` runs out. Repeat steps 2 and 3 for a fresh sandbox ID, and use the new ID in your test.
207
+
293
208
  </Accordion>
209
+ <Accordion title="The runner connects, but clicks and screenshots do nothing (macOS)">
210
+
211
+ Accessibility or Screen Recording permission is missing. Add your terminal app to both lists in **System Settings → Privacy & Security**, then quit and reopen it.
294
212
 
295
- <Accordion title="Waiting for config file">
296
- The runner cannot find `/tmp/testdriver-agent.json` (or `C:\Windows\Temp\testdriver-agent.json`). Write the config file on the same machine and readable by the same user that starts the runner. To use a different location, set `CONFIG_PATH`.
297
213
  </Accordion>
214
+ <Accordion title="Config file not found after 300s">
215
+
216
+ The runner couldn't find the config file. Write it on the same machine, readable by the user who starts the runner, or set `CONFIG_PATH` to where it is.
298
217
 
299
- <Accordion title="Test provisions a cloud sandbox instead of using my machine">
300
- Pass `newSandbox: false` to `TestDriver()` and make sure both `ip` and `sandboxId` reach `connect()`. If either is undefined, the SDK falls back to cloud provisioning.
301
218
  </Accordion>
219
+ <Accordion title="The test runs in a cloud sandbox instead">
220
+
221
+ Check that both `TD_MACHINE_IP` and `TD_SANDBOX_ID` are set when you run the test. If `sandboxId` is undefined, TestDriver creates a cloud sandbox.
302
222
 
303
- <Accordion title="Invalid API key">
304
- Confirm `TD_API_KEY` matches the environment in `TD_API_ROOT`. Keys are scoped per environment. Get your key at [console.testdriver.ai/team](https://console.testdriver.ai/team).
305
223
  </Accordion>
224
+ <Accordion title="Screenshots are blank or frozen (Linux)">
225
+
226
+ `DISPLAY` points at a display with no desktop, or the screen blanked. Start a desktop on that display and turn off blanking with `xset s off && xset s noblank && xset -dpms`.
306
227
 
307
- <Accordion title="Screenshots are blank or show a frozen desktop (Linux)">
308
- `DISPLAY` points at a display with no desktop running, or the screen blanked. Start a desktop on that display and disable blanking with `xset s off && xset s noblank && xset -dpms`.
309
228
  </Accordion>
310
229
  </AccordionGroup>
311
230
 
312
- ## Environment variables
313
-
314
- | Variable | Default | Purpose |
315
- |---|---|---|
316
- | `TD_API_KEY` | Required | Your team API key |
317
- | `TD_API_ROOT` | `https://api.testdriver.ai` | API server to register with |
318
- | `CONFIG_PATH` | `/tmp/testdriver-agent.json` | Override the runner config file location |
319
- | `DISPLAY` | `:0` | X11 display (Linux) |
320
- | `SENTRY_DSN` | Unset | Error reporting endpoint |
231
+ ## Runner environment variables
232
+
233
+ | Variable | Default | Description |
234
+ | --- | --- | --- |
235
+ | `CONFIG_PATH` | `/tmp/testdriver-agent.json`, or `C:\Windows\Temp\testdriver-agent.json` on Windows | Where the runner reads its config file |
236
+ | `DISPLAY` | `:0` | The X11 display to drive (Linux) |
237
+
238
+ ## Next steps
239
+
240
+ <CardGroup cols={2}>
241
+ <Card title="Self-host on AWS" icon="aws" href="/aws-setup">
242
+ Start a fresh Windows EC2 instance for each test.
243
+ </Card>
244
+ <Card title="Self-hosted" icon="server" href="/self-hosted">
245
+ What the Enterprise plan includes.
246
+ </Card>
247
+ <Card title="Locate elements" icon="crosshairs" href="/locating-elements">
248
+ Describe elements so TestDriver finds them on any screen.
249
+ </Card>
250
+ <Card title="Make assertions" icon="circle-check" href="/making-assertions">
251
+ Check that your app reached the right state.
252
+ </Card>
253
+ </CardGroup>