# `Hakushi.Test`
[🔗](https://github.com/hattoriai/hakushi/blob/v0.1.0/lib/hakushi/test.ex#L1)

Helpers for `Phoenix.LiveViewTest`, to read and change the canvases of
a LiveView with no browser.

    import Hakushi.Test

    test "joins two tables", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/schema")

      assert :ok = connect(view, "schema", {"orders", "user_id"}, {"users", "id"})
      assert [%{source: "orders", target: "users"}] = edges(view, "schema")

      assert {:error, "A node cannot connect to itself."} =
               connect(view, "schema", "users", "users")
    end

The functions send the events that the browser sends (see
`Hakushi.Canvas`), so each change goes the way of a person's: the rules,
`on_change`, the room of a shared canvas. A change the canvas refuses
gives `{:error, reason}`, with the words the person sees.

`nodes/2` and `edges/2` read what the canvas shows: the nodes and edges
as the browser has them, in their order.

# `connect`

```elixir
@spec connect(
  struct(),
  String.t(),
  String.t() | {String.t(), String.t()},
  String.t() | {String.t(), String.t()}
) :: :ok | {:error, String.t()}
```

Connects two nodes, as a person draws an edge from a handle to a
handle: each end a node's id, or `{node, handle}`.

# `copy_paste`

```elixir
@spec copy_paste(struct(), String.t(), [String.t()], {number(), number()} | nil) ::
  {:ok, [String.t()]} | {:error, String.t()}
```

Copies nodes, and pastes them at `{x, y}` (or next to them): gives
`{:ok, ids}` of the new nodes.

# `drop`

```elixir
@spec drop(struct(), String.t(), String.t() | nil, {number(), number()}, keyword()) ::
  {:ok, [String.t()]} | {:error, String.t()}
```

Drops an item (`Hakushi.Components.canvas_item/1`) on the canvas at
`{x, y}`, or double-clicks there (`item` is `nil`): gives `{:ok, [id]}`
of the node that `new_node` made. `parent: group` drops it in a group,
as a drop on the group does.

# `duplicate`

```elixir
@spec duplicate(struct(), String.t(), [String.t()]) ::
  {:ok, [String.t()]} | {:error, String.t()}
```

Duplicates nodes, as ⌘D does: gives `{:ok, ids}` of the copies.

# `edges`

```elixir
@spec edges(struct(), String.t()) :: [map()]
```

The edges of the canvas `id`: maps with `:id`, `:source`,
`:source_handle`, `:target`, `:target_handle`, `:path`, `:label`,
`:marker` and `:animated`.

# `label`

```elixir
@spec label(struct(), String.t(), String.t(), String.t() | nil) ::
  :ok | {:error, String.t()}
```

Sets the label of an edge, or takes it away (`nil`).

# `move`

```elixir
@spec move(struct(), String.t(), String.t() | [tuple()], {number(), number()} | nil) ::
  :ok | {:error, String.t()}
```

Moves nodes, as a person drags them: `{id, x, y}` for each, or one
node's id and `{x, y}`. A tuple `{id, x, y, width, height}` resizes it
too. A map `%{id: id, x: x, y: y, parent: group}` drops it into a group
(or out of one, with `parent: nil`), as a drop on a group does.

# `nodes`

```elixir
@spec nodes(struct(), String.t()) :: [map()]
```

The nodes of the canvas `id`, in the order they are drawn: maps with
`:id`, `:type`, `:x`, `:y`, `:width`, `:height` (`nil` for the size of
the content), `:locked`, `:parent` (the group it is in, or `nil`) and
`:label` (the name screen readers say).

# `notice`

```elixir
@spec notice(struct(), String.t()) :: String.t() | nil
```

The words the canvas shows for the last change it refused, or `nil`.

# `people`

```elixir
@spec people(struct(), String.t()) :: [String.t()]
```

The people the canvas `id` shows on a shared canvas (not the person
of this LiveView): their ids.

# `reconnect`

```elixir
@spec reconnect(struct(), String.t(), String.t(), keyword()) ::
  :ok | {:error, String.t()}
```

Moves an end of an edge to another handle, as a person drags the end of
a selected edge: `source:` or `target:`, a node's id or
`{node, handle}`.

# `redo`

```elixir
@spec redo(struct(), String.t()) :: :ok | {:error, String.t()}
```

Does again the last change undone, as ⇧⌘Z does.

# `remove`

```elixir
@spec remove(struct(), String.t(), keyword()) :: :ok | {:error, String.t()}
```

Deletes nodes (with their edges) and edges, as the Delete key does:
`nodes: ids, edges: ids`. (Not `delete`, which `Phoenix.ConnTest` has.)

# `undo`

```elixir
@spec undo(struct(), String.t()) :: :ok | {:error, String.t()}
```

Undoes the last change of this LiveView's person, as ⌘Z does.

---

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