# `Cerberus`
[🔗](https://github.com/ftes/cerberus/blob/v0.1.7/lib/cerberus.ex#L1)

Public session-first facade for Cerberus drivers.

This module validates option schemas, normalizes locator inputs, and dispatches
operations to static/live/browser session implementations while preserving a
consistent API shape.

Technical guarantees:
- Public operations accept and return `Cerberus.Session` structs.
- Locator-based operations keep `session` first and support locator composition forms.
- Path and assertion operations resolve timeout defaults per driver.
- Profiling buckets are emitted per operation and driver kind.

# `alt`

```elixir
@spec alt(String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds an alt-text locator.

# `alt`

```elixir
@spec alt(String.t() | Regex.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
@spec alt(Cerberus.Locator.t(), String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds or composes an alt-text locator.

Supported forms:
- `alt(value, opts)` for a leaf locator
- `alt(locator, value)` to compose with an existing locator

# `alt`

```elixir
@spec alt(
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.locator_leaf_opts()
) ::
  Cerberus.Locator.t()
```

Composes an alt-text constraint into an existing locator with locator options.

# `and_`

```elixir
@spec and_(Cerberus.Locator.t(), Cerberus.Locator.t()) :: Cerberus.Locator.t()
```

Composes two locators with logical AND (same-element intersection).

Both sides must match the same DOM node.

# `assert_checked`

```elixir
@spec assert_checked(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Asserts that at least one element matched by `locator` is checked.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `assert_checked`

```elixir
@spec assert_checked(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) :: arg
when arg: var
```

# `assert_disabled`

```elixir
@spec assert_disabled(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Asserts that at least one element matched by `locator` is disabled.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `assert_disabled`

```elixir
@spec assert_disabled(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `assert_download`

```elixir
@spec assert_download(arg, String.t(), Cerberus.Options.assert_download_opts()) :: arg
when arg: var
```

Asserts a file download by suggested filename across drivers.

Typical flow is sequential:

    session
    |> click(role(:link, name: "Download Report"))
    |> assert_download("report.txt")

Browser driver waits on BiDi download events. Static/live drivers assert on
the current response `content-disposition` headers.

## Options

* `:timeout` (`t:pos_integer/0`) - Wait timeout in milliseconds for download detection. The default value is `1500`.

# `assert_has`

```elixir
@spec assert_has(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Asserts that content matched by `locator` exists.

Unscoped:
`assert_has(session, ~l"Articles"e)`

Composed locator form:
`assert_has(session, and_(css("a"), text("Counter", exact: true)))`

For explicit scope boundaries, use `within/3`.

# `assert_has`

```elixir
@spec assert_has(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) :: arg
when arg: var
```

Asserts content exists.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `assert_path`

```elixir
@spec assert_path(arg, String.t() | Regex.t(), Cerberus.Options.path_opts()) :: arg
when arg: var
```

Asserts the session path matches `expected`.

## Options

* `:exact` (`t:boolean/0`) - Requires an exact path match unless disabled. The default value is `true`.

* `:query` (`t:term/0`) - Optionally validates query params as a subset map/keyword. The default value is `nil`.

* `:timeout` (`t:non_neg_integer/0`) - Retries path assertions for up to this many milliseconds. The default value is `0`.

# `assert_readonly`

```elixir
@spec assert_readonly(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Asserts that at least one element matched by `locator` is readonly.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `assert_readonly`

```elixir
@spec assert_readonly(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `assert_selected`

```elixir
@spec assert_selected(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Asserts that at least one element matched by `locator` is selected.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `assert_selected`

```elixir
@spec assert_selected(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `assert_value`

```elixir
@spec assert_value(arg, Cerberus.Locator.t(), String.t() | Regex.t()) :: arg
when arg: var
```

Asserts that the current value of a form field matched by `locator` equals `expected`.

String values use exact matching. Regex values are matched against the current field value.

# `assert_value`

```elixir
@spec assert_value(
  arg,
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.assert_value_opts()
) :: arg
when arg: var
```

Asserts a form-field value.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Retries value assertions for up to this many milliseconds. The default value is `0`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `check`

```elixir
@spec check(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Checks a checkbox matched by `locator`.

Bare string/regex shorthand is not supported.

Use explicit locators like `~l"..."l`, `testid(...)`, `css(...)`, or explicit
text sigils (`~l"..."e` / `~l"..."i`).

Sigil examples: `check(session, ~l"#subscribe"c)`,
`check(session, ~l"subscribe-checkbox"t)`.

# `check`

```elixir
@spec check(arg, Cerberus.Locator.t(), Cerberus.Options.check_opts()) :: arg
when arg: var
```

Checks a matched checkbox.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `choose`

```elixir
@spec choose(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Chooses a radio input matched by `locator`.

Bare string/regex shorthand is not supported.

Use explicit locators like `~l"..."l`, `testid(...)`, `css(...)`, or explicit
text sigils (`~l"..."e` / `~l"..."i`).

Sigil examples: `choose(session, ~l"#contact_email"c)`,
`choose(session, ~l"contact-email"t)`.

# `choose`

```elixir
@spec choose(arg, Cerberus.Locator.t(), Cerberus.Options.choose_opts()) :: arg
when arg: var
```

Chooses a matched radio input.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `click`

```elixir
@spec click(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Clicks a matched element using unscoped shorthand (`click(session, locator)`).

# `click`

```elixir
@spec click(arg, Cerberus.Locator.t(), Cerberus.Options.click_opts()) :: arg
when arg: var
```

Clicks a matched element.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched elements to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched elements to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched elements to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched elements to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `close_tab`

```elixir
@spec close_tab(arg) :: arg when arg: var
```

Closes the current tab for browser sessions.

# `closest`

```elixir
@spec closest(Cerberus.Locator.t(), Cerberus.Options.closest_opts()) ::
  Cerberus.Locator.t()
```

Composes a locator that matches the closest ancestor of a nested `from` locator.

Example:

    within(session, closest(~l".fieldset"c, from: ~l"textbox:Email"r), &assert_has(&1, ~l"can't be blank"e))

# `css`

```elixir
@spec css(String.t()) :: Cerberus.Locator.t()
```

Builds a CSS locator.

# `css`

```elixir
@spec css(String.t(), Cerberus.Options.locator_leaf_opts()) :: Cerberus.Locator.t()
@spec css(Cerberus.Locator.t(), String.t()) :: Cerberus.Locator.t()
```

Builds or composes a CSS locator.

Supported forms:
- `css(value, opts)` for a leaf locator
- `css(locator, value)` to compose with an existing locator

# `css`

```elixir
@spec css(Cerberus.Locator.t(), String.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
```

Composes a CSS constraint into an existing locator with locator options.

# `fill_in`

```elixir
@spec fill_in(
  arg,
  Cerberus.Locator.t(),
  Cerberus.Options.fill_in_value(),
  Cerberus.Options.fill_in_opts()
) :: arg
when arg: var
```

Fills a form field matched by `locator`.

Bare string/regex shorthand is not supported.

Use explicit locators like `~l"..."l`, `role(...)`, `placeholder(...)`,
`title(...)`, `testid(...)`, `css(...)`, or explicit text sigils
(`~l"..."e` / `~l"..."i`).

Sigil examples: `fill_in(session, ~l"#search_q"c, "Aragorn")`,
`fill_in(session, ~l"search-input"t, "Aragorn")`.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `filter`

```elixir
@spec filter(
  Cerberus.Locator.t(),
  keyword()
) :: Cerberus.Locator.t()
```

Adds locator filters to an existing locator.

Supported filters:
- `has: locator`
- `has_not: locator`
- `visible: boolean`

# `label`

```elixir
@spec label(String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds a label locator.

# `label`

```elixir
@spec label(String.t() | Regex.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
@spec label(Cerberus.Locator.t(), String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds or composes a label locator.

Supported forms:
- `label(value, opts)` for a leaf locator
- `label(locator, value)` to compose with an existing locator

# `label`

```elixir
@spec label(
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.locator_leaf_opts()
) ::
  Cerberus.Locator.t()
```

Composes a label constraint into an existing locator with locator options.

# `not_`

```elixir
@spec not_(Cerberus.Locator.t()) :: Cerberus.Locator.t()
```

Negates a locator.

# `not_`

```elixir
@spec not_(Cerberus.Locator.t(), Cerberus.Locator.t()) :: Cerberus.Locator.t()
```

Composes `left AND NOT(right)`.

# `open_browser`

```elixir
@spec open_browser(arg) :: arg when arg: var
```

Writes the current rendered page snapshot to a temporary HTML file and opens it.

This is primarily useful for human debugging because it lets you inspect the
rendered page in a real browser tab.

For callback-based DOM inspection in-process (for example, by AI tooling), see
`render_html/2`.

# `open_tab`

```elixir
@spec open_tab(arg) :: arg when arg: var
```

Opens a new tab for browser sessions and returns the updated session.

# `or_`

```elixir
@spec or_(Cerberus.Locator.t(), Cerberus.Locator.t()) :: Cerberus.Locator.t()
```

Composes two locators with logical OR (union).

Action operations still require a unique final target at execution time.

# `placeholder`

```elixir
@spec placeholder(String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds a placeholder locator.

# `placeholder`

```elixir
@spec placeholder(String.t() | Regex.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
@spec placeholder(Cerberus.Locator.t(), String.t() | Regex.t()) ::
  Cerberus.Locator.t()
```

Builds or composes a placeholder locator.

Supported forms:
- `placeholder(value, opts)` for a leaf locator
- `placeholder(locator, value)` to compose with an existing locator

# `placeholder`

```elixir
@spec placeholder(
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.locator_leaf_opts()
) ::
  Cerberus.Locator.t()
```

Composes a placeholder constraint into an existing locator with locator options.

# `refute_checked`

```elixir
@spec refute_checked(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Refutes that any element matched by `locator` is checked.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `refute_checked`

```elixir
@spec refute_checked(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) :: arg
when arg: var
```

# `refute_disabled`

```elixir
@spec refute_disabled(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Refutes that any element matched by `locator` is disabled.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `refute_disabled`

```elixir
@spec refute_disabled(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `refute_has`

```elixir
@spec refute_has(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Refutes that content matched by `locator` exists.

Unscoped:
`refute_has(session, ~l"500 Internal Server Error"e)`

Composed locator form:
`refute_has(session, and_(css("button"), text("Dangerous", exact: true)))`

For explicit scope boundaries, use `within/3`.

# `refute_has`

```elixir
@spec refute_has(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) :: arg
when arg: var
```

Refutes content exists.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `refute_path`

```elixir
@spec refute_path(arg, String.t() | Regex.t(), Cerberus.Options.path_opts()) :: arg
when arg: var
```

Refutes that the session path matches `expected`.

## Options

* `:exact` (`t:boolean/0`) - Requires an exact path match unless disabled. The default value is `true`.

* `:query` (`t:term/0`) - Optionally validates query params as a subset map/keyword. The default value is `nil`.

* `:timeout` (`t:non_neg_integer/0`) - Retries path assertions for up to this many milliseconds. The default value is `0`.

# `refute_readonly`

```elixir
@spec refute_readonly(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Refutes that any element matched by `locator` is readonly.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `refute_readonly`

```elixir
@spec refute_readonly(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `refute_selected`

```elixir
@spec refute_selected(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Refutes that any element matched by `locator` is selected.

## Options

* `:visible` - Chooses visible text only, hidden only, or both. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Retries text assertions for up to this many milliseconds. The default value is `0`.

* `:count` (`t:term/0`) - Requires exactly this many text matches. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many text matches. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many text matches. The default value is `nil`.

* `:between` (`t:term/0`) - Requires text match count to fall within an inclusive range. The default value is `nil`.

# `refute_selected`

```elixir
@spec refute_selected(arg, Cerberus.Locator.t(), Cerberus.Options.assert_opts()) ::
  arg
when arg: var
```

# `refute_value`

```elixir
@spec refute_value(arg, Cerberus.Locator.t(), String.t() | Regex.t()) :: arg
when arg: var
```

Refutes that the current value of a form field matched by `locator` equals `expected`.

String values use exact matching. Regex values are matched against the current field value.

# `refute_value`

```elixir
@spec refute_value(
  arg,
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.assert_value_opts()
) :: arg
when arg: var
```

Refutes a form-field value.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Retries value assertions for up to this many milliseconds. The default value is `0`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `reload_page`

```elixir
@spec reload_page(arg, Cerberus.Options.reload_opts()) :: arg when arg: var
```

Reloads the current path, defaulting to `/` when the session has no current path.

# `render_html`

```elixir
@spec render_html(arg, Cerberus.Options.return_result_opts()) :: arg | LazyHTML.t()
when arg: var
@spec render_html(arg, (LazyHTML.t() -&gt; term())) :: arg when arg: var
```

Renders the current page HTML.

This is primarily for debugging, and can be useful for AI-assisted workflows
that need to inspect the entire DOM tree in-process.

Use either:
- callback form (`render_html(session, fn lazy_html -> ... end)`) to keep piping
- `return_result: true` (`render_html(session, return_result: true)`) to return `LazyHTML`

For human-oriented inspection in a browser, see `open_browser/1`.

## Options

* `:return_result` (`t:boolean/0`) - When true, returns the computed value instead of the session. The default value is `false`.

# `role`

```elixir
@spec role(String.t() | atom()) :: Cerberus.Locator.t()
```

Builds a role locator.

# `role`

```elixir
@spec role(String.t() | atom(), Cerberus.Options.role_locator_opts()) ::
  Cerberus.Locator.t()
@spec role(Cerberus.Locator.t(), String.t() | atom()) :: Cerberus.Locator.t()
```

Builds or composes a role locator.

Supported forms:
- `role(role_name, opts)` for a leaf locator
- `role(locator, role_name)` to compose with an existing locator

# `role`

```elixir
@spec role(
  Cerberus.Locator.t(),
  String.t() | atom(),
  Cerberus.Options.role_locator_opts()
) ::
  Cerberus.Locator.t()
```

Composes a role constraint into an existing locator with locator options.

# `scope`

```elixir
@spec scope(Cerberus.Locator.t(), Cerberus.Locator.t()) :: Cerberus.Locator.t()
```

Composes two locators with scope chaining (descendant query).

The right locator is resolved within each element matched by the left locator.

# `select`

```elixir
@spec select(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Selects option text in a `<select>` field matched by `locator`.

Bare string/regex shorthand is not supported.

For multi-select fields, pass the full desired selection on every call
(`option: [~l"Elf"e, ~l"Dwarf"e]`). Each `select/3` call replaces the selection
with the provided option value(s).
Sigil examples: `select(session, ~l"#race_select"c, option: ~l"Elf"e)`,
`select(session, ~l"race-select"t, option: ~l"Elf"e)`.

# `select`

```elixir
@spec select(arg, Cerberus.Locator.t(), Cerberus.Options.select_opts()) :: arg
when arg: var
```

Selects option text in a matched `<select>` field.

## Options

* `:option` (`t:term/0`) - Required. Text locator (`~l"..."e`/`text("...", exact: true)`) or list of text locators to select; for multi-select inputs pass all desired values on each call.

* `:exact_option` (`t:boolean/0`) - Requires exact option-text matches unless disabled. The default value is `true`.

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched selects to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched selects to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched selects to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched selects to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `session`

```elixir
@spec session() :: Cerberus.Session.t()
```

Starts a default non-browser (`:phoenix`) session with default options.

# `session`

```elixir
@spec session(Cerberus.Options.session_common_opts()) :: Cerberus.Session.t()
@spec session(Plug.Conn.t()) :: Cerberus.Session.t()
@spec session(:phoenix) :: Cerberus.Session.t()
@spec session(:browser) :: Cerberus.Session.t()
```

Starts a non-browser (`:phoenix`) session.

This arity also accepts `Plug.Conn` and driver atoms:

- `session(conn)` seeds the new session from an existing conn.
- `session(:phoenix)` starts non-browser mode.
- `session(:browser)` starts browser mode with defaults.

## Options

* `:endpoint` (`t:term/0`) - Endpoint module override.

* `:conn` (`t:term/0`) - Seed Plug.Conn for session state.

* `:timeout_ms` (`t:non_neg_integer/0`) - Default timeout in milliseconds.

# `session`

```elixir
@spec session(:phoenix, Cerberus.Options.session_common_opts()) ::
  Cerberus.Session.t()
@spec session(:browser, Cerberus.Options.session_browser_opts()) ::
  Cerberus.Session.t()
```

Starts a browser session.

Browser context defaults can be configured globally via `config :cerberus, :browser`
and overridden per session with:

- `user_agent: "..."`
- `browser: [viewport: [width: ..., height: ...] | {w, h}]`
- `browser: [user_agent: "..."]`
- `browser: [popup_mode: :allow | :same_tab]` to control `window.open` behavior
- `browser: [init_script: "..."]` or `browser: [init_scripts: ["...", ...]]`
- `webdriver_url: "http://remote-webdriver:4444"` to use a remote WebDriver endpoint
  without local browser/chromedriver launch.

## Options

* `:endpoint` (`t:term/0`) - Endpoint module override.

* `:timeout_ms` (`t:non_neg_integer/0`) - Default timeout in milliseconds.

* `:ready_timeout_ms` (`t:pos_integer/0`) - Browser readiness timeout in milliseconds.

* `:ready_quiet_ms` (`t:pos_integer/0`) - Browser readiness quiet window in milliseconds.

* `:user_agent` (`t:term/0`) - Top-level user-agent override for browser session context.

* `:browser` (`t:keyword/0`) - Per-session browser overrides.

* `:webdriver_url` (`t:term/0`) - Remote WebDriver URL.

* `:chrome_webdriver_url` (`t:term/0`) - Remote Chrome WebDriver URL.

* `:chrome_binary` (`t:term/0`) - Chrome binary path override.

* `:chromedriver_binary` (`t:term/0`) - ChromeDriver binary path override.

* `:chrome_args` (`t:term/0`) - Additional Chrome launch arguments.

* `:headless` (`t:boolean/0`) - Headless browser toggle.

* `:slow_mo` (`t:non_neg_integer/0`) - Delay in milliseconds applied before each browser BiDi command.

* `:chromedriver_port` (`t:pos_integer/0`) - ChromeDriver port override.

* `:chrome_startup_retries` (`t:non_neg_integer/0`) - Chrome startup retry count.

* `:chromedriver_log_path` (`t:term/0`) - ChromeDriver log file path.

* `:startup_log_tail_bytes` (`t:non_neg_integer/0`) - Startup log tail byte limit.

* `:startup_log_tail_lines` (`t:non_neg_integer/0`) - Startup log tail line limit.

* `:base_url` (`t:term/0`) - Base URL override for remote runtime.

# `sigil_l`

```elixir
@spec sigil_l(
  String.t(),
  charlist()
) :: Cerberus.Locator.t()
```

Builds a locator using `~l`.

Supported forms:
- `~l"text"` exact text (default)
- `~l"text"e` exact text
- `~l"text"i` inexact text
- `~l"text"l` label locator form
- `~l"ROLE:NAME"r` role locator form
- `~l"selector"c` CSS locator form
- `~l"test-id"t` testid locator form (defaults to exact matching)

Rules:
- use at most one locator-kind modifier (`r`, `c`, `l`, or `t`)
- `e` and `i` are mutually exclusive
- `r` requires `ROLE:NAME` input

# `submit`

```elixir
@spec submit(arg) :: arg when arg: var
```

Submits the active form (the most recently interacted form field).

# `submit`

```elixir
@spec submit(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Submits a matched submit-capable control using default options.

# `submit`

```elixir
@spec submit(arg, Cerberus.Locator.t(), Cerberus.Options.submit_opts()) :: arg
when arg: var
```

Submits a matched submit-capable control.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched submit controls to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched submit controls to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched submit controls to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched submit controls to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `switch_tab`

```elixir
@spec switch_tab(Cerberus.Session.t(), Cerberus.Session.t()) :: Cerberus.Session.t()
```

Switches the active tab to `target_session` for browser sessions.

# `testid`

```elixir
@spec testid(String.t()) :: Cerberus.Locator.t()
```

Builds a test-id locator.

# `testid`

```elixir
@spec testid(String.t(), Cerberus.Options.locator_leaf_opts()) :: Cerberus.Locator.t()
@spec testid(Cerberus.Locator.t(), String.t()) :: Cerberus.Locator.t()
```

Builds or composes a test-id locator.

Supported forms:
- `testid(value, opts)` for a leaf locator
- `testid(locator, value)` to compose with an existing locator

# `testid`

```elixir
@spec testid(Cerberus.Locator.t(), String.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
```

Composes a test-id constraint into an existing locator with locator options.

# `text`

```elixir
@spec text(String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds a text locator.

# `text`

```elixir
@spec text(String.t() | Regex.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
@spec text(Cerberus.Locator.t(), String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds or composes a text locator.

Supported forms:
- `text(value, opts)` for a leaf locator
- `text(locator, value)` to compose with an existing locator

# `text`

```elixir
@spec text(
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.locator_leaf_opts()
) ::
  Cerberus.Locator.t()
```

Composes a text constraint into an existing locator with locator options.

# `title`

```elixir
@spec title(String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds a title locator.

# `title`

```elixir
@spec title(String.t() | Regex.t(), Cerberus.Options.locator_leaf_opts()) ::
  Cerberus.Locator.t()
@spec title(Cerberus.Locator.t(), String.t() | Regex.t()) :: Cerberus.Locator.t()
```

Builds or composes a title locator.

Supported forms:
- `title(value, opts)` for a leaf locator
- `title(locator, value)` to compose with an existing locator

# `title`

```elixir
@spec title(
  Cerberus.Locator.t(),
  String.t() | Regex.t(),
  Cerberus.Options.locator_leaf_opts()
) ::
  Cerberus.Locator.t()
```

Composes a title constraint into an existing locator with locator options.

# `uncheck`

```elixir
@spec uncheck(arg, Cerberus.Locator.t()) :: arg when arg: var
```

Unchecks a checkbox matched by `locator`.

Bare string/regex shorthand is not supported.

Use explicit locators like `~l"..."l`, `testid(...)`, `css(...)`, or explicit
text sigils (`~l"..."e` / `~l"..."i`).

Sigil examples: `uncheck(session, ~l"#subscribe"c)`,
`uncheck(session, ~l"subscribe-checkbox"t)`.

# `uncheck`

```elixir
@spec uncheck(arg, Cerberus.Locator.t(), Cerberus.Options.check_opts()) :: arg
when arg: var
```

Unchecks a matched checkbox.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched fields to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched fields to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched fields to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched fields to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `unwrap`

```elixir
@spec unwrap(arg, (term() -&gt; term())) :: arg when arg: var
```

Executes a callback with driver-native escape-hatch data.

Browser sessions receive a constrained `Cerberus.Browser.Native` handle.
Prefer public Cerberus operations and `Cerberus.Browser.*` helpers for stable flows.

# `upload`

```elixir
@spec upload(arg, Cerberus.Locator.t(), String.t(), Cerberus.Options.upload_opts()) ::
  arg
when arg: var
```

Uploads a file into a matched file input.

Bare string/regex shorthand is not supported.

Use explicit locators like `~l"..."l`, `testid(...)`, `css(...)`, or explicit
text sigils (`~l"..."e` / `~l"..."i`).

Sigil examples: `upload(session, ~l"#avatar"c, "/tmp/avatar.jpg")`,
`upload(session, ~l"avatar-upload"t, "/tmp/avatar.jpg")`.

## Options

* `:timeout` (`t:non_neg_integer/0`) - Browser action timeout in milliseconds.

* `:force` (`t:boolean/0`) - Bypasses browser actionability checks before dispatching the action. The default value is `false`.

* `:checked` (`t:term/0`) - Requires matched file inputs to be checked/unchecked. The default value is `nil`.

* `:disabled` (`t:term/0`) - Requires matched file inputs to be disabled/enabled. The default value is `nil`.

* `:selected` (`t:term/0`) - Requires matched file inputs to be selected/unselected. The default value is `nil`.

* `:readonly` (`t:term/0`) - Requires matched file inputs to be readonly/editable. The default value is `nil`.

* `:count` (`t:term/0`) - Requires exactly this many matched candidates. The default value is `nil`.

* `:min` (`t:term/0`) - Requires at least this many matched candidates. The default value is `nil`.

* `:max` (`t:term/0`) - Requires at most this many matched candidates. The default value is `nil`.

* `:between` (`t:term/0`) - Requires matched candidate count to fall within an inclusive range. The default value is `nil`.

* `:first` (`t:boolean/0`) - Selects the first matched candidate. The default value is `false`.

* `:last` (`t:boolean/0`) - Selects the last matched candidate. The default value is `false`.

* `:nth` (`t:term/0`) - Selects the nth (1-based) matched candidate. The default value is `nil`.

* `:index` (`t:term/0`) - Selects the index (0-based) matched candidate. The default value is `nil`.

# `visit`

```elixir
@spec visit(arg, String.t(), Cerberus.Options.visit_opts()) :: arg when arg: var
```

Visits `path` and returns the updated session.

# `within`

```elixir
@spec within(arg, Cerberus.Locator.t(), (arg -&gt; arg)) :: arg when arg: var
```

Executes `callback` within a narrowed scope.

`scope` must be a `Locator.t()` (for example, `~l"#secondary-panel"c`).
Use `closest/2` when scope should resolve to the nearest matching ancestor
around a nested element (for example, a field wrapper around a label).

Use `within/3` when you need explicit scope boundaries for mixed operations.

Browser note: when locator-based `within/3` matches an `<iframe>`, Cerberus switches
the query root to that iframe document. Only same-origin iframes are supported.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
