Masu.Test (Masu v0.1.0)

Copy Markdown View Source

Helpers for Phoenix.LiveViewTest, to read and query the grids of a LiveView with no browser.

import Masu.Test

test "finds the late orders", %{conn: conn} do
  {:ok, view, _html} = live(conn, ~p"/orders")

  assert total(view, "orders") == 120

  view
  |> filter("orders", [{"status", :eq, "late"}])
  |> sort("orders", {"total", :desc})

  assert [%{"number" => "A-1042"} | _] = rows(view, "orders")
end

The functions send the events that the browser sends (see Masu.Grid), so the grid applies a sort, a filter or a search as it does for a person: the source sorts, filters and counts, and rows/3 reads the rows it gives.

Changes broadcast with Masu.Live before a call are in the rows it reads: the call waits for the LiveView to take them.

A row is a map of each column's key to its value as the browser gets it: numbers and booleans as they are, decimals as strings, dates and times in ISO 8601, and for a column with content the text of its cell.

Summary

Functions

The labels of the items of the app's own (Masu.Action) that the grid id offers for the column key: in its header menu (:header), or in the menu of its cells (:cell).

Adds rows to the grid id, as the person does with "New row" or a paste below the last row: each a map of column keys (or atoms) to values, as the browser sends them. The grid saves each through its create, or its changeset of its struct.

Applies a view to the grid id, as a link or a saved view does: params as view/2 gives them (%{} for the grid's own view). Returns the keys of the columns of the parts that no longer apply (see Masu.View.from_params/3).

Asks the grid id for its count, as the person does when they go to the end of a grid that does not know it (Ctrl+End): {:exact, n}, or {:at_least, n} from a source that does not know it either.

Runs the item label of the menu of the cell of the row row_id and the column key of the grid id, as header_action/4 does. The grid reads the row and the value of the cell from its source.

Closes the panel of an item of the grid id, as Escape does. Returns the view.

Closes the row row_id of a tree in the grid id. Returns the view.

The labels of the columns of the grid id, in order.

What the grid id knows of its count: {:exact, n}, or {:at_least, n} while it does not know it (count={:none}, a count not in yet, or a source that does not count). total/2 gives n.

Deletes the rows ids of the grid id, or, with :selection, the rows selected (select/4, select_all/3), as the person does with Ctrl+Delete. Returns {:ok, undo}, with the token that brings them back (restore_rows/3; nil when the grid cannot), or {:error, errors, undo} with {row_id, message} for each row that was not deleted.

Opens (or, with false, closes) the detail of the row row_id in the grid id: the grid renders its :detail slot for the row, which Phoenix.LiveViewTest.render/1 then has. Returns the view.

Edits cells of the grid id, as a person typing in them, pasting or undoing does: edits is a list of {row_id, key, value}, the value as the browser sends it (a string, or nil to empty the cell). The grid saves the edits of each row together.

Opens the row row_id of a tree in the grid id, as a click on its arrow (or →) does: its children show under it. Returns the view.

Opens every row beside row_id that has children, as * does. Returns the view.

Exports the grid id as its Export menu does (Masu.Export), and downloads the file from the link the browser gets, through the endpoint and the router's export route (Masu.Router): {name, binary}. A conn (Phoenix.ConnTest.build_conn/0, with what the route's pipeline wants of it, a signed-in user) is given with :conn.

The link the Export menu of the grid id gives the browser, for a test of the route itself: that it wants a signed-in user, say.

Filters the grid id: filters is a list of {key, op, value} (see Masu.Filter for the operators), which replaces the grid's filters. Returns the view.

Groups the rows of the grid id by columns (Masu.Group), as the header menu does: keys, the first the outermost; [] stops grouping. Returns the view.

The rows of a grouped grid id that are groups, in order, as maps of :id (what expand/3 takes), :key, :value, :count, :level, :expanded and :totals (by column key). Options as rows/3.

Runs the item label of the header menu of the column key of the grid id, as a click on it does: its function, its event to the LiveView, or its panel, which Phoenix.LiveViewTest.render/1 then has. An item that is only a JS command runs in the browser, not here. Returns the view.

The ids of the rows of the grid id, as rows/3 reads them.

Changes the layout of the grid id, as its columns menu, its headers and their edges do: any of order: keys (every column, in order), hidden: keys, pinned: %{key => :start | :end} and widths: %{key => pixels}. Returns the view.

The rows of a tree (Masu.Tree) in the grid id, in order, as maps of :id, :level (0 for a root), :children (whether it has any) and :expanded. Options as rows/3.

Goes to a page of the grid id (paging={:pages}), from 1, as its pager does, and gives the ids of its rows.

The place (from 0) of the row row_id in the grid's current order, or nil when its query leaves the row out: where the grid scrolls to follow another person to it.

Brings back the rows of a delete (its undo token, delete_rows/3), as the person does with Ctrl+Z. Returns {:ok, ids}.

The rows of the grid id, in its current order.

Searches the grid id as its search box does. Returns the view.

Selects rows of the grid id (selectable) by their ids, as their boxes do, or, with false, takes them out. Returns the view.

