testdriverai 7.11.282-test → 7.11.283-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.
@@ -327,4 +327,3 @@ const customMarkdown = markdown.replace(
327
327
 
328
328
  - **Documentation:** [testdriver.ai/docs](https://testdriver.ai/docs)
329
329
  - **Issues:** [github.com/testdriverai/testdriverai/issues](https://github.com/testdriverai/testdriverai/issues)
330
- - **Discord:** Join our [community Discord](https://discord.gg/testdriver)
@@ -160,7 +160,6 @@ GITHUB_TOKEN=ghp_xxx GITHUB_PR_NUMBER=123 npm run test:sdk
160
160
 
161
161
  - **Documentation:** [testdriver.ai/docs](https://testdriver.ai/docs)
162
162
  - **Issues:** [GitHub Issues](https://github.com/testdriverai/testdriverai/issues)
163
- - **Discord:** [Join our community](https://discord.gg/testdriver)
164
163
 
165
164
  ---
166
165
 
@@ -341,7 +341,6 @@ Yes! Enterprise plans include self-hosting options. See [self-hosting guide](/gu
341
341
 
342
342
  ### Where can I get help?
343
343
 
344
- - **Discord** - [discord.com/invite/cWDFW8DzPm](https://discord.com/invite/cWDFW8DzPm)
345
344
  - **Docs** - [docs.testdriver.ai](https://docs.testdriver.ai)
346
345
  - **GitHub** - [github.com/testdriverai/testdriverai](https://github.com/testdriverai/testdriverai)
347
346
  - **Email** - support@testdriver.ai
@@ -356,14 +355,6 @@ Yes! Enterprise plans include self-hosting options. See [self-hosting guide](/gu
356
355
  - Dashcam URL
357
356
  - Minimal reproduction
358
357
 
359
- ### Is there a community?
360
-
361
- Yes! Join our [Discord](https://discord.com/invite/cWDFW8DzPm) to:
362
- - Ask questions
363
- - Share tips
364
- - See examples
365
- - Get updates
366
-
367
358
  ## See Also
368
359
 
369
360
  <CardGroup cols={2}>
@@ -378,8 +369,4 @@ Yes! Join our [Discord](https://discord.com/invite/cWDFW8DzPm) to:
378
369
  <Card title="Best Practices" icon="star" href="/guides/best-practices">
379
370
  Testing patterns
380
371
  </Card>
381
-
382
- <Card title="Discord Community" icon="discord" href="https://discord.com/invite/cWDFW8DzPm">
383
- Join the community
384
- </Card>
385
372
  </CardGroup>
@@ -487,9 +487,8 @@ If issues persist:
487
487
 
488
488
  1. **Check Dashcam recording** - See what actually happened
489
489
  2. **Enable debug logging** - `verbosity: 2`
490
- 3. **Search Discord** - [discord.com/invite/cWDFW8DzPm](https://discord.com/invite/cWDFW8DzPm)
491
- 4. **Check docs** - [docs.testdriver.ai](https://docs.testdriver.ai)
492
- 5. **Report bug** - [github.com/testdriverai/testdriverai/issues](https://github.com/testdriverai/testdriverai/issues)
490
+ 3. **Check docs** - [docs.testdriver.ai](https://docs.testdriver.ai)
491
+ 4. **Report bug** - [github.com/testdriverai/testdriverai/issues](https://github.com/testdriverai/testdriverai/issues)
493
492
 
494
493
  ### Information to Include
495
494
 
package/docs/agent.mdx CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "The TestDriver agent"
3
- sidebarTitle: "Introduction"
3
+ sidebarTitle: "Add to GitHub"
4
4
  description: "How the TestDriver agent reviews pull requests, builds tests, and answers @mentions on GitHub."
5
5
  icon: "hand-horns"
6
6
  ---
package/docs/ci-cd.mdx CHANGED
@@ -289,8 +289,8 @@ TESTDRIVER_RUN_URL=https://console.testdriver.ai/runs/abc123
289
289
  <Card title="Add TestDriver to GitHub" icon="github" href="/quickstart-github">
290
290
  Get an AI code review on every pull request.
291
291
  </Card>
292
- <Card title="Hosted plans" icon="cloud" href="/hosted">
293
- Compare plans, testing minutes, and concurrency.
292
+ <Card title="Hosted sandboxes" icon="cloud" href="/hosted">
293
+ How testing minutes and concurrency work.
294
294
  </Card>
295
295
  <Card title="Speed up reruns with caching" icon="brain" href="/caching">
296
296
  Reuse element locations from passing runs.
@@ -100,7 +100,7 @@ The agent then:
100
100
  2. Updates the test.
101
101
  3. Opens a pull request with the fix for you to review.
102
102
 
103
- You can make the same request from your editor through the [Claude Code plugin](/quickstart-claude) or the [VS Code extension](/quickstart-vscode).
103
+ You can make the same request from your editor through the [Claude Code connector](/quickstart-claude) or the [VS Code extension](/quickstart-vscode).
104
104
 
105
105
  <Warning>
106
106
  Review the agent's fix before you merge it. A test updated to pass may no longer check what you meant. Confirm that the assertions still describe the behavior you want.
@@ -59,7 +59,7 @@ To save a screenshot at a specific point instead, call [`screenshot()`](/screens
59
59
 
60
60
  ## Inspect screenshots with your AI assistant
61
61
 
62
- With the [local TestDriver MCP server](/mcp-setup#run-the-server-locally), your AI assistant can list and view these screenshots. Ask in plain language:
62
+ With the [TestDriver MCP server](/mcp-setup), your AI assistant can list and view these screenshots. Ask in plain language:
63
63
 
64
64
  ```text
65
65
  The login test failed at line 42. Show me the screenshots from just before and after that line.
package/docs/docs.json CHANGED
@@ -16,17 +16,7 @@
16
16
  {
17
17
  "group": "Overview",
18
18
  "pages": [
19
- {
20
- "group": "Get started",
21
- "icon": "rocket",
22
- "pages": [
23
- "/quickstart",
24
- "/quickstart-github",
25
- "/quickstart-claude",
26
- "/mcp-setup"
27
- ]
28
- },
29
- "/agent",
19
+ "/quickstart",
30
20
  "/what-is-testdriver",
31
21
  {
32
22
  "group": "Examples",
@@ -49,6 +39,14 @@
49
39
  }
50
40
  ]
51
41
  },
42
+ {
43
+ "group": "Quickstart",
44
+ "pages": [
45
+ "/agent",
46
+ "/quickstart-claude",
47
+ "/mcp-setup"
48
+ ]
49
+ },
52
50
  {
53
51
  "group": "Using TestDriver",
54
52
  "pages": [
@@ -173,7 +171,6 @@
173
171
  "socials": {
174
172
  "x": "https://x.com/testdriverai",
175
173
  "github": "https://github.com/testdriverai",
176
- "discord": "https://discord.com/invite/cWDFW8DzPm",
177
174
  "youtube": "https://www.youtube.com/@testdriverai"
178
175
  }
179
176
  },
@@ -15,7 +15,7 @@ Describe a flow in plain language, and the TestDriver agent writes the test for
15
15
 
16
16
  Install TestDriver in an AI coding assistant that can edit files in your repository:
17
17
 
18
- - **Claude Code:** [install the plugin](/quickstart-claude).
18
+ - **Claude Code:** [install the connector](/quickstart-claude).
19
19
  - **VS Code or Cursor:** [install the extension](/quickstart-vscode).
20
20
  - **Any other assistant:** run `npx testdriverai init` in your repository and choose your assistant. See [Set up a project](/quickstart-manual).
21
21
 
@@ -262,5 +262,4 @@ The GIF replays are automatically embedded so reviewers can see what happened wi
262
262
  ## Getting Help
263
263
 
264
264
  - 📚 [Full Documentation](https://docs.testdriver.ai)
265
- - 💬 [Discord Community](https://discord.gg/testdriver)
266
265
  - 🐛 [Report Issues](https://github.com/testdriverai/testdriverai/issues)
package/docs/hosted.mdx CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: "Hosted plans"
2
+ title: "Hosted sandboxes"
3
3
  sidebarTitle: "Hosted"
4
- description: "Run tests on TestDriver's cloud sandboxes, billed by testing minutes, with no infrastructure to manage."
4
+ description: "Run tests on TestDriver's cloud sandboxes, with no infrastructure to manage."
5
5
  icon: "cloud"
6
6
  mode: "wide"
7
7
  ---
@@ -11,32 +11,11 @@ import { EnterpriseBadge, EnterpriseCta } from '/snippets/enterprise.mdx';
11
11
  By default, your tests run on TestDriver's cloud. Each test gets a fresh sandbox, and you don't manage any machines.
12
12
 
13
13
  - Hosted is the default. When you follow the [Quickstart](/quickstart), you're using it.
14
- - You're billed in **testing minutes**: the time a sandbox is running.
14
+ - Usage is measured in **testing minutes**: the time a sandbox is running.
15
15
  - Your plan sets how many sandboxes can run at the same time.
16
16
 
17
- ## Plans
18
-
19
- | | Free | Pro | Team |
20
- | --- | --- | --- | --- |
21
- | **Price** | $0 | $24 per seat per month | $600 per month |
22
- | **Testing minutes included** | 30 | 360 | 10,000 |
23
- | **Extra minutes** | Not available | $0.08 per minute | $0.08 per minute |
24
- | **Sandboxes at once** | 2 | 4 | 8 |
25
- | **Users** | Unlimited | One per seat | 5 |
26
- | **Test analytics** | No | Yes | Yes |
27
- | **CPU, RAM, and network profiles** | No | Yes | Yes |
28
- | **Support** | Community | Community | Private |
29
-
30
17
  <EnterpriseCta feature="Windows sandboxes, custom screen resolutions, and self-hosting" plural />
31
18
 
32
- Pro starts with a 14-day free trial. Start a plan from the [TestDriver console](https://console.testdriver.ai/checkout/pro).
33
-
34
- On the Free plan, new sandboxes are refused once you've used your 30 minutes. Upgrade to keep testing.
35
-
36
- <Note>
37
- If you install TestDriver from GitHub Marketplace, GitHub bills you instead. The **Open Source** plan is free with 300 testing minutes per month. The **Team** plan is $20 per seat per month with 120 testing minutes per seat.
38
- </Note>
39
-
40
19
  ## How testing minutes are counted
41
20
 
42
21
  Testing minutes run while a sandbox is running. That includes sandboxes started by:
@@ -70,10 +49,10 @@ concurrency:
70
49
 
71
50
  Consider [self-hosting](/self-hosted) when you need to:
72
51
 
73
- - Run tests on your own infrastructure, without per-minute billing.
52
+ - Run tests on your own infrastructure.
74
53
  - Use your own AI provider keys.
75
54
  - Run custom VM images with your software preinstalled.
76
- - Run more tests in parallel than the hosted plans allow.
55
+ - Run more tests in parallel than hosted allows.
77
56
 
78
57
  ## Next steps
79
58
 
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#D97757"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
@@ -20,7 +20,7 @@ https://mcp.testdriver.ai/mcp
20
20
  ## Before you begin
21
21
 
22
22
  - **An MCP client** that supports remote servers, such as Claude, Claude Code, Cursor, VS Code, or ChatGPT.
23
- - **A TestDriver account.** [Sign up at console.testdriver.ai](https://console.testdriver.ai). The free plan includes 30 testing minutes and needs no credit card.
23
+ - **A TestDriver account.** [Sign up at console.testdriver.ai](https://console.testdriver.ai).
24
24
 
25
25
  ## Add the server
26
26
 
@@ -133,35 +133,6 @@ Each action also returns the SDK code for that step. The agent uses it to assemb
133
133
 
134
134
  To turn that test into a file you run locally and in CI, [set up a project](/quickstart-manual).
135
135
 
136
- ## Run the server locally
137
-
138
- Run the server as a local stdio process for headless automation, or to authenticate with an API key instead of a browser sign-in:
139
-
140
- ```bash
141
- npx -p testdriverai testdriverai-mcp
142
- ```
143
-
144
- It reads your API key from the `TD_API_KEY` environment variable. Create a key at [console.testdriver.ai/team/api-keys](https://console.testdriver.ai/team/api-keys).
145
-
146
- Then configure your client to start the server:
147
-
148
- ```json .mcp.json
149
- {
150
- "mcpServers": {
151
- "testdriver": {
152
- "type": "stdio",
153
- "command": "npx",
154
- "args": ["-p", "testdriverai", "testdriverai-mcp"],
155
- "env": { "TD_API_KEY": "${TD_API_KEY}" }
156
- }
157
- }
158
- }
159
- ```
160
-
161
- <Tip>
162
- `npx testdriverai init` writes this config for your client, along with the TestDriver agent, skills, an example test, and a GitHub Actions workflow. See [Set up a project](/quickstart-manual).
163
- </Tip>
164
-
165
136
  ## Troubleshooting
166
137
 
167
138
  <AccordionGroup>
@@ -174,7 +145,14 @@ Then configure your client to start the server:
174
145
 
175
146
  Your client needs to support OAuth 2.1 with Dynamic Client Registration.
176
147
 
177
- Clients that only support local (stdio) servers can't connect to the hosted URL. [Run the server locally](#run-the-server-locally) with an API key instead.
148
+ Clients that only support local (stdio) servers can't connect to the hosted URL.
149
+
150
+ </Accordion>
151
+ <Accordion title="The agent says an upgrade is required">
152
+
153
+ Your team's plan doesn't include sandbox sessions. You can sign in and connect, but `session_start` returns an upgrade link instead of a sandbox.
154
+
155
+ Follow the link, then ask the agent to try again. You don't need to reconnect.
178
156
 
179
157
  </Accordion>
180
158
  <Accordion title="The sandbox expired in the middle of a session">
@@ -186,7 +164,7 @@ Then configure your client to start the server:
186
164
  </Accordion>
187
165
  <Accordion title="I ran out of testing minutes">
188
166
 
189
- Sandbox time counts against your plan's testing minutes. Check your usage and upgrade at [console.testdriver.ai/usage](https://console.testdriver.ai/usage).
167
+ Sandbox time counts against your plan's testing minutes. Check your usage at [console.testdriver.ai/usage](https://console.testdriver.ai/usage).
190
168
 
191
169
  </Accordion>
192
170
  </AccordionGroup>
@@ -12,7 +12,7 @@ The connector is the fastest way to get started: one click, a browser sign-in, a
12
12
  ## Before you begin
13
13
 
14
14
  - **[Claude Code](https://code.claude.com)**, signed in with the same account you use on claude.ai.
15
- - **A TestDriver account.** [Sign up at console.testdriver.ai](https://console.testdriver.ai). The free plan includes 30 testing minutes and needs no credit card.
15
+ - **A TestDriver account.** [Sign up at console.testdriver.ai](https://console.testdriver.ai).
16
16
 
17
17
  <Steps>
18
18
  <Step title="Install the connector">
@@ -41,61 +41,9 @@ The connector is the fastest way to get started: one click, a browser sign-in, a
41
41
 
42
42
  Claude starts a sandbox, performs each step, and gets a screenshot after every action. Each tool call also returns the SDK code for that step, which Claude assembles into a runnable [Vitest](https://vitest.dev) test.
43
43
 
44
- To save and run those tests locally and in CI, [set up a project](/quickstart-manual).
45
-
46
- </Step>
47
- </Steps>
48
-
49
- ## Alternative: install the plugin
50
-
51
- Prefer everything to run locally, or want the `testdriver` agent and skills bundled in? Install the TestDriver plugin instead. It bundles three things:
52
-
53
- - The TestDriver MCP server, run locally over stdio
54
- - The `testdriver` agent, which builds tests step by step
55
- - Skills that teach Claude the TestDriver SDK
56
-
57
- The plugin requires **Node.js 20.19 or later** and a **TestDriver API key**. Create one at [console.testdriver.ai/team/api-keys](https://console.testdriver.ai/team/api-keys).
58
-
59
- <Steps>
60
- <Step title="Set your API key">
61
-
62
- The plugin's MCP server reads your key from the `TD_API_KEY` environment variable. Add it to your shell profile (such as `~/.zshrc`) so every Claude Code session can use it:
63
-
64
- ```bash
65
- export TD_API_KEY="your_api_key"
66
- ```
67
-
68
- Open a new terminal, or run `source ~/.zshrc`, before you start Claude Code.
69
-
70
- </Step>
71
- <Step title="Install the plugin">
72
-
73
- TestDriver is a community plugin. In Claude Code, run `/plugin`, open the **Discover** tab, search for **TestDriver**, and install it.
44
+ If Claude replies with an upgrade link instead, your team's plan doesn't include sandbox sessions. Follow the link, then ask again.
74
45
 
75
- You can also install it from TestDriver's own marketplace:
76
-
77
- ```text
78
- /plugin marketplace add testdriverai/testdriverai
79
- /plugin install testdriver@testdriver
80
- ```
81
-
82
- </Step>
83
- <Step title="Check the connection">
84
-
85
- Run `/mcp` in Claude Code. The `testdriver` server should be listed as connected.
86
-
87
- If it isn't, check that `TD_API_KEY` is set in the terminal you started Claude Code from.
88
-
89
- </Step>
90
- <Step title="Write your first test">
91
-
92
- Ask for the TestDriver agent by name:
93
-
94
- ```text
95
- Use the testdriver agent to write a test that logs in to https://testdriver-sandbox.vercel.app/login and adds an item to the cart.
96
- ```
97
-
98
- The agent starts a sandbox and performs each step. It writes the code into a test file under `tests/`, then runs it with Vitest until it passes.
46
+ To save and run those tests locally and in CI, [set up a project](/quickstart-manual).
99
47
 
100
48
  </Step>
101
49
  </Steps>
@@ -17,7 +17,7 @@ There's nothing to install locally.
17
17
 
18
18
  - **A GitHub repository** where you can install apps (you own it, or you're an admin of its organization).
19
19
  - **A TestDriver account.** You create one or sign in during installation.
20
- - **A paid plan or trial for automatic reviews.** On the free plan, the agent still reviews a pull request when you @mention it. See [pricing](https://testdriver.ai/pricing).
20
+ - **A plan that includes automatic reviews.** Without one, the agent still reviews a pull request when you @mention it.
21
21
 
22
22
  <Steps>
23
23
  <Step title="Install the GitHub app">
@@ -43,7 +43,7 @@ npx vitest run
43
43
  <Steps>
44
44
  <Step title="Add your API key">
45
45
 
46
- Create an API key at [console.testdriver.ai/team/api-keys](https://console.testdriver.ai/team/api-keys). The free plan includes 30 testing minutes and needs no credit card.
46
+ Copy your API key from [console.testdriver.ai/team/api-keys](https://console.testdriver.ai/team/api-keys).
47
47
 
48
48
  Save the key in a `.env` file at your project root. The SDK loads it automatically:
49
49
 
@@ -142,7 +142,7 @@ To write tests with an AI assistant, add the TestDriver agent and MCP server to
142
142
  npx testdriverai init --client cursor,claude-code,vscode --no-sample-test
143
143
  ```
144
144
 
145
- Your existing config and tests stay as they are. For Claude Code or VS Code, you can use the [plugin](/quickstart-claude) or [extension](/quickstart-vscode) instead.
145
+ Your existing config and tests stay as they are. For Claude Code or VS Code, you can use the [connector](/quickstart-claude) or [extension](/quickstart-vscode) instead.
146
146
 
147
147
  ## Next steps
148
148
 
@@ -11,7 +11,7 @@ TestDriver writes and runs end-to-end tests for web apps, desktop apps, and brow
11
11
  Choose where you want to start:
12
12
 
13
13
  <CardGroup cols={1}>
14
- <Card title="Add to GitHub" icon="github" href="/quickstart-github" arrow horizontal>
14
+ <Card title="Add to GitHub" icon="github" href="/agent" arrow horizontal>
15
15
  An AI code reviewer that tests every pull request in a real sandbox.
16
16
  </Card>
17
17
  <Card title="Add Claude Connector" icon="/images/content/icons/claude.svg" href="/quickstart-claude" arrow horizontal>
@@ -28,7 +28,3 @@ Choose where you want to start:
28
28
  Not sure? Start with GitHub. Your next pull request gets a review without any setup.
29
29
 
30
30
  Set up via CLI when you want to write and run tests yourself.
31
-
32
- <Tip>
33
- Questions along the way? Ask in the [TestDriver Discord](https://discord.com/invite/cWDFW8DzPm).
34
- </Tip>
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "Self-hosted (Enterprise)"
3
3
  sidebarTitle: "Self-hosted"
4
- description: "Run TestDriver sandboxes on your own infrastructure for a flat license fee instead of testing minutes."
4
+ description: "Run TestDriver sandboxes on your own infrastructure instead of TestDriver's cloud."
5
5
  icon: "server"
6
6
  mode: "wide"
7
7
  ---
@@ -12,7 +12,6 @@ On the Enterprise plan, your tests run on machines in your own infrastructure in
12
12
 
13
13
  <EnterpriseCta feature="Self-hosting" />
14
14
 
15
- - You pay a flat license fee per parallel test, with no testing minutes to meter.
16
15
  - Your app and test data stay in your environment.
17
16
  - You use your own AI provider key and your own VM images.
18
17
 
@@ -74,21 +73,10 @@ Self-hosted sandboxes run in your account, so you can connect to a running insta
74
73
 
75
74
  For regulated environments, TestDriver can also deploy the API and console inside your network, on AWS, Azure, GCP, or on-premises. [Contact TestDriver](https://testdriver.ai/enterprise) to discuss it.
76
75
 
77
- ## Pricing
78
-
79
- - A flat monthly fee that includes 2 parallel tests and 5 seats.
80
- - Unlimited testing, with no per-minute fees.
81
- - Extra parallel licenses are $250 per month each. Extra seats are $100 per month each.
82
- - Setup help and support from TestDriver engineers in a shared Slack or Teams channel.
83
- - A 30-day pilot with a money-back guarantee.
84
-
85
- See [testdriver.ai/enterprise](https://testdriver.ai/enterprise) for current pricing and terms.
86
-
87
76
  ## Hosted or self-hosted
88
77
 
89
78
  | | Hosted | Self-hosted |
90
79
  | --- | --- | --- |
91
- | **Billing** | Testing minutes | Flat license fee |
92
80
  | **Sandboxes** | TestDriver's cloud | Your AWS account or machines |
93
81
  | **AI key** | TestDriver's | Your own Gemini key |
94
82
  | **VM images** | Standard | Your own |
@@ -25,8 +25,8 @@ The TestDriver VS Code extension is a powerful tool that integrates TestDriver's
25
25
 
26
26
  <Tip>
27
27
  The TestDriver VS Code Extension is currently in beta. If you encounter any
28
- issues or have feedback, please let us know [in
29
- Discord](https://discord.com/invite/cWDFW8DzPm)
28
+ issues or have feedback, please let us know [on
29
+ GitHub](https://github.com/testdriverai/testdriverai/issues)
30
30
  </Tip>
31
31
 
32
32
  <Steps>
@@ -30,14 +30,14 @@ Assertions use the current state of the page to determine if the step passes or
30
30
 
31
31
  ## Reporting issues
32
32
 
33
- If you encounter any issues while using TestDriver, please report them to us. You can do this by creating a new issue in the [discord](https://discord.com/invite/cWDFW8DzPm). We appreciate your feedback and will work to resolve any problems as quickly as possible.
33
+ If you encounter any issues while using TestDriver, please report them to us. You can do this by creating a new issue on [GitHub](https://github.com/testdriverai/testdriverai/issues). We appreciate your feedback and will work to resolve any problems as quickly as possible.
34
34
 
35
35
  <Card
36
36
  title="Report an Issue"
37
37
  icon="arrow-turn-down-right"
38
38
  iconType="duotone"
39
39
  horizontal
40
- href="https://discord.com/invite/cWDFW8DzPm"
40
+ href="https://github.com/testdriverai/testdriverai/issues"
41
41
  >
42
42
  We'd love to hear from you!
43
43
  </Card>
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  title: "What is TestDriver?"
3
+ sidebarTitle: "Introduction"
3
4
  description: "TestDriver tests apps by seeing the screen and controlling a real machine, without selectors."
4
5
  icon: "circle-info"
5
6
  ---
@@ -0,0 +1,24 @@
1
+ /**
2
+ * plan-gate.ts
3
+ *
4
+ * The hosted connector's paywall. Anyone can sign in and connect, but a team on
5
+ * the free plan can't start a sandbox: `session_start` returns an upgrade
6
+ * message with a checkout link instead. This mirrors the console, where a free
7
+ * team meets the same wall when it tries to reveal its API key.
8
+ *
9
+ * Only the hosted OAuth transport applies it. A local stdio server
10
+ * authenticates with an API key, which a team can only get once it has
11
+ * upgraded.
12
+ */
13
+ /** Where a free team goes to start a trial. Overridable for staging. */
14
+ export declare function upgradeUrl(): string;
15
+ /**
16
+ * Whether a team on `plan` must upgrade before starting a sandbox.
17
+ *
18
+ * `undefined` means the backend sent no plan at all (an older API, or a
19
+ * transport that never exchanged a token), so there is nothing to gate on. An
20
+ * empty or null plan is a brand-new signup, which is on free.
21
+ */
22
+ export declare function planNeedsUpgrade(plan: string | null | undefined): boolean;
23
+ /** The text the agent relays to the user in place of a sandbox. */
24
+ export declare function upgradeRequiredMessage(): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * plan-gate.ts
3
+ *
4
+ * The hosted connector's paywall. Anyone can sign in and connect, but a team on
5
+ * the free plan can't start a sandbox: `session_start` returns an upgrade
6
+ * message with a checkout link instead. This mirrors the console, where a free
7
+ * team meets the same wall when it tries to reveal its API key.
8
+ *
9
+ * Only the hosted OAuth transport applies it. A local stdio server
10
+ * authenticates with an API key, which a team can only get once it has
11
+ * upgraded.
12
+ */
13
+ /** Where a free team goes to start a trial. Overridable for staging. */
14
+ export function upgradeUrl() {
15
+ return (process.env.TD_MCP_UPGRADE_URL ||
16
+ "https://console.testdriver.ai/checkout/pro?source=mcp_connector");
17
+ }
18
+ /**
19
+ * Whether a team on `plan` must upgrade before starting a sandbox.
20
+ *
21
+ * `undefined` means the backend sent no plan at all (an older API, or a
22
+ * transport that never exchanged a token), so there is nothing to gate on. An
23
+ * empty or null plan is a brand-new signup, which is on free.
24
+ */
25
+ export function planNeedsUpgrade(plan) {
26
+ if (plan === undefined) {
27
+ return false;
28
+ }
29
+ return !plan || plan === "free";
30
+ }
31
+ /** The text the agent relays to the user in place of a sandbox. */
32
+ export function upgradeRequiredMessage() {
33
+ return ("UPGRADE REQUIRED: This TestDriver team is on the Free plan, which doesn't include sandbox sessions through the connector. " +
34
+ `Start a free trial of TestDriver Pro to continue: ${upgradeUrl()}\n\n` +
35
+ "Show the user this link and stop. Don't retry session_start until they confirm they've upgraded.");
36
+ }
@@ -26,6 +26,7 @@ import * as core from "./core/actions.js";
26
26
  import { NoActiveSessionError } from "./core/actions.js";
27
27
  import { resolveE2bTemplateId, resolveOs } from "./env-utils.js";
28
28
  import { authenticate, authorizationServerMetadata, authorizeRedirectUrl, isOAuthEnabled, protectedResourceMetadata, wwwAuthenticate } from "./http-auth.js";
29
+ import { planNeedsUpgrade, upgradeRequiredMessage, upgradeUrl } from "./plan-gate.js";
29
30
  import { SessionStartInputSchema } from "./provision-types.js";
30
31
  // =============================================================================
31
32
  // Sentry
@@ -567,6 +568,18 @@ Debug mode (connect to existing sandbox):
567
568
  }, async (params, extra) => {
568
569
  const startTime = Date.now();
569
570
  const progress = makeProgressReporter(extra);
571
+ // Hosted connector paywall: a free team can sign in and connect, but meets
572
+ // the upgrade wall here instead of getting a sandbox (see plan-gate.ts).
573
+ // `plan` is only set by the OAuth transport, so stdio is never gated.
574
+ const sessionPlan = core.getAdapterState().plan;
575
+ if (planNeedsUpgrade(sessionPlan)) {
576
+ logger.info("session_start: Blocked, team is on the free plan");
577
+ return createToolResult(false, upgradeRequiredMessage(), {
578
+ action: "session_start",
579
+ error: "UPGRADE_REQUIRED",
580
+ upgradeUrl: upgradeUrl(),
581
+ });
582
+ }
570
583
  // Resolve OS with priority: explicit param > TD_OS env var > "linux" default
571
584
  // This mirrors the behavior of the Vitest hooks (hooks.mjs) which also reads TD_OS
572
585
  const { os: resolvedOs, warning: osWarning } = resolveOs(params.os);
@@ -1746,7 +1759,7 @@ async function exchangeOAuthTokenForApiKey(token) {
1746
1759
  if (!data.apiKey) {
1747
1760
  return { ok: false, status: 403, error: "no_team", description: "No TestDriver team is linked to this account" };
1748
1761
  }
1749
- return { ok: true, apiKey: data.apiKey };
1762
+ return { ok: true, apiKey: data.apiKey, plan: data.identity ? data.identity.plan ?? null : undefined };
1750
1763
  }
1751
1764
  catch (error) {
1752
1765
  logger.error("http: exchange-oauth-token error", { error: String(error) });
@@ -1823,6 +1836,7 @@ async function startHttpServer() {
1823
1836
  // disabled this is a no-op so local/trusted-network usage is unchanged.
1824
1837
  let resolvedApiKey = null;
1825
1838
  let resolvedToken = null;
1839
+ let resolvedPlan;
1826
1840
  if (isOAuthEnabled()) {
1827
1841
  const auth = await authenticate(req);
1828
1842
  if (!auth.ok) {
@@ -1841,6 +1855,7 @@ async function startHttpServer() {
1841
1855
  return;
1842
1856
  }
1843
1857
  resolvedApiKey = exchange.apiKey;
1858
+ resolvedPlan = exchange.plan;
1844
1859
  }
1845
1860
  const sessionId = req.headers["mcp-session-id"];
1846
1861
  const sid = Array.isArray(sessionId) ? sessionId[0] : sessionId;
@@ -1848,6 +1863,11 @@ async function startHttpServer() {
1848
1863
  // transport a pre-parsed body). GET (SSE) and DELETE carry no JSON body.
1849
1864
  const body = req.method === "POST" ? await readJsonBody(req) : undefined;
1850
1865
  let connection = sid ? connections.get(sid) : undefined;
1866
+ // Refresh the plan on every request, so a team that upgrades mid-session
1867
+ // gets past the session_start paywall without reconnecting.
1868
+ if (connection && isOAuthEnabled()) {
1869
+ connection.ctx.adapter.plan = resolvedPlan;
1870
+ }
1851
1871
  // A brand-new session: only an `initialize` request may create one.
1852
1872
  if (!connection) {
1853
1873
  if (sid) {
@@ -1883,6 +1903,9 @@ async function startHttpServer() {
1883
1903
  if (resolvedToken) {
1884
1904
  ctx.adapter.oauthToken = resolvedToken;
1885
1905
  }
1906
+ if (isOAuthEnabled()) {
1907
+ ctx.adapter.plan = resolvedPlan;
1908
+ }
1886
1909
  const mcpServer = buildServer();
1887
1910
  const transport = new StreamableHTTPServerTransport({
1888
1911
  // Tag the owning machine into the id (multi-machine only) so later
@@ -0,0 +1,38 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { planNeedsUpgrade, upgradeRequiredMessage, upgradeUrl } from "./plan-gate.js";
3
+
4
+ afterEach(() => {
5
+ delete process.env.TD_MCP_UPGRADE_URL;
6
+ });
7
+
8
+ describe("planNeedsUpgrade", () => {
9
+ it("gates the free plan and a brand-new team with no plan set", () => {
10
+ expect(planNeedsUpgrade("free")).toBe(true);
11
+ expect(planNeedsUpgrade("")).toBe(true);
12
+ expect(planNeedsUpgrade(null)).toBe(true);
13
+ });
14
+
15
+ it("lets every other plan through", () => {
16
+ for (const plan of ["pro", "team", "enterprise", "oss", "github-team", "self-hosted"]) {
17
+ expect(planNeedsUpgrade(plan)).toBe(false);
18
+ }
19
+ });
20
+
21
+ it("does not gate when the backend reported no plan at all", () => {
22
+ expect(planNeedsUpgrade(undefined)).toBe(false);
23
+ });
24
+ });
25
+
26
+ describe("upgradeRequiredMessage", () => {
27
+ it("carries the checkout link", () => {
28
+ expect(upgradeRequiredMessage()).toContain(
29
+ "https://console.testdriver.ai/checkout/pro?source=mcp_connector",
30
+ );
31
+ });
32
+
33
+ it("honours the staging override", () => {
34
+ process.env.TD_MCP_UPGRADE_URL = "https://console-dev.testdriver.ai/checkout/pro";
35
+ expect(upgradeUrl()).toBe("https://console-dev.testdriver.ai/checkout/pro");
36
+ expect(upgradeRequiredMessage()).toContain("console-dev.testdriver.ai");
37
+ });
38
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * plan-gate.ts
3
+ *
4
+ * The hosted connector's paywall. Anyone can sign in and connect, but a team on
5
+ * the free plan can't start a sandbox: `session_start` returns an upgrade
6
+ * message with a checkout link instead. This mirrors the console, where a free
7
+ * team meets the same wall when it tries to reveal its API key.
8
+ *
9
+ * Only the hosted OAuth transport applies it. A local stdio server
10
+ * authenticates with an API key, which a team can only get once it has
11
+ * upgraded.
12
+ */
13
+
14
+ /** Where a free team goes to start a trial. Overridable for staging. */
15
+ export function upgradeUrl(): string {
16
+ return (
17
+ process.env.TD_MCP_UPGRADE_URL ||
18
+ "https://console.testdriver.ai/checkout/pro?source=mcp_connector"
19
+ );
20
+ }
21
+
22
+ /**
23
+ * Whether a team on `plan` must upgrade before starting a sandbox.
24
+ *
25
+ * `undefined` means the backend sent no plan at all (an older API, or a
26
+ * transport that never exchanged a token), so there is nothing to gate on. An
27
+ * empty or null plan is a brand-new signup, which is on free.
28
+ */
29
+ export function planNeedsUpgrade(plan: string | null | undefined): boolean {
30
+ if (plan === undefined) {
31
+ return false;
32
+ }
33
+ return !plan || plan === "free";
34
+ }
35
+
36
+ /** The text the agent relays to the user in place of a sandbox. */
37
+ export function upgradeRequiredMessage(): string {
38
+ return (
39
+ "UPGRADE REQUIRED: This TestDriver team is on the Free plan, which doesn't include sandbox sessions through the connector. " +
40
+ `Start a free trial of TestDriver Pro to continue: ${upgradeUrl()}\n\n` +
41
+ "Show the user this link and stop. Don't retry session_start until they confirm they've upgraded."
42
+ );
43
+ }
@@ -32,6 +32,7 @@ import * as core from "./core/actions.js";
32
32
  import { NoActiveSessionError, type ActionResult } from "./core/actions.js";
33
33
  import { resolveE2bTemplateId, resolveOs } from "./env-utils.js";
34
34
  import { authenticate, authorizationServerMetadata, authorizeRedirectUrl, isOAuthEnabled, protectedResourceMetadata, wwwAuthenticate } from "./http-auth.js";
35
+ import { planNeedsUpgrade, upgradeRequiredMessage, upgradeUrl } from "./plan-gate.js";
35
36
  import { SessionStartInputSchema, type SessionStartInput } from "./provision-types.js";
36
37
  import { type SessionState } from "./session.js";
37
38
 
@@ -733,6 +734,19 @@ Debug mode (connect to existing sandbox):
733
734
  const startTime = Date.now();
734
735
  const progress = makeProgressReporter(extra);
735
736
 
737
+ // Hosted connector paywall: a free team can sign in and connect, but meets
738
+ // the upgrade wall here instead of getting a sandbox (see plan-gate.ts).
739
+ // `plan` is only set by the OAuth transport, so stdio is never gated.
740
+ const sessionPlan = core.getAdapterState().plan as string | null | undefined;
741
+ if (planNeedsUpgrade(sessionPlan)) {
742
+ logger.info("session_start: Blocked, team is on the free plan");
743
+ return createToolResult(false, upgradeRequiredMessage(), {
744
+ action: "session_start",
745
+ error: "UPGRADE_REQUIRED",
746
+ upgradeUrl: upgradeUrl(),
747
+ });
748
+ }
749
+
736
750
  // Resolve OS with priority: explicit param > TD_OS env var > "linux" default
737
751
  // This mirrors the behavior of the Vitest hooks (hooks.mjs) which also reads TD_OS
738
752
  const { os: resolvedOs, warning: osWarning } = resolveOs(params.os);
@@ -2116,7 +2130,9 @@ function readJsonBody(req: http.IncomingMessage): Promise<unknown> {
2116
2130
  * catch-all `no_team`.
2117
2131
  */
2118
2132
  type ExchangeResult =
2119
- | { ok: true; apiKey: string }
2133
+ // `plan` is undefined when the backend sent no identity, null when the team
2134
+ // has no plan set yet (a brand-new signup, which is on free).
2135
+ | { ok: true; apiKey: string; plan: string | null | undefined }
2120
2136
  | { ok: false; status: number; error: string; description: string };
2121
2137
 
2122
2138
  async function exchangeOAuthTokenForApiKey(token: string): Promise<ExchangeResult> {
@@ -2146,11 +2162,11 @@ async function exchangeOAuthTokenForApiKey(token: string): Promise<ExchangeResul
2146
2162
  logger.warn("http: exchange-oauth-token failed", { status: resp.status, error, description });
2147
2163
  return { ok: false, status: resp.status, error, description };
2148
2164
  }
2149
- const data = (await resp.json()) as { apiKey?: string };
2165
+ const data = (await resp.json()) as { apiKey?: string; identity?: { plan?: string | null } };
2150
2166
  if (!data.apiKey) {
2151
2167
  return { ok: false, status: 403, error: "no_team", description: "No TestDriver team is linked to this account" };
2152
2168
  }
2153
- return { ok: true, apiKey: data.apiKey };
2169
+ return { ok: true, apiKey: data.apiKey, plan: data.identity ? data.identity.plan ?? null : undefined };
2154
2170
  } catch (error) {
2155
2171
  logger.error("http: exchange-oauth-token error", { error: String(error) });
2156
2172
  return { ok: false, status: 502, error: "exchange_unreachable", description: "Could not reach the TestDriver API to exchange the token" };
@@ -2241,6 +2257,7 @@ async function startHttpServer() {
2241
2257
  // disabled this is a no-op so local/trusted-network usage is unchanged.
2242
2258
  let resolvedApiKey: string | null = null;
2243
2259
  let resolvedToken: string | null = null;
2260
+ let resolvedPlan: string | null | undefined;
2244
2261
  if (isOAuthEnabled()) {
2245
2262
  const auth = await authenticate(req);
2246
2263
  if (!auth.ok) {
@@ -2259,6 +2276,7 @@ async function startHttpServer() {
2259
2276
  return;
2260
2277
  }
2261
2278
  resolvedApiKey = exchange.apiKey;
2279
+ resolvedPlan = exchange.plan;
2262
2280
  }
2263
2281
 
2264
2282
  const sessionId = req.headers["mcp-session-id"];
@@ -2270,6 +2288,12 @@ async function startHttpServer() {
2270
2288
 
2271
2289
  let connection: HttpConnection | undefined = sid ? connections.get(sid) : undefined;
2272
2290
 
2291
+ // Refresh the plan on every request, so a team that upgrades mid-session
2292
+ // gets past the session_start paywall without reconnecting.
2293
+ if (connection && isOAuthEnabled()) {
2294
+ connection.ctx.adapter.plan = resolvedPlan;
2295
+ }
2296
+
2273
2297
  // A brand-new session: only an `initialize` request may create one.
2274
2298
  if (!connection) {
2275
2299
  if (sid) {
@@ -2306,6 +2330,9 @@ async function startHttpServer() {
2306
2330
  if (resolvedToken) {
2307
2331
  ctx.adapter.oauthToken = resolvedToken;
2308
2332
  }
2333
+ if (isOAuthEnabled()) {
2334
+ ctx.adapter.plan = resolvedPlan;
2335
+ }
2309
2336
  const mcpServer = buildServer();
2310
2337
  const transport = new StreamableHTTPServerTransport({
2311
2338
  // Tag the owning machine into the id (multi-machine only) so later
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testdriverai",
3
- "version": "7.11.282-test",
3
+ "version": "7.11.283-test",
4
4
  "description": "Next generation autonomous AI agent for end-to-end testing of web & desktop",
5
5
  "main": "sdk.js",
6
6
  "types": "sdk.d.ts",