Skip to content
Local Drive

TestSprite

Run your first end-to-end test in five minutes, then the reference for everything else.

Local Drive's end-to-end tests run on TestSprite: a deployed server and a real browser, driven the way a person would drive them. It is one layer of the testing pyramid, and everything below it stays as it was. go test and flutter test are still the fast loop.

Recommended, never required. No account is needed to build, test or send a pull request, and CI does not run it.

One thing before you start. TestSprite drives a browser from the cloud, so the target has to be publicly reachable. The CLI rejects localhost and private addresses, so you need a deployment: a staging server, a preview, or your own instance on a domain.

Working on a laptop only? Skip to AI agents and MCP. The MCP server can reach a local app, which is the way round this.

Quick start

Five minutes, four steps. You need Node.js 20.19+, 22.13+ or 24+ (odd numbered releases are not supported), a TestSprite account, and a deployment holding nothing you would miss.

1. Install and sign in.

npm install -g @testsprite/testsprite-cli
testsprite setup

setup asks for your API key, which comes from the TestSprite dashboard under Settings, then API Keys. It stores it in ~/.testsprite/credentials and never touches this repository.

2. Point it at your deployment.

testsprite project create --type frontend --name "Local Drive web" \
  --url https://your-deployment.example
 
export TESTSPRITE_PROJECT_ID=prj_...

3. Run one test.

testsprite test create \
  --plan-from ./e2e/testsprite/frontend/01-sign-in-opens-the-file-list.plan.json \
  --run --wait --target-url https://your-deployment.example

Replace PROJECT_ID in that plan file with your own id first, or pass --project "$TESTSPRITE_PROJECT_ID".

4. Read what happened.

Exit 0 means it passed. If it did not:

testsprite test failure get <test-id> --out ./.testsprite/failure --failed-only

That writes the failing step, the DOM around it and a hypothesis. Then fix the application and run it again.

That is the whole loop. Everything below is reference.

How the loop works

The part worth internalising, because a test that was written and never run has verified nothing.

change ──▶ run the test ──▶ read the failure bundle ──▶ decide what is wrong
                 ▲                                              │
                 └──────────────── fix, then rerun ◀────────────┘

Deciding what is wrong is the step that matters, and it has three answers:

  • The application is wrong. Fix the application. This is the common case and the reason the layer exists.
  • The product changed on purpose. Update the plan to describe the new intended behaviour, in the same commit as the change that caused it.
  • The environment is wrong. A deployment that had not finished, a fixture account that was removed, a network fault. Fix the environment and run again; changing the test would hide it.

Never edit a test to make it pass. The intended behaviour is the source of truth, and a suite that is edited until it is green is worth less than no suite, because it still costs time to run and no longer tells anyone anything.

Why this layer exists

The layers below run against source. This one runs against a deployment, and the interesting failures are the ones no unit test can see: a control that moved, a screen that renders before its data arrives, a redirect that loops. Writing those as browser scripts produces a suite that breaks whenever a class name changes and gets deleted within a year.

TestSprite takes the workflow in sentences and drives the browser itself, so a test survives the refactor that renames the button. When one fails it returns a bundle: the failing step, the DOM around it, and a hypothesis. That is the part that makes a failure worth having.

It is a development dependency and nothing more. The server does not call it, the client does not know it exists. If this collaboration ended, e2e/testsprite/ would be deleted and nothing else in the repository would change.

CLI reference

The two projects

Local Drive has two, because it is two things:

Project Type Points at Covers
Local Drive web frontend The web client's public URL The workflows in e2e/testsprite/frontend/
Local Drive API backend The server's public URL The contracts in e2e/testsprite/backend/
testsprite project create --type frontend --name "Local Drive web" \
  --url https://your-deployment.example \
  --instruction "A self hosted file server. Sign in first; the file list is the main screen."
 
testsprite project create --type backend --name "Local Drive API"

Running the committed suite

The plans and API tests live in e2e/testsprite/. See its README for what each file covers.

What you want Command
Check the plans are valid, offline, no key testsprite test lint --plan-from-dir ./e2e/testsprite/frontend
Create and run every frontend workflow testsprite test create-batch --plan-from-dir ./e2e/testsprite/frontend --run --wait --target-url <url>
Create and run one backend contract testsprite test create --type backend --project "$TESTSPRITE_PROJECT_ID" --code-file ./e2e/testsprite/backend/<file>.py --run --wait --target-url <url>
Run everything already created testsprite test run --all --project "$TESTSPRITE_PROJECT_ID" --wait
Replay one after a fix testsprite test rerun <test-id> --wait
Score a test that fails intermittently testsprite test flaky <test-id>

--wait blocks until there is a verdict. --output json gives a machine readable envelope, which is what an agent or a script should read.

A frontend rerun replays the saved script and is free. A backend rerun dispatches the whole dependency closure, so producers and teardowns run too.

The linting one is worth knowing: it needs no key, no account and no network, so it is the check to run before opening a pull request that touches the suite.

Investigating a failure

Start with the triage card:

testsprite test result <test-id> --include-analysis

Then pull the bundle. It holds the failing step, the DOM around it, the test source and a root cause hypothesis, all anchored to one snapshot:

testsprite test failure get <test-id> --out ./.testsprite/failure

--failed-only trims it to the failing step and its neighbours, which is usually what you want when handing it to an agent. To pin an exact run rather than the latest failure, which matters when several run at once:

testsprite test artifact get <run-id> --out ./.testsprite/runs/<run-id>

.testsprite/ is ignored by git. A bundle contains screenshots of whatever was on screen, so it stays local.

AI agents and MCP

The agent skill