Selects every row of the query of the grid id (or, with false, none). Returns the view.

The selection of the grid id: %{all: boolean, ids: [...], except: [...], count: n}.

Sorts the grid id as clicks on its headers do: sorts is a key, a {key, :asc | :desc}, or a list of them (the first the most important). [] takes the order away. Returns the view.

How many rows the grid id has for its current query.

The totals of the query of the grid id, by column key: the row of totals at its bottom (Masu.Group). nil when no column has an aggregate.

The values that the filter menu of the column key offers: the values of the column among the rows of the query (without the column's own filters), each with its count, the most frequent first. :search narrows them as the menu's search box does.

The view of the grid id, as its params (see Masu.View): what differs from the grid's own view. %{} is the grid's own view.

Functions

actions(view, id, kind, key)

@spec actions(struct(), String.t(), :header | :cell, String.t() | atom()) :: [
  String.t()
]

The labels of the items of the app's own (Masu.Action) that the grid id offers for the column key: in its header menu (:header), or in the menu of its cells (:cell).

add_rows(view, id, rows)

@spec add_rows(struct(), String.t(), map() | [map()]) ::
  {:ok, [term()]}
  | {:error, ok: term(), error: [{String.t() | nil, String.t()}]}

Adds rows to the grid id, as the person does with "New row" or a paste below the last row: each a map of column keys (or atoms) to values, as the browser sends them. The grid saves each through its create, or its changeset of its struct.

Returns {:ok, ids} when every row was saved, or {:error, results}, a result for each row: {:ok, id} or {:error, [{key, message}]} (a key of nil for an error of the row).

apply_view(view, id, params)

@spec apply_view(struct(), String.t(), map()) :: [String.t()]

Applies a view to the grid id, as a link or a saved view does: params as view/2 gives them (%{} for the grid's own view). Returns the keys of the columns of the parts that no longer apply (see Masu.View.from_params/3).

ask_count(view, id)

@spec ask_count(struct(), String.t()) :: {:exact | :at_least, non_neg_integer()}

Asks the grid id for its count, as the person does when they go to the end of a grid that does not know it (Ctrl+End): {:exact, n}, or {:at_least, n} from a source that does not know it either.

cell_action(view, id, label, key, row_id, opts \\ [])

@spec cell_action(
  struct(),
  String.t(),
  String.t(),
  String.t() | atom(),
  term(),
  keyword()
) :: struct()

Runs the item label of the menu of the cell of the row row_id and the column key of the grid id, as header_action/4 does. The grid reads the row and the value of the cell from its source.

Options: :range, {ids, keys}: a range of cells selected, its rows' ids and its columns' keys, that the cell is in.

close_panel(view, id)

@spec close_panel(struct(), String.t()) :: struct()

Closes the panel of an item of the grid id, as Escape does. Returns the view.

collapse(view, id, row_id)

@spec collapse(struct(), String.t(), term()) :: struct()

Closes the row row_id of a tree in the grid id. Returns the view.

columns(view, id)

@spec columns(struct(), String.t()) :: [String.t()]

The labels of the columns of the grid id, in order.

count(view, id)

@spec count(struct(), String.t()) :: {:exact | :at_least, non_neg_integer()}

What the grid id knows of its count: {:exact, n}, or {:at_least, n} while it does not know it (count={:none}, a count not in yet, or a source that does not count). total/2 gives n.

delete_rows(view, id, ids)

@spec delete_rows(struct(), String.t(), [term()] | :selection) ::
  {:ok, String.t() | nil} | {:error, [{term(), String.t()}], String.t() | nil}

Deletes the rows ids of the grid id, or, with :selection, the rows selected (select/4, select_all/3), as the person does with Ctrl+Delete. Returns {:ok, undo}, with the token that brings them back (restore_rows/3; nil when the grid cannot), or {:error, errors, undo} with {row_id, message} for each row that was not deleted.

detail(view, id, row_id, open \\ true)

@spec detail(struct(), String.t(), term(), boolean()) :: struct()

Opens (or, with false, closes) the detail of the row row_id in the grid id: the grid renders its :detail slot for the row, which Phoenix.LiveViewTest.render/1 then has. Returns the view.

edit(view, id, edits)

@spec edit(struct(), String.t(), [{term(), String.t() | atom(), term()}]) ::
  :ok | {:error, [{term(), String.t(), String.t()}]}

Edits cells of the grid id, as a person typing in them, pasting or undoing does: edits is a list of {row_id, key, value}, the value as the browser sends it (a string, or nil to empty the cell). The grid saves the edits of each row together.

An edit may be {row_id, key, value, before}, with the value the person saw: the grid refuses it when the cell's value changed meanwhile, as it does for the browser.

Returns :ok when every edit was saved, or {:error, errors} with {row_id, key, message} for each cell that was not.

expand(view, id, row_id)

@spec expand(struct(), String.t(), term()) :: struct()

Opens the row row_id of a tree in the grid id, as a click on its arrow (or →) does: its children show under it. Returns the view.

expand_siblings(view, id, row_id)

@spec expand_siblings(struct(), String.t(), term()) :: struct()

Opens every row beside row_id that has children, as * does. Returns the view.

export(view, id, format, opts \\ [])

@spec export(struct(), String.t(), :csv | :xlsx, keyword()) :: {String.t(), binary()}

Exports the grid id as its Export menu does (Masu.Export), and downloads the file from the link the browser gets, through the endpoint and the router's export route (Masu.Router): {name, binary}. A conn (Phoenix.ConnTest.build_conn/0, with what the route's pipeline wants of it, a signed-in user) is given with :conn.

export_url(view, id, format)

@spec export_url(struct(), String.t(), :csv | :xlsx) :: String.t()

The link the Export menu of the grid id gives the browser, for a test of the route itself: that it wants a signed-in user, say.

filter(view, id, filters)

@spec filter(struct(), String.t(), [tuple()]) :: struct()

Filters the grid id: filters is a list of {key, op, value} (see Masu.Filter for the operators), which replaces the grid's filters. Returns the view.

group(view, id, keys)

@spec group(struct(), String.t(), [String.t() | atom()]) :: struct()

Groups the rows of the grid id by columns (Masu.Group), as the header menu does: keys, the first the outermost; [] stops grouping. Returns the view.

groups(view, id, opts \\ [])

@spec groups(struct(), String.t(), keyword()) :: [map()]

The rows of a grouped grid id that are groups, in order, as maps of :id (what expand/3 takes), :key, :value, :count, :level, :expanded and :totals (by column key). Options as rows/3.

header_action(view, id, label, key)

@spec header_action(struct(), String.t(), String.t(), String.t() | atom()) :: struct()

Runs the item label of the header menu of the column key of the grid id, as a click on it does: its function, its event to the LiveView, or its panel, which Phoenix.LiveViewTest.render/1 then has. An item that is only a JS command runs in the browser, not here. Returns the view.

ids(view, id, opts \\ [])

@spec ids(struct(), String.t(), keyword()) :: [term()]

The ids of the rows of the grid id, as rows/3 reads them.

layout(view, id, changes)

@spec layout(struct(), String.t(), keyword()) :: struct()

Changes the layout of the grid id, as its columns menu, its headers and their edges do: any of order: keys (every column, in order), hidden: keys, pinned: %{key => :start | :end} and widths: %{key => pixels}. Returns the view.

nodes(view, id, opts \\ [])

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

The rows of a tree (Masu.Tree) in the grid id, in order, as maps of :id, :level (0 for a root), :children (whether it has any) and :expanded. Options as rows/3.

page(view, id, page)

@spec page(struct(), String.t(), pos_integer()) :: [term()]

Goes to a page of the grid id (paging={:pages}), from 1, as its pager does, and gives the ids of its rows.

place(view, id, row_id)

@spec place(struct(), String.t(), term()) :: non_neg_integer() | nil

The place (from 0) of the row row_id in the grid's current order, or nil when its query leaves the row out: where the grid scrolls to follow another person to it.

restore_rows(view, id, undo)

@spec restore_rows(struct(), String.t(), String.t()) ::
  {:ok, [term()]} | {:error, term()}

Brings back the rows of a delete (its undo token, delete_rows/3), as the person does with Ctrl+Z. Returns {:ok, ids}.

rows(view, id, opts \\ [])

@spec rows(struct(), String.t(), keyword()) :: [map()]

The rows of the grid id, in its current order.

Options: :from (0), the first row, and :count (100), how many (at most 500, as the browser asks).

search(view, id, text)

@spec search(struct(), String.t(), String.t()) :: struct()

Searches the grid id as its search box does. Returns the view.

select(view, id, ids, on \\ true)

@spec select(struct(), String.t(), [term()], boolean()) :: struct()

Selects rows of the grid id (selectable) by their ids, as their boxes do, or, with false, takes them out. Returns the view.

select_all(view, id, on \\ true)

@spec select_all(struct(), String.t(), boolean()) :: struct()

Selects every row of the query of the grid id (or, with false, none). Returns the view.

selection(view, id)

@spec selection(struct(), String.t()) :: map()

The selection of the grid id: %{all: boolean, ids: [...], except: [...], count: n}.

sort(view, id, sorts)

@spec sort(struct(), String.t(), term()) :: struct()

Sorts the grid id as clicks on its headers do: sorts is a key, a {key, :asc | :desc}, or a list of them (the first the most important). [] takes the order away. Returns the view.

total(view, id)

@spec total(struct(), String.t()) :: non_neg_integer()

How many rows the grid id has for its current query.

totals(view, id)

@spec totals(struct(), String.t()) :: map() | nil

The totals of the query of the grid id, by column key: the row of totals at its bottom (Masu.Group). nil when no column has an aggregate.

values(view, id, key, opts \\ [])

@spec values(struct(), String.t(), String.t(), keyword()) :: [
  {term(), non_neg_integer()}
]

The values that the filter menu of the column key offers: the values of the column among the rows of the query (without the column's own filters), each with its count, the most frequent first. :search narrows them as the menu's search box does.

view(view, id)

@spec view(struct(), String.t()) :: map()

The view of the grid id, as its params (see Masu.View): what differs from the grid's own view. %{} is the grid's own view.