# Write your first test

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

This is the canonical loop: describe a flow, let the agent build it, review.

## 1. Make sure the project is set up

```sh
npx @unotest/web init
```

## 2. Describe the flow to your agent

In your AI editor, be specific about the start, the actions, and the assertion:

> Open `/login`, sign in with `TEST_USER_EMAIL` / `TEST_PASSWORD`, and check that
> a heading "Dashboard" is visible.

The agent will explore your live app over MCP, then write a scenario.

## 3. Let it write & run

The agent records actions, generates `unotest/e2e/login.js`, and runs it. If a
step fails, it pauses, inspects, patches and resumes — then shows you the result.

## 4. Read the result

```js
function test_login() {
  step("Sign in with the demo user", () => {
    goto("/login");
    fill(getByLabel("Email"), TEST_USER_EMAIL);
    fill(getByLabel("Password"), TEST_PASSWORD);
    click(getByRole("button", { name: "Continue" }));
  });

  step("Dashboard is shown", () => {
    assertVisible(getByRole("heading", { name: "Dashboard" }));
  });
}
```

## 5. Commit

It's ordinary `.js` in your repo. Tweak the labels or selectors if you like,
then commit it like any code.

:::tip
Keep `TEST_USER_EMAIL` / `TEST_PASSWORD` in [variables](/concepts/variables/),
not in the test.
:::
