# Testing

`Narabe.Test` moves, opens, renames, selects and picks in
`Phoenix.LiveViewTest`, with no browser. It reads the page with
LazyHTML, which a Phoenix 1.8 app has in its test deps; else add
`{:lazy_html, ">= 0.1.0", only: :test}`.

```elixir
import Narabe.Test

test "a card moves to Done", %{conn: conn} do
  {:ok, view, _html} = live(conn, ~p"/boards/#{board.id}")

  move(view, "sprint", card.id, parent: done.id, index: 0)
  assert_reply(view, %{ok: true})
  assert {"Done", ["Write the docs", "Ship"]} in columns(view, "sprint")
end
```

## Sending events

Each sends the list's own event, with the params the browser sends, to
the LiveView or the component of the list's `phx-target`, and gives the
rendered LiveView. The list's id may have a `#` in front.

* `move/4` sends `on_move`: the ids (one or a list) and `:after`,
  `:before`, `:parent` and `:index`, as in `Narabe.Move`. `columns: true`
  moves a board's columns.
* `expand/3` sends `on_expand` for a tree item whose children are not
  loaded.
* `rename/4` sends `on_rename`.
* `select/3` sends `on_select`.
* `pick/3` picks an item of a tree picker: the form's `phx-change`, with
  the item's id. The form needs an `id`.

Each raises when the page has no list with that id, or the list has no
such event.

```elixir
move(view, "pages", blog.id, parent: docs.id, after: intro.id)
move(view, "pages", docs.id, parent: intro.id)
assert_reply(view, %{error: "into_itself"})

expand(view, "pages", archive.id)
rename(view, "pages", post.id, "Hello")
pick(view, "move_parent_id", folder.id)
```

`assert_reply/2` is LiveViewTest's: it checks the reply to the last
event.

## Reading the page

* `items/2` gives the labels of a list's items in order (a board's cards,
  a tree's loaded items).
* `outline/2` gives a tree's loaded items as `{label, level}`, the top
  level being 1.
* `columns/2` gives a board's columns as `{label, card labels}`.

```elixir
assert items(view, "tasks") == ["Task 2", "Task 3", "Task 1", "Task 4"]
assert outline(view, "pages") == [{"Docs", 1}, {"Intro", 2}, {"Blog", 2}]
```

A browser moves the items before the server answers; a test does not.
The page shows what the server renders next. A list in a stream is not
rendered again for the person who moved, so check the database instead:

```elixir
move(view, "todos", b.id, before: a.id)
assert Todo |> Narabe.Ecto.ordered() |> Repo.all() |> Enum.map(& &1.id) == [b.id, a.id]
```

## Without a LiveView

`Narabe.Move.apply/3` applies a move in memory, and
`Narabe.Move.to_params/1` gives the params of a move as the browser sends
them, for an event handler or an agent's tool:

```elixir
params = Narabe.Move.to_params(%Narabe.Move{ids: [42], after: 12})
{:ok, move} = Narabe.Move.parse(params, :id)
{:ok, moved} = Narabe.Move.apply(items, move)
```

`Narabe.Ecto` runs in the Ecto sandbox as any query does.

## In a browser

Narabe's own browser tests (`mix test.e2e`) run in Chromium, Firefox and
WebKit against the development pages (`mix dev`): drags, the keyboard,
refused moves, trees, the picker, a second viewer, and Issho. The phone
tests (a held finger, a swipe, one level at a time) run in Chromium only,
whose touch events they drive.
