Your agent writes the E2E tests.
You review and commit.
unotest is AI-native end-to-end testing. Your AI agent drives your real app over MCP and writes clean, reviewable tests in your repo — for web and for iOS.
Works with Claude Code · Cursor · Codex
unotest web
E2E for web apps. Playwright-vocabulary DSL on a sandboxed engine, driven by your agent over MCP.
unotest mobile
E2E for iOS apps (React Native + native Swift). The agent drives the Simulator through the accessibility tree.
Full control
AI does the work. You keep control.
The whole point: speed from the agent, ownership stays with you.
Plain .js in your repo
Tests are ordinary JavaScript in unotest/e2e/*.js. Git, code review, CI — no proprietary format, no binary blob.
No silent fixes
agent_fix composes context and a suggestion — it never calls an LLM itself and never applies a patch on its own. You read the diff and commit.
Runs locally
Everything runs on your machine. Your app never leaves it. No cloud, no account to start.
Safe to run blindly
Scenarios execute in a sandboxed AST interpreter — no require, no fetch, no filesystem. AI-generated tests can run without surprises.
What's new
unotest 0.40.0
Released 19 September 2026.
A box that is ready says so
Renting a box takes minutes, and it used to end in silence — close the tab and you learned nothing: not that the machine was up, not where it answers. The service now writes to the address on the account the moment the box is ready. The letter names the box, points at the card where its login stays readable, and gives the commands that put a suite on it. A box deleted by hand writes too, and says which deletion happened.
Your boxes, before a second one is rented
Run in a directory that does not know a box — a fresh checkout, a second project — the box commands used to answer with three things to try, and the easiest of them rented another box. They now ask the account first: with one box they name it and hand the command back ready to run, with several they list them.
One name for an environment, everywhere
The name that ordered a run and the name that reads its results are the same name at last: both halves take the bare environment and the full project/environment, and translate between them against the box's own list. A name the box does not serve is refused before the bundle is uploaded, not after, and the refusal names what it does serve — with a command you can run rather than a description.