# Shared test data: fixtures

When several test files need the same data, write a fixture. A fixture is
a test-only action, in the domain's `fixtures/` folder, that creates data
by calling the application's own actions and returns what the tests need:

```jadpo
// domains/planning/fixtures/alice_with_todos.jadpo
/// Alice, signed up, with two open todos.
fixture alice_with_todos() -> Principal.user {
    var user: User = attempt register_user("alice@example.test")
    var alice: Principal.user = Principal.user(user)
    attempt create_todo(CreateTodo { title: "Buy milk" }, alice)
    attempt create_todo(CreateTodo { title: "Book dentist" }, alice)
    return alice
}
```

A test calls a fixture by name, like any action. Because the fixture goes
through the real actions, validation, lifecycle and policy apply exactly
as they do for a user. Seeds build their data the same way
([Seeds](seeds.md)). A failure inside a fixture fails the test
that called it, so a fixture has no `fails` list.

## Who can call a fixture

Only tests, other fixtures and seeds can call a fixture. An action that
calls one is `semantic.not_callable`.

## A fixture for other domains: `public`

A fixture is private to its domain unless it is marked `public`. Another
domain's tests, fixtures and seeds, and a scenario in root `tests/`, call
a public fixture through its domain, like an action:
`planning.alice_with_todos()`. Calling a private one from outside its
domain is `visibility.private_cross_domain`. `public` offers a fixture to
tests, fixtures and seeds only: application code still never calls it.

Here `planning` offers a public fixture, and both a `reminders` test and a
scenario call it:

```jadpo
// domains/planning/fixtures/two_open_todos.jadpo
use planning/types { TodoCount }
use planning/actions { add_todo }

/// Two open todos, added the way a user adds them.
public fixture two_open_todos() -> TodoCount {
    var one: TodoCount = add_todo(0)
    return add_todo(one)
}
```

```jadpo
// domains/reminders/actions/send_reminders.test.jadpo
use planning

test "reminders start from planning's open todos" {
    send_reminders()
    assert planning.two_open_todos() == 2
}
```

```jadpo
// tests/a_plan_starts_with_two_todos.test.jadpo
use planning

test "a plan starts with two open todos" {
    assert planning.two_open_todos() == 2
}
```

## Seeds and fixtures

A seed is data for local development and demos, made the same way:

| | Seed | Fixture |
|---|---|---|
| Lives in | `database/seeds/` | a domain's `fixtures/` |
| Used by | `jadpo seed <name>`, for local development and demos | tests |
| Creates data by | calling actions | calling actions |
| Data lasts | until you reset the local database | until the test ends |
| In production | refused | never compiled in |

A seed may call fixtures, so demo data and test data share their builders.
A test never loads a seed: seeds change whenever the demo changes.

## Data builders

A data builder makes one record with valid defaults, for a test that
needs a record in a particular state. The compiler generates one for each
entity: `make.Todo { title: "Buy milk" }` fills every other required field
with a valid default and goes through the real create operation, so
validation and policy apply. A builder may set any field that isn't
generated, including ones ordinary inputs don't accept, so hard-to-reach
states are easy to build.

With builders, fixtures remain for meaningful scenarios. They return a
named object holding what they made (`setup.alice`, `setup.todos`), so a
test never has to look its own data up again.

Data builders, and the named object a fixture returns with them, aren't
built yet. Until they are, build the data with a fixture that returns
what the tests need, as above.
