mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-01-09 00:17:59 +08:00
8c91a1f788
Co-authored-by: José Valim <jose.valim@dashbit.co>
147 lines
3.6 KiB
Elixir
147 lines
3.6 KiB
Elixir
defmodule Livebook.TestHelpers do
|
|
import Phoenix.LiveViewTest
|
|
|
|
alias Livebook.Session.Data
|
|
|
|
@doc """
|
|
Creates file structure according to the given specification.
|
|
"""
|
|
def create_tree!(path, items) do
|
|
for {name, content} <- items do
|
|
child_path = Path.join(path, to_string(name))
|
|
|
|
case content do
|
|
items when is_list(items) ->
|
|
File.mkdir!(child_path)
|
|
create_tree!(child_path, items)
|
|
|
|
content when is_binary(content) ->
|
|
File.write!(child_path, content)
|
|
end
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Creates the given number of subdirectories and returns their paths.
|
|
"""
|
|
def create_subdirs!(path, number) do
|
|
for n <- 1..number//1 do
|
|
child_path = Path.join(path, "subdir#{n}")
|
|
File.mkdir_p!(child_path)
|
|
child_path
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Applies the given list of operations to `Livebook.Session.Data`.
|
|
|
|
Raises if any of the operations results in an error.
|
|
"""
|
|
def data_after_operations!(data \\ Data.new(), operations) do
|
|
operations
|
|
|> List.flatten()
|
|
|> Enum.reduce(data, fn operation, data ->
|
|
case Data.apply_operation(data, operation) do
|
|
{:ok, data, _action} ->
|
|
data
|
|
|
|
:error ->
|
|
raise "failed to set up test data, operation #{inspect(operation)} returned an error"
|
|
end
|
|
end)
|
|
end
|
|
|
|
@doc """
|
|
Converts a Unix-like absolute path into OS-compatible absolute path.
|
|
"""
|
|
defmacro p("/" <> path), do: Path.expand("/") <> path
|
|
|
|
@doc """
|
|
Confirms the action guarded by `LivebookWeb.Confirm/3` and
|
|
returns the rendered result.
|
|
"""
|
|
def render_confirm(view, options \\ %{}) do
|
|
options =
|
|
for {option, value} <- options,
|
|
into: %{},
|
|
do: {Atom.to_string(option), Atom.to_string(value)}
|
|
|
|
view
|
|
|> element(~s/[data-el-confirm-form]/)
|
|
|> render_submit(%{"options" => options})
|
|
end
|
|
|
|
@doc """
|
|
Builds code that renders the given output as part of evaluation.
|
|
"""
|
|
def source_for_output(output) do
|
|
quote do
|
|
send(
|
|
Process.group_leader(),
|
|
{:io_request, self(), make_ref(), {:livebook_put_output, unquote(Macro.escape(output))}}
|
|
)
|
|
end
|
|
|> Macro.to_string()
|
|
end
|
|
|
|
@doc """
|
|
Builds code that renders the given output as part of evaluation.
|
|
"""
|
|
def source_for_input_read(input_id) do
|
|
quote do
|
|
send(
|
|
Process.group_leader(),
|
|
{:io_request, self(), make_ref(), {:livebook_get_input_value, unquote(input_id)}}
|
|
)
|
|
end
|
|
|> Macro.to_string()
|
|
end
|
|
|
|
@doc """
|
|
Builds code that awaits for a messages before finishing.
|
|
|
|
Returns `{code, continue_fun}`, where calling `continue_fun` should
|
|
continue execution. Embedded runtime must be used for this to work.
|
|
"""
|
|
def source_for_blocking() do
|
|
name = Livebook.Utils.random_short_id() |> String.to_atom()
|
|
|
|
code =
|
|
quote do
|
|
# This test uses the Embedded runtime, so we can target the
|
|
# process by name
|
|
Process.register(self(), unquote(name))
|
|
receive do: (:stop -> :ok)
|
|
end
|
|
|> Macro.to_string()
|
|
|
|
ack_fun = fn ->
|
|
send(Process.whereis(name), :pong)
|
|
end
|
|
|
|
{code, ack_fun}
|
|
end
|
|
|
|
@doc """
|
|
Builds a terminal output map.
|
|
"""
|
|
defmacro terminal_text(text, chunk \\ false) do
|
|
quote do
|
|
%{type: :terminal_text, text: unquote(text), chunk: unquote(chunk)}
|
|
end
|
|
end
|
|
|
|
def clean_message(message) do
|
|
message
|
|
|> remove_trailing_whitespace()
|
|
|> remove_ansi()
|
|
end
|
|
|
|
defp remove_trailing_whitespace(string) do
|
|
String.replace(string, ~r/ +$/m, "")
|
|
end
|
|
|
|
defp remove_ansi(string) do
|
|
String.replace(string, ~r/\e\[\d+m/, "")
|
|
end
|
|
end
|