> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ancha.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These docs describe the Ancha CLI, npm package @ancha-labs/cli, and the hosted workspace at app.ancha.io. Coding agents should start at https://docs.ancha.io/coding-agents. Run the CLI as `ancha` after `npm install -g @ancha-labs/cli`, or as `npx -y @ancha-labs/cli` without installing. Pass --json for machine-readable output, or set ANCHA_JSON=1. Every command ends with a `next:` line naming the next command. Exit codes: 0 pass, 1 a check failed or a comparison regressed, 2 usage, config or authentication error, 3 infrastructure error, 4 unimplemented endpoint with --strict.

# Test with pytest

> Start a fresh world for a Python test, keep your agent on your machine, and save the result as an Ancha run.

The `pytest-ancha` plugin gives each test a `world` fixture and records each executed test as a local run. Python code uses `import ancha`.

## Install the plugin

The package is not published on PyPI. Install a supplied wheel in the Python environment where you run pytest:

```bash theme={null}
python -m pip install ./pytest_ancha-0.1.0-py3-none-any.whl
```

The plugin loads automatically. Use Ancha CLI 0.1.5 or later for `world capture` and `world record`. `ANCHA_CLI` can name another CLI command.

## Write a test

Use a scene file containing the tools, starter data and checks for your agent. Run pytest from the project directory:

```python theme={null}
import pytest

@pytest.mark.ancha(scene="scenes/support-reply/scene.yaml")
def test_support_reply(world):
    world.start("python agent.py")
    assert world.wait_until_quiet(timeout=60) == 0
    assert world.check()
```

`world.start` gives the process the world's tool URLs and fake credentials. Your agent runs on your computer. `wait_until_quiet` waits for that process to exit; its timeout is in real seconds. The fixture stops any remaining process, records a world observation and removes the world after the test.

The marker accepts `scene`, `test` (an alias for `scene`), `world` (a saved world ID), `on`, `seed` and `ttl`. Without a scene or saved world, the fixture uses the single scene named in `ancha.yaml`.

`world.check()` returns a report. A failed check makes the report false. Invalid checks, unknown references and CLI failures raise `ancha.AnchaError`, with `code`, `message` and optional `hint`. A false check does not fail pytest until you assert it:

```python theme={null}
assert not world.check({"id": "no_reply", "trace": {"called": "* /api/chat.postMessage"}})
```

This assertion passes when the agent did not call `chat.postMessage`. The recorded run preserves the observed check without turning it into a required passing check.

## Choose where the world runs

```bash theme={null}
python -m pytest --on local
python -m pytest --on cloud
```

`--on cloud` uses the hosted workspace selected by the CLI. Sign in with `ancha login` first, or configure a server URL and API key. The world runs there; pytest and the agent stay on your computer. Run files also stay on your computer.

The pytest `--on` option overrides the marker's `on`. Without it, the marker wins. With neither, the CLI's normal world selection applies: login alone keeps worlds local; an explicit server URL can select another server. `--on local` forces local worlds.

## Repeat attempts

```python theme={null}
import ancha
import pytest

@pytest.mark.ancha(scene="scenes/support-reply/scene.yaml")
@ancha.attempts(3, min_pass_rate=2 / 3)
def test_support_reply(world):
    world.start("python agent.py")
    assert world.wait_until_quiet(timeout=60) == 0
    assert world.check()
```

Each attempt starts with a fresh world. A failed assertion counts as a failed attempt. The test passes when its pass rate meets the threshold. Setup, capture and cleanup errors remain infrastructure failures; they do not count as failed agent answers.

## Read the saved run

Each executed pytest item produces a run under `.ancha/runs/`, with `source: pytest` and `target: local`. Parameterized cases are separate runs; parameter values are replaced by a hash in the recorded test ID. Tests without a world also get a record. `--collect-only` creates none.

```bash theme={null}
ancha --local runs list --json
ancha --local runs show <run-id> --json
ancha --local explain <run-id> --json
```

The record contains pytest phase outcomes, each attempt and its available world state, trace and check observations. Pytest assertions determine the result. Skips and expected failures stay ungraded. A world capture or cleanup failure makes the affected attempt invalid. The record preserves a passing call followed by a failing teardown as separate phase results.

The plugin does not save environment values, raw exception messages, captured test output or agent logs. Keep `.ancha/` out of version control. Uploading pytest records is not supported; they remain local.


## Related topics

- [Tests](https://docs.ancha.io/concepts/tests.md)
- [ancha schema](https://docs.ancha.io/cli/schema.md)
- [ancha test](https://docs.ancha.io/cli/test.md)
- [World lifecycle](https://docs.ancha.io/cli/world-lifecycle.md)
- [Test a Slack bot](https://docs.ancha.io/guides/test-a-slack-bot.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.