# Write a test by hand

> For the complete documentation index, see [llms.txt](/llms.txt)

You never *have* to let the agent write everything. Scenarios are plain `.js`,
so you can author or edit them by hand.

## The shape

```js
// unotest/e2e/search.js
function test_search() {
  step("Search for a known product", () => {
    goto("/");
    fill(getByRole("searchbox"), "wireless mouse");
    press(getByRole("searchbox"), "Enter");
  });

  step("Results contain the product", () => {
    assertVisible(getByRole("link", { name: /wireless mouse/i }));
  });
}
```

## Rules to keep in mind

- Put every executable step inside `step("intent", () => { … })`.
- Prefer [stable selectors](/concepts/selectors/).
- Reference [variables](/concepts/variables/) by bare `UPPER_SNAKE`.
- Scenarios live in a feature subfolder of `unotest/e2e/`, not its root.

## Lint as you go

```sh
npx @unotest/web lint
```

The [linter](/reference/linter/) catches brittle selectors, missing step
wrappers, and unexplained `pause()`. See the full [DSL reference](/reference/dsl/).
