# Assertions

`assert condition` fails the test when the condition is false. On failure,
the report shows the file, the line, the source of the condition, and the
value of each side of a comparison.

## Checking that a call fails

To check that a call fails, name the failure with `fails`:

```jadpo
test "completing a missing todo fails" {
    var alice: Principal.user = alice_with_todos()
    var missing: Todo.id = "01908f6e-1c2a-7b3c-9d4e-5f6a7b8c9d0e"
    assert complete_todo(missing, alice) fails TodoNotFound
}
```

`assert … fails` checks the call itself. A failure that leaves while the
call's arguments are worked out ends the test, like any other unhandled
failure.

## Calls that can fail

A call that can fail still needs `attempt`, `match` or `assert … fails`,
as everywhere else
([Passing a failure on: `attempt`](passing-a-failure-on-attempt.md)).
A call with `attempt` that fails ends the test as failed, and names the
failure.

## Comparing values

Whole values are compared with `==`. On failure, records and lists show a
field-by-field diff. A route test checks `response.status`,
`response.code` and the typed output ([Route tests](kinds-of-test.md#route-tests)).

There are no snapshot assertions, and no mocks of your own code.

## Events and query cost

`assert emitted ReminderDue { todo_id: todo.id }` checks that an event
was emitted, as the fakes' `.requests` checks provider calls. It isn't
built yet.

A test doesn't assert what a query costs. The compiler reports each
query's cost in the build report, and a change shows in the approval
review.

## What a failed test reports

A failed test gives a person or an agent everything needed to fix it
without rerunning it, the same standard as the application's own
[failures](failures.md). It is shown readably in a terminal, and as
versioned JSON with `--json`:

```text
FAIL  a rate-limited reminder is retried
      domains/planning/schedules/overdue_reminders.test.jadpo:31

  assert list.count(sent) == 2
         │                │
         1                [ReminderMessage { to: "alice@example.test", todo_title: "Buy milk", ... }]

  expected  2
  actual    1

  what ran (trace t-7f3a, clock 2026-01-15T12:00:00Z, order seed 48213):
    overdue_reminders.run()                         2 todos due
      queue_overdue_reminders()                     committed: 2 Todo updated, 2 ReminderDue emitted
    send_reminder (ReminderDue todo=01908f6e…)      reminders.messages.send → rate_limited → retry
    send_reminder (ReminderDue todo=01908f6e…)      retry scheduled for 12:00:02, not yet due
    send_reminder (ReminderDue todo=7c21d0aa…)      reminders.messages.send → accepted

  fakes:  reminders.messages.send   2 scripted, 2 used
  data:   kept as jadpo_test_7f3a (--keep-failed)
  rerun:  jadpo test domains/planning/schedules/overdue_reminders.test.jadpo:31 --seed 48213
```

- **The assertion broken into parts:** every sub-expression's value, with
  records compared field by field in a diff.
- **For `assert … fails X`:** the failure that happened instead, with its
  internal fields, or the value the call returned.
- **What ran:** the test's trace in short
  ([Debugging and review](debugging-and-review.md)): actions, queries,
  writes, events delivered or pending, retries, and provider calls with
  what was sent and answered.
- **How to reproduce it:** the clock, the order seed, configuration
  overrides, fake usage, the kept database and the exact rerun command.
- Every failure has a stable code (`test.assertion_failed`,
  `test.fake_unused`, `test.fake_exhausted`, `test.unexpected_failure`,
  `test.fault` for a fault such as an overflow, and
  `test.subscriber_failed` for a subscriber's delivery that failed for
  good between the test's steps) so an agent can act on it
  without parsing text. Each is shown with its real report under
  [Errors](testing.md#errors).

### As JSON

`jadpo test --json` prints one document in the envelope every command
shares (`schemaVersion` 2, `command`, `ok`, `data`, `diagnostics`), and
`jadpo help --json` describes every field under `testReport`. `data` holds the order `seed`; `root`, the project folder as
seen from where the command ran (`"."` from inside it), which every path is
relative to; the `selection`; the `counts`; and the `tests` in the order
they ran. A failed test's `failure` has its `code` and `help`, its
`location` in the test, one of `assertion`, `failure` or `fault`, for
`test.subscriber_failed` the `delivery` it happened in (its `event`,
`subscriber`, `attempt` and `attempts`, `null` otherwise), and the
`rerun` command, which works from where the command ran. Part of the
document for the `test.fault` example under [Errors](testing.md#errors):

```json
{
  "code": "test.fault",
  "location": { "path": "plans.test.jadpo", "start": 93, "end": 117, "line": 3, "column": 12, "endLine": 3, "endColumn": 36, "label": "" },
  "fault": {
    "kind": "int_overflow",
    "at": { "path": "plans.jadpo", "start": 118, "end": 134, "line": 6, "column": 19, "endLine": 6, "endColumn": 35, "label": "out of range" },
    "stack": [
      { "location": { "path": "plans.jadpo", "start": 118, "end": 134, "line": 6, "column": 19, "endLine": 6, "endColumn": 35, "label": "" }, "callable": "function plan_effort", "repeats": 1 },
      { "location": { "path": "plans.test.jadpo", "start": 93, "end": 117, "line": 3, "column": 12, "endLine": 3, "endColumn": 36, "label": "" }, "callable": "test \"a long plan still adds up\"", "repeats": 1 }
    ]
  },
  "rerun": "jadpo test plans.test.jadpo:3 --seed 1"
}
```

Every location, a test's, a failure's `at`, a stack frame's and a
diagnostic's, has the one shape `path`, `start`, `end`, `line`, `column`,
`endLine`, `endColumn`, `label`. A stack frame is `{ location, callable,
repeats }`, a recursion counted once. A project with errors runs nothing:
`data` is `{ ran: false, root, fileCount, errors, warnings }` and the errors
are the diagnostics. `--failed` with nothing to rerun gives `{ selection,
gone, tests: [] }`, where `gone` counts the tests that failed last time and
are no longer in the project. `--watch --json` writes one document per
line, its `data` with a `watch` object (`event`, `changed`, `reached`,
`failing`, `files`, `fixed`).
