Files
bDS2/test/bds/desktop_test.exs

248 lines
8.9 KiB
Elixir

defmodule BDS.DesktopTest do
use ExUnit.Case, async: false
import Plug.Test
defmodule TestFolderPicker do
def choose_directory(_prompt), do: Process.get(:test_folder_picker_response, :cancel)
end
test "desktop configuration no longer uses a pending adapter" do
assert Application.get_env(:bds, BDS.Application)[:desktop_adapter] == :desktop
end
test "desktop child specs include the local shell server and desktop window in non-test environments" do
children = BDS.Application.desktop_children(:dev)
child_ids = Enum.map(children, &Supervisor.child_spec(&1, []).id)
assert Enum.any?(children, fn child ->
match?({BDS.Desktop.Server, _opts}, child)
end)
assert Enum.any?(children, fn child ->
match?({Desktop.Window, opts} when is_list(opts), child) and
Keyword.fetch!(elem(child, 1), :id) == BDS.Desktop.MainWindow
end)
assert Enum.uniq(child_ids) == child_ids
end
test "desktop children stay disabled in test so command-line tests do not spawn wx windows" do
assert BDS.Application.desktop_children(:test) == []
end
test "desktop shell url points at the embedded shell route" do
url = BDS.Desktop.url(4011)
assert url == "http://127.0.0.1:4011/"
end
test "desktop menu bar exposes the native menu groups for the shell window" do
groups = BDS.Desktop.MenuBar.groups(dev_mode?: false)
item_ids = fn items ->
items
|> Enum.reject(&Map.get(&1, :separator, false))
|> Enum.map(& &1.id)
end
assert Enum.map(groups, & &1.id) == [:file, :edit, :view, :blog, :help]
view_group = Enum.find(groups, &(&1.id == :view))
assert :toggle_sidebar in item_ids.(view_group.items)
assert :toggle_panel in item_ids.(view_group.items)
assert :toggle_assistant_sidebar in item_ids.(view_group.items)
blog_group = Enum.find(groups, &(&1.id == :blog))
blog_actions = item_ids.(blog_group.items)
assert :metadata_diff in blog_actions
assert :edit_menu in blog_actions
assert :rebuild_database in blog_actions
assert :find_duplicates in blog_actions
assert :validate_site in blog_actions
help_group = Enum.find(groups, &(&1.id == :help))
help_actions = item_ids.(help_group.items)
assert :documentation in help_actions
assert :api_documentation in help_actions
end
test "desktop shell html follows the old app frame regions and references bundled assets" do
html = BDS.Desktop.ShellController.index_html()
assert html =~ ~s(class="app")
assert html =~ ~s(class="window-titlebar")
assert html =~ ~s(class="activity-bar")
assert html =~ ~s(class="sidebar")
assert html =~ ~s(class="tab-bar")
assert html =~ ~s(class="status-bar")
assert html =~ ~s(src="/assets/app.js")
assert html =~ ~s(href="/assets/app.css")
end
test "desktop router serves the shell without requiring Phoenix endpoint secrets" do
conn = conn(:get, "/?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
assert conn.resp_body =~ ~s(class="app")
end
test "desktop router exposes live task status for shell polling" do
assert {:ok, task} =
BDS.Tasks.register_external_task("preview build", %{
group_id: "generation",
group_name: "Generation"
})
on_exit(fn ->
_ = BDS.Tasks.complete_task(task.id)
end)
assert :ok = BDS.Tasks.report_progress(task.id, 0.5, "halfway")
conn = conn(:get, "/api/tasks?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
assert Plug.Conn.get_resp_header(conn, "content-type") == ["application/json; charset=utf-8"]
payload = Jason.decode!(conn.resp_body)
assert payload["active_count"] >= 1
assert payload["running_task_message"] == "preview build: halfway"
assert Enum.any?(payload["tasks"], fn item ->
item["id"] == task.id and item["group_name"] == "Generation" and item["progress"] == 0.5
end)
end
test "desktop router exposes projects for shell project selection and creation" do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
BDS.Repo.delete_all(BDS.Projects.Project)
internal_projects_root = "/Users/gb/Projects/bDS2/priv/data/projects"
before_internal_dirs =
case File.ls(internal_projects_root) do
{:ok, entries} -> MapSet.new(entries)
{:error, :enoent} -> MapSet.new()
end
temp_dir = Path.join(System.tmp_dir!(), "bds-desktop-projects-#{System.unique_integer([:positive])}")
File.mkdir_p!(temp_dir)
on_exit(fn ->
File.rm_rf(temp_dir)
end)
{:ok, project} = BDS.Projects.create_project(%{name: "Desktop Projects", data_path: temp_dir})
{:ok, _active} = BDS.Projects.set_active_project(project.id)
conn = conn(:get, "/api/projects?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
payload = Jason.decode!(conn.resp_body)
assert payload["active_project_id"] == project.id
assert Enum.any?(payload["projects"], &(&1["id"] == project.id and &1["name"] == "Desktop Projects"))
assert Enum.any?(payload["projects"], &(&1["id"] == "default" and &1["name"] == "My Blog"))
created_data_dir = Path.join(temp_dir, "created-from-shell")
create_conn =
conn(
:post,
"/api/projects?k=#{Desktop.Auth.login_key()}",
Jason.encode!(%{"name" => "Created From Shell", "data_path" => created_data_dir})
)
|> Plug.Conn.put_req_header("content-type", "application/json")
create_conn = BDS.Desktop.Router.call(create_conn, BDS.Desktop.Router.init([]))
assert create_conn.status == 200
created_payload = Jason.decode!(create_conn.resp_body)
assert created_payload["project"]["name"] == "Created From Shell"
assert created_payload["active_project_id"] == created_payload["project"]["id"]
assert created_payload["project"]["data_path"] == created_data_dir
after_internal_dirs =
case File.ls(internal_projects_root) do
{:ok, entries} -> MapSet.new(entries)
{:error, :enoent} -> MapSet.new()
end
assert after_internal_dirs == before_internal_dirs
end
test "desktop router lets the shell choose an existing project folder and reuses matching projects" do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
temp_dir = Path.join(System.tmp_dir!(), "bds-desktop-existing-project-#{System.unique_integer([:positive])}")
meta_dir = Path.join(temp_dir, "meta")
File.mkdir_p!(meta_dir)
File.write!(
Path.join(meta_dir, "project.json"),
Jason.encode!(%{"name" => "Existing Blog", "description" => "Imported from disk"})
)
{:ok, project} = BDS.Projects.create_project(%{name: "Existing Blog", data_path: temp_dir})
previous_desktop = Application.get_env(:bds, :desktop, [])
Application.put_env(:bds, :desktop, Keyword.put(previous_desktop, :folder_picker, TestFolderPicker))
Process.put(:test_folder_picker_response, {:ok, temp_dir})
on_exit(fn ->
Application.put_env(:bds, :desktop, previous_desktop)
Process.delete(:test_folder_picker_response)
File.rm_rf(temp_dir)
end)
conn = conn(:post, "/api/project-folder?k=#{Desktop.Auth.login_key()}")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
payload = Jason.decode!(conn.resp_body)
assert payload["status"] == "ok"
assert payload["path"] == temp_dir
assert payload["name"] == "Existing Blog"
assert payload["description"] == "Imported from disk"
assert payload["existing_project_id"] == project.id
end
test "desktop router executes shell commands through the JSON api" do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo)
:ok = Ecto.Adapters.SQL.Sandbox.allow(BDS.Repo, self(), Process.whereis(BDS.Preview))
temp_dir = Path.join(System.tmp_dir!(), "bds-desktop-router-#{System.unique_integer([:positive])}")
File.mkdir_p!(temp_dir)
on_exit(fn ->
File.rm_rf(temp_dir)
_ = BDS.Preview.stop_preview("default")
end)
{:ok, project} = BDS.Projects.create_project(%{name: "Desktop Router", data_path: temp_dir})
{:ok, _project} = BDS.Projects.set_active_project(project.id)
conn =
conn(:post, "/api/commands?k=#{Desktop.Auth.login_key()}", Jason.encode!(%{"action" => "open_in_browser"}))
|> Plug.Conn.put_req_header("content-type", "application/json")
conn = BDS.Desktop.Router.call(conn, BDS.Desktop.Router.init([]))
assert conn.status == 200
assert Plug.Conn.get_resp_header(conn, "content-type") == ["application/json; charset=utf-8"]
payload = Jason.decode!(conn.resp_body)
assert payload["result"]["kind"] == "open_url"
assert payload["result"]["project_id"] == project.id
assert payload["result"]["url"] == "http://127.0.0.1:4123/"
end
end