unotest connects your editor’s AI agent to your real application through an MCP server, and turns what the agent does into a reviewable test.
The loop
- You describe a flow in plain English to your agent.
- The agent explores your live app through ~37 MCP tools — reading a semantic snapshot, clicking, filling, recording each action.
- It writes a scenario to
unotest/e2e/<name>.jswith stable selectors andstep("intent", …)labels. - It runs the scenario through the sandboxed engine and, on failure, pauses to inspect, patch and resume.
- You review and commit the
.js.
Semantic perception, not pixels
The agent doesn’t look at screenshots. It reads a semantic snapshot of the page (web) or the accessibility tree (iOS) — roles, names, labels, test IDs, rendered as a token-cheap text outline. This is cheaper, more reliable, and stable across visual redesigns.
A sandboxed engine
Scenarios are plain JavaScript, but they don’t run in Node. They execute in a
sandboxed AST interpreter — no require, no fetch, no filesystem, no
network except the typed apiCall helper. That’s why AI-generated tests are
safe to run blindly.
Stable by construction
Selectors follow a strict priority — getByTestId → getByRole → getByLabel → getByText → locator(css) — and the linter flags brittle patterns. Tests survive
refactors because they target meaning, not markup.
Local-first
The MCP server, the browser/Simulator, the runner and the viewer all run on your machine. Your app never leaves it. No cloud, no account.
The ecosystem
| Package | Role |
|---|---|
@unotest/web | CLI · MCP server · runner (web) |
@unotest/mobile | CLI · MCP server · runner (iOS) |
@unotest/viewer | local results browser |
@unotest/dsl | scenario parser + validator |
@unotest/protocol | shared types |