# jest/valid-expect

> Require `expect` to get a value, end in a called matcher, and be awaited when it is async

`expect(value)` doesn't check anything by itself. The check happens when you call a matcher such as `.toBe()`, so an `expect` with no matcher, or with a matcher that isn't called, passes no matter what the value is.

`.resolves` and `.rejects` make the matcher return a promise. If the test doesn't await or return it, the test ends first, and a failed assertion doesn't fail the test.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"jest/valid-expect" = "error" # or "warn"
```

Every option, set to its default:

```toml bunfig.toml
[lint.rules]
"jest/valid-expect" = ["error", {
  alwaysAwait = false,
  asyncMatchers = ["toResolve", "toReject"],
  minArgs = 1,
  maxArgs = 1,
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 5} */}
```ts
import { expect, test } from "@jest/globals";

test("adds the tax", () => {
  expect(total(100)); // no matcher
  expect(total(100)).toBe; // the matcher is not called
  expect().toBe(108); // no value
  expect(total(100), "after tax").toBe(108); // more than one argument
  expect(total(100)).never.toBe(0); // `never` is not a modifier
});
```

{/* bad */}
```ts
import { expect, test } from "@jest/globals";

test("loads the user", () => {
  expect(loadUser(1)).resolves.toEqual({ id: 1 });
});
```

Not reported:

{/* good */}
```ts
import { expect, test } from "@jest/globals";

test("adds the tax", () => {
  expect(total(100)).toBe(108);
  expect(total(100)).not.toBe(0);
});

test("loads the user", async () => {
  await expect(loadUser(1)).resolves.toEqual({ id: 1 });
});

test("rejects an unknown id", () => {
  return expect(loadUser(-1)).rejects.toThrow("not found");
});
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `alwaysAwait` | `false` | Also report an async assertion that's returned instead of awaited. |
| `asyncMatchers` | `["toResolve", "toReject"]` | Matchers that return a promise, so you need to await or return them. Your list replaces the default. |
| `minArgs` | `1` | The fewest arguments `expect` can take. |
| `maxArgs` | `1` | The most arguments `expect` can take. |

{/* bad {"options": [{"alwaysAwait": true}]} */}
```ts
import { expect, test } from "@jest/globals";

test("rejects an unknown id", () => {
  return expect(loadUser(-1)).rejects.toThrow("not found");
});
```

Use `asyncMatchers` for custom matchers that return a promise:

{/* bad {"options": [{"asyncMatchers": ["toResolveWith"]}]} */}
```ts
import { expect, test } from "@jest/globals";

test("loads the user", () => {
  expect(loadUser(1)).toResolveWith({ id: 1 });
});
```

Raise `maxArgs` if your setup lets `expect` take a message:

{/* good {"options": [{"maxArgs": 2}]} */}
```ts
import { expect, test } from "@jest/globals";

test("adds the tax", () => {
  expect(total(100), "after tax").toBe(108);
});
```
