# Checks

> Check what the page shows with expect, and know how long each check looks.

Source: https://rehearsal.dev/retest/essentials/checks

A check on an element or a page looks again until it passes or its time runs out. It never repeats an action. Await every check.

```ts
await expect(page.getByTestId('saved-task')).toHaveText('Release checklist')
await expect(page.getByRole('dialog')).not.toBeVisible()
await expect(page).toHaveURL('/tasks')
```

## Element checks

| Matcher | Passes when |
| --- | --- |
| `toBeVisible()` | Exactly one element matches, and it is visible. |
| `toBeHidden()` | Nothing matches, or nothing that matches is visible. |
| `toBeChecked()` | Exactly one element matches, it can be ticked, and it is ticked. |
| `toBeEnabled()`, `toBeDisabled()` | Exactly one element matches, and it is enabled, or disabled. |
| `toHaveText(text)` | Exactly one element matches, and its whole text equals `text`, or matches a regular expression. |
| `toHaveText([...texts])` | The matches, hidden ones included, have exactly these texts, in document order. |
| `toContainText(text)` | Exactly one element matches, and its text holds `text`, case and all. |
| `toHaveCount(n)` | Exactly `n` elements match, visible or not. |
| `toHaveValue(value)` | Exactly one field matches, and its whole value is `value`. |

- `toHaveText` and `toContainText` trim both ends and read each run of spaces or line breaks as one space. `toHaveValue` compares the value exactly.
- Disabled means a native control that is disabled, on its own or in a disabled `<fieldset>`, or an element whose nearest `aria-disabled` is `true`.
- A check lists at most 100 matches, so `toHaveText([...texts])` and `toBeHidden()` cannot pass when more match.

## Page checks

| Matcher | Passes when |
| --- | --- |
| `expect(page).toHaveURL(url)` | The page's whole address, query and fragment included, equals `url`. A relative URL resolves against the base URL. |
| `expect(page).toHaveTitle(title)` | The page's whole title equals `title`, trimmed, with each run of spaces read as one. |

Both also take a regular expression, searched for anywhere. A secret on the page reads as its placeholder, such as `{{password}}`, so a check compares that.

## Negation

`.not` before a matcher passes only on a look that shows the opposite.

- `.not.toBeVisible()` passes when nothing matches. So do `.not.toHaveCount(n)` and `.not.toHaveText([...texts])`.
- Every other negation needs exactly one element. `.not.toHaveText('Draft')` on no match fails `not_found`, and on several fails `ambiguous`.
- An element that cannot have the state passes neither way: `.not.toBeChecked()` on a paragraph fails.

## Values

Value checks compare what the test holds, at once.

| Matcher | Passes when |
| --- | --- |
| `toBe(expected)` | The two are the same, compared with `Object.is`. |
| `toEqual(expected)` | The two are deeply equal: objects by their own keys, arrays item by item, dates by their time, maps and sets by their members. |
| `toContain(item)` | A string or an array holds the item. |
| `toMatch(pattern)` | A string matches the regular expression. |

Value checks have no `.not`. The type check refuses a value matcher on an element and an element matcher on a value. It also refuses `.not` written twice and any matcher on a secret.

## Soft checks

`expect.soft(x)` records a failure and lets the test go on. The test still fails at the end, with its first failure leading and the others listed after it.

```ts
await expect.soft(page.getByTestId('page-loads')).toHaveText('1')
expect.soft(await savedTasks()).toBe(before + 1)
```

## Polling

`expect.poll(fn, { timeout, intervals })` calls `fn` again until its value passes, or its time runs out. Use it for a value the page does not show, such as a count from your API.

```ts
await expect.poll(savedTasks, { timeout: 5000 }).toBe(before + 1)
```

`fn` may only read. An action inside it fails the test, because it would run again on every look.

## How long a check looks

- A check has 5 seconds by default, the assertion budget.
- Every element and page check takes `{ timeout }` in milliseconds, as in `toBeVisible({ timeout: 2000 })`. It can shorten the budget, never lengthen it.
- The page tells Retest when it changes, so a look follows a change once 50 ms have passed since the last look. Without a change, looks come 50, 100 and 250 ms apart, then every 500 ms.

> [!NOTE]
> A failed check prints what it expected, what the page showed and how many times it looked. [Read a failure](https://rehearsal.dev/retest/essentials/read-a-failure.md) explains the card.
