---
title: Assertions
description: Fail the attempt when the agent's work misses an assertion.
---
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reeval.ai/llms.txt
> Use this file to discover all available pages before exploring further.

You call `expect` in the evaluation body. A failing assertion fails the attempt. For more information about how an assertion becomes an outcome, see [Assertion](/reference/glossary#assertion). For more information about scoring the reply with a model, see [Judgments](/evaluations/grading/judgments).

## Check a file the agent wrote

`toHaveFile` reads a file in the sandbox. Await it. The second argument to `expect` is the label in the result. The `camelcase` environment is the one from [Evaluate](/evaluations/evaluate).

In the `evals/camelcase.eval.ts` file, send the task and check that the readme documents the option:

```ts title="evals/camelcase.eval.ts"
evaluate('adds a separators option', { environment: camelcase }, async (c) => {
  await c.send(
    'Add a separators option to camelCase: a string of extra characters ' +
      "that also separate words, so camelCase('foo/bar', {separators: '/'}) " +
      "is 'fooBar'. Add tests to test.js and document it in readme.md. " +
      'Run the tests with node --test.',
  )

  await expect(c).toHaveFile('readme.md', /separators/)
})
```

Without a label, the row reads `toHaveFile readme.md`. `c.readFile` returns the file text, or `null` when the path is missing:

```ts title="with-soft-checks.eval.ts"
expect
  .soft(await c.readFile('test/math.test.js'), 'tests divide')
  .toContain('divide(')
```

## Run the project's tests

`c.exec` runs a command in the sandbox and returns `exitCode`, `stdout`, and `stderr`. `toSucceed` passes when `exitCode` is 0. Await it.

In the `evals/camelcase.eval.ts` file, run the repository's tests, then write a hidden test the prompt never mentions and run it:

```ts title="evals/camelcase.eval.ts"
  await expect(c.exec('node --test'), "the repo's tests pass").toSucceed()
  await c.writeFile('separators.test.js', hidden)
  await expect(
    c.exec('node --test separators.test.js'),
    'the option works',
  ).toSucceed()
```

For more information about `c.exec`, see [the `c.exec` method](/reference/attempt-context#cexec). For a runnable project, see [`with-existing-codebase`](https://github.com/invertase/reeval/tree/main/examples/with-existing-codebase).

## Check what the agent did

`toHaveEdited` checks file edits in the transcript. `toHaveRun` checks shell commands the harness ran. Pass `c` or the turn that `c.send` returns:

```ts title="with-transcript-matchers.eval.ts"
expect(turn, 'edited math.js').toHaveEdited('src/math.js')
expect(turn, 'ran the tests').toHaveRun(/node --test|npm (test|t)\b/)
expect(turn, 'installed nothing').not.toHaveRun(/npm (install|i)\b/)
```

`toHaveCalledTool`, `toHaveCalledMcp`, and `toHaveCalledSkill` read the same transcript. For a runnable project, see [`with-transcript-matchers`](https://github.com/invertase/reeval/tree/main/examples/with-transcript-matchers).

`toHaveSearched` and `toHaveFetched` throw `HarnessCapabilityError` when the harness does not report web searches or web fetches.

## Use soft and polled assertions

`expect.soft` records a failure and runs the later assertions. The attempt fails at the end on the first soft assertion that did not pass. In the `evals/camelcase.eval.ts` file, make both file assertions soft, so each attempt reports both:

```ts title="evals/camelcase.eval.ts"
await expect.soft(c, 'readme documents it').toHaveFile('readme.md', /separators/)
await expect.soft(c, 'tests cover it').toHaveFile('test.js', /separators/)
```

`expect.poll` calls a function until the matcher passes, every 50 milliseconds, for at most 1000 milliseconds. It then fails with the last error. Await it. Pass `{ interval, timeout }` in milliseconds to change the wait. `message` sets the label:

```ts
await expect.poll(() => c, { timeout: 5000 }).toHaveFile('readme.md')
```

## Troubleshooting

Match the attempt error to a fix:

| Symptom | Check | Next action |
|---|---|---|
| `expected file readme.md to exist` | `toHaveFile` found no file at that path. | Use the path the prompt names. |
| `expected command to succeed, exit code 1` | `exitCode` was not 0. The message includes the tail of `stderr` and `stdout`. | Read that tail, then change the command or the task. |
| `expect(…).toHaveFile() wasn't awaited` | An async matcher ran without `await`. | Put `await` before `toHaveFile`, `toSucceed`, or `expect.poll`. |
| `toHaveSearched() can't check this turn: its harness doesn't report web searches` | The matcher threw `HarnessCapabilityError`. | Check the reply or a file, or use a harness that reports web searches. |
| `toHaveEdited() expects a turn from c.send(), or c` | The matcher did not receive `c` or a turn. | Pass `c` or the turn that `c.send` returned. |

## Reference

For more information about every matcher, `expect.soft`, and `expect.poll`, see [Matchers](/reference/matchers).
