# Introduction

> For the complete documentation index, see [llms.txt](/llms.txt)

**unotest is AI-native end-to-end testing.** You don't write the tests — your
AI agent does, by driving your real app through an MCP server. You review the
result and commit it.

It's not a black box. Everything the agent does ends up as ordinary,
human-readable `.js` in your repository, with stable selectors and plain-English
step labels. You can open it, understand it, and rewrite it by hand at any time.

**AI does the work. You keep control.**

## Two surfaces, one idea

| | **unotest web** | **unotest mobile** |
| --- | --- | --- |
| Target | Web apps | iOS apps (React Native + native Swift) |
| Engine | Playwright / Chromium | WebDriverAgent / XCUI |
| Perception | semantic DOM snapshots | accessibility tree |
| Runs on | any OS | macOS only (Apple licensing) |

Both share the same DNA: an MCP server, a sandboxed JavaScript DSL, plain `.js`
tests in your repo, a pause-on-failure debugger, and local-first execution.

## Why it's different

- **The agent perceives structure, not pixels.** It reads a semantic snapshot
  (roles, labels, test IDs) — cheap on tokens and stable across redesigns.
- **Stable selectors by default.** `getByTestId → getByRole → getByLabel →
  getByText → locator(css)`. The linter steers away from brittle CSS.
- **Self-healing, with you in the loop.** A failing step pauses mid-run; the
  agent inspects, patches and resumes. `agent_fix` never calls an LLM itself and
  never applies a patch silently — you approve the diff.
- **Safe to run blindly.** Scenarios execute in a sandboxed AST interpreter — no
  `require`, no `fetch`, no filesystem.
- **Local-first.** Everything runs on your machine. No cloud, no account.

## Next

- [Quick start — web](/start/quickstart-web/)
- [Quick start — iOS](/start/quickstart-ios/)
- [How it works](/start/how-it-works/)