The mechanics are covered by TestSprite's own skill, which the CLI installs and keeps in step with its own version:

testsprite agent install --target claude

claude is the mature target. cursor, cline, windsurf, copilot, kiro, codex and antigravity are also supported. Run testsprite agent list for where each one lands, and testsprite agent status to check an installed skill is not stale.

Those generated files are ignored by git, so each contributor installs the ones for their own tool and no single editor's copy sits in the repository going out of date.

What is specific to this project, meaning when the layer is worth reaching for and what a failure means here, is in .ai/skills/verify-with-testsprite.md. Read that with AI agents.

The MCP server, and when to prefer it

The CLI is the primary interface. The MCP server is a second way in, aimed at an assistant working inside an editor, and it earns its place here for one reason: it can test an app that is only running locally, which the CLI cannot. For a self hosted project where the normal state of a change is "running on my laptop", it is often the only interface that can verify anything at all.

claude mcp add TestSprite --env API_KEY=your_api_key -- npx @testsprite/testsprite-mcp@latest

Cursor, Trae, Windsurf, VS Code and GitHub Copilot are also supported; they take the same package in their own MCP settings, with API_KEY in the environment. See TestSprite's MCP installation guide for each client's exact configuration, and the tool reference for what it exposes.

Situation Use
Change is deployed somewhere public The CLI
Change is only running locally The MCP
Running the committed suite in e2e/testsprite/ The CLI
Exploring what a new area should even test The MCP
Scripting, or anything that needs an exit code The CLI

The MCP writes testsprite_tests/ into the working directory, including generated cases, reports, a standard_prd.json and a tmp/ holding config.json, code_summary.json and test_results.json. Some of that carries an API key and a map of the codebase, so the whole tree is ignored here. See Security.

The Web Portal is the third piece and holds the account: keys, project credentials, the credit balance, and the dashboard a run links back to. Some settings exist only there, and this repository does not try to reproduce them.

Advanced configuration

Where the API key lives

The key is never committed, never pasted into a file in this repository, and never printed into a log. Nothing here reads it; the CLI finds it itself.

Where How
Your machine testsprite setup writes ~/.testsprite/credentials, mode 0600
A shell, one off TESTSPRITE_API_KEY=… in the environment
A pipeline A secret named TESTSPRITE_API_KEY
More than one account Profiles: --profile <name>, or TESTSPRITE_PROFILE

To configure credentials without installing the agent skills:

testsprite setup --no-agent

Running it from a pipeline

There is no TestSprite job in this repository's CI, deliberately. Runs cost credits and need a deployment to point at, so they happen when somebody decides they are worth it rather than on every push.

If you wire it into a pipeline of your own, the exit code is the contract:

Code Meaning
0 Passed
1 Failed, blocked or cancelled
3 Auth: key missing, revoked, or the wrong scope
5 Validation: a bad field, or a missing flag
7 Timed out. Inconclusive rather than a regression; resume with test wait
11 Rate limited. Honour Retry-After
12 Out of credits
14 The CLI is too old for the backend

Treat 7 as inconclusive rather than red. The plan lint needs no key and no network, which is the part worth automating first.

Troubleshooting

localhost is rejected. Working as intended. Use a deployment, or the MCP server for a local app.

auth status fails. Run testsprite setup, or export TESTSPRITE_API_KEY. testsprite doctor says which part is missing.

A frontend test passes but asserts nothing useful. Usually a step that says "verify the page loads". Assert the thing that would be wrong if the feature broke: a specific name in the listing, not visibility of a container.

A test fails only sometimes. Score it before trusting it: testsprite test flaky <test-id>. A plan that depends on state left by an earlier run is the usual cause.

A run timed out (exit 7). The run is still going server side. Resume with testsprite test wait <run-id> rather than triggering a second one.

Security

Nothing either tool generates is committed. Only the files written by hand in e2e/testsprite/ are tracked. Everything below is ignored, and the rules are deliberately broader than the paths in use today, because a key cannot be un-leaked:

Path Why it stays out
testsprite_tests/ Written by the MCP. Holds generated cases and reports
testsprite_tests/tmp/config.json Can carry the API key
testsprite_tests/tmp/code_summary.json A map of the codebase
testsprite_tests/standard_prd.json Describes behaviour that may be unreleased
.testsprite/ CLI state, and failure bundles
.testsprite/failure/, .testsprite/runs/ Screenshots and DOM snapshots of the account the run used
TC001_*.py and siblings Generated test cases
.claude/skills/testsprite-*/ and the equivalents Generated agent skills, one per editor

If you need to share a generated artifact, force add it deliberately after reading it. The default is out.

The rest:

  • No key, token or password is committed anywhere. Placeholders only.
  • Backend tests read the injected credential block and never hardcode one. A hardcoded token expires and cannot be rotated, and test create warns when it sees one.
  • Tests run against a dedicated account on a deployment holding nothing anyone would miss. The frontend plans create folders, rename files and use the trash.
  • Never point this suite at a server holding real files. A run uploads, renames and trashes things, and a failure bundle photographs whatever was on screen.
  • Testing sends the application under test to a third party service. Treat that as you would any hosted tool, and read TestSprite's own documentation for what it retains.

Keeping this current

TestSprite is moving quickly, so this page holds Local Drive's own workflow and links out for anything that changes underneath it. Commands here were verified against the CLI and the official documentation on 2026-08-11, with @testsprite/testsprite-cli v0.5.0 on Node 24.

If something no longer matches, TestSprite's documentation wins:

testsprite --version
testsprite doctor
testsprite --help

The CLI reference and llms.txt are the sources to check against. Update the verification date above when you do.