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

# Test rules in plain English

> Define API assertions in plain English or manually so scenarios know what pass and fail mean.

# Test rules in plain English

Test rules are the assertions that decide whether an API scenario passed.

You can let Qodex generate rules from plain English, or write the structured assertion yourself when the check needs to be exact.

## How rules differ from scenario steps

A step is what the test does. A rule is what the test expects to see.

| Layer    | Purpose                          | Example                                                                |
| -------- | -------------------------------- | ---------------------------------------------------------------------- |
| **Step** | Performs an HTTP action          | `POST /users` with body `{ email, name }`                              |
| **Rule** | Asserts a property of the result | `status equals 201`, `body.id exists`, `body.email equals input email` |

A single step can carry many rules. A scenario passes only when every step's rules evaluate true.

Rules persist on the step as `expectations[]`, each one a structured assertion:

```json theme={null}
{
  "expectations": [
    { "kind": "status", "equals": 201 },
    { "kind": "jsonpath", "path": "$.id", "exists": true },
    { "kind": "jsonpath", "path": "$.email", "equals": "${INPUT_EMAIL}" },
    { "kind": "header", "name": "content-type", "contains": "application/json" }
  ]
}
```

The structured shape is what the runner evaluates. Plain English is one way to author that structure.

## Writing rules in plain English

When you ask the agent to author a scenario, it generates rules based on the endpoint's response schema and common validation patterns. You see them in the **Suggested rules** panel on the step.

Common auto-generated rules:

* "Status code should be 200."
* "Response body should contain `user_id`."
* "Field `email` should match the input email."
* "Error message should appear when email is missing."

To add your own rule on top, type it in:

```text theme={null}
The created order should have a total that matches the
sum of the items' prices times their quantities.
```

Qodex converts that to a structured assertion, saves it on the step, and shows the generated JavaScript so you can verify the conversion.

## Writing rules manually

When the English-to-assertion conversion is not sharp enough, write the assertion directly. Open the step, go to the **Write** tab, and pick a rule kind:

* **Status**: `equals`, `in [200, 201, 204]`, `notEquals`.
* **JSONPath**: `exists`, `equals`, `notEquals`, `contains`, `matches`, `lengthEquals`, `lengthGreaterThan`.
* **Header**: `equals`, `contains`, `matches`, `exists` on the header name (case-insensitive).
* **Body shape**: validate the response body against a JSON Schema or a TypeScript-style shape.
* **Custom JavaScript**: a free-form expression that returns truthy for pass, falsy for fail.

Custom JavaScript has access to the response context:

```javascript theme={null}
// step.expectations[].kind = "custom"
current_status_code === 201 &&
current_response_body.email === current_request_body.email &&
typeof current_response_body.id === "string" &&
current_response_body.id.length > 0
```

Available identifiers:

* `current_status_code`, `current_response_body`, `current_response_headers`.
* `current_request_body`, `current_request_headers`.
* `${var}` interpolation happens before the expression evaluates, so captures and environment variables work.

## When to do which

| Use plain English when...                                         | Use JavaScript when...                                 |
| ----------------------------------------------------------------- | ------------------------------------------------------ |
| The check is a common pattern (status, field existence, equality) | The check requires a computation over the response     |
| You want the agent to author and maintain the rule                | The rule depends on multiple fields or an array reduce |
| You're prototyping a new scenario                                 | You're hand-tuning an established scenario             |

In practice, let the agent draft and hand-edit the rules where it matters. The agent is fast at shape, such as status and JSONPath checks. Humans are better at business invariants, such as totals matching or audit trails being complete.

## What runs at execution time

The runner evaluates `expectations[]` on every step. A failing expectation:

* Marks the step `fail`.
* Captures the expected and actual values into the test run record.
* Surfaces in the per-step breakdown in the Test Runs view.

A failing scenario then enters the failure-classification pipeline (real bug vs stale test vs environment issue) on the next run.

## On the roadmap

<Tip>
  An assertion DSL with operator dropdown lands as part of API Playground phase 2. Database-validation rules (run a SQL query after the API step, compare the row to the expected state) are in active design. The current `expectations[]` shape will stay as the persistent format; the new DSL is sugar on top.
</Tip>

## Related

<CardGroup cols={2}>
  <Card title="Scenarios" icon="list-checks" href="/api-testing-scenarios">
    The structure that carries rules.
  </Card>

  <Card title="Auto-verification on save" icon="circle-check" href="/api-testing-auto-verification">
    Rules run the moment you save.
  </Card>

  <Card title="Request data generation" icon="sparkles" href="/api-testing-request-data-generation">
    The data that rules evaluate against.
  </Card>

  <Card title="Findings" icon="bug" href="/findings">
    What happens when a rule fails on an active scenario.
  </Card>
</CardGroup>
