From 63d6c9f215bf012c5e924a075bafdc977dbf7a77 Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sat, 30 May 2026 20:10:13 +0200 Subject: [PATCH] D4-4: add script editor UI tests for save, run, check syntax, delete --- SPECGAPS.md | 2 +- test/bds/desktop/shell_live_test.exs | 127 +++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/SPECGAPS.md b/SPECGAPS.md index 3210020..30afa4b 100644 --- a/SPECGAPS.md +++ b/SPECGAPS.md @@ -179,7 +179,7 @@ All reconciled to follow code. Specs must be self-consistent and match code. | ~~D4-1~~ | ~~editor_media.allium~~ | ~~AI analysis, delete~~ | ~~Translate, replace file, link-to-post, translation CRUD, detect language~~ | **Resolved:** backend tests cover replace_file, link-to-post, translation CRUD (upsert + unique constraint); added standalone `delete_media_translation/2` test (row + sidecar deletion, no-op for non-existent, not-found for unknown media); added `MediaDetectLanguage` rule integration test (AI mock, language persisted, sidecar rewritten) | | ~~D4-2~~ | ~~editor_settings.allium~~ | ~~AI endpoints, airplane toggle, rebuild~~ | ~~Protected categories~~ (resolved D1-17), ~~MCP agents~~ (6 `mcp_rows` + 3 `toggle_mcp_agent` tests), ~~style/theme~~ (19 `build_style` + 4 select/change/apply/display tests), ~~search filter~~ (9 `build_settings` visibility tests), ~~categories CRUD~~ (7 `category_rows` + 2 update + 3 add + 2 save + 4 reset tests) | **Resolved:** 3 new test files (mcp_config_test.exs, style_editor_test.exs, settings_search_test.exs) + expanded managed_categories_test.exs cover all untested areas. Total 56 tests added across MCP agents, style/theme, search filter, and categories CRUD. | | D4-3 | ~~editor_chat.allium~~ | ~~Chat creation, pinned tab~~ | ~~API key screen, message rendering, input area, model selector, inline surfaces~~ | **Resolved:** 3 tests added — WelcomeScreen assertions (robot icon, title, 5 tips), CSP external image rewriting in markdown, chart inline surface rendering with series labels/values | -| D4-4 | editor_script.allium | Editor layout, create defaults | Save, syntax check, run, delete | +| D4-4 | editor_script.allium | Editor layout, create defaults | ~~Save, syntax check, run, delete~~ | **Resolved:** 4 tests added — save persists title change + version bump to DB, run executes script without crash, check syntax validates without side effects, delete removes DB record + file | | D4-5 | editor_template.allium | Editor layout, create defaults | Save with validation, validate, delete with references | | D4-6 | editor_tags.allium | Sync/discover, merge | Cloud sizing, color picker, delete confirmation, create form | | D4-7 | editor_misc.allium | Menu add/save, metadata diff, validation | Menu protection, import analysis, translation fix, duplicate dismiss, git diff | diff --git a/test/bds/desktop/shell_live_test.exs b/test/bds/desktop/shell_live_test.exs index ef6bac8..a674110 100644 --- a/test/bds/desktop/shell_live_test.exs +++ b/test/bds/desktop/shell_live_test.exs @@ -5374,6 +5374,133 @@ defmodule BDS.Desktop.ShellLiveTest do assert length(:binary.matches(html, ~s(class="chat-surface-chart-row"))) == 2 end + test "script editor save persists draft changes to the database", %{project: project} do + {:ok, script} = + Scripts.create_script(%{ + project_id: project.id, + title: "Save Test", + kind: :utility, + content: "function main() return 42 end" + }) + + {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) + + render_click(view, "pin_sidebar_item", %{ + "route" => "scripts", + "id" => script.id, + "title" => script.title, + "subtitle" => "draft" + }) + + view + |> form(".scripts-view-shell form", %{script_editor: %{title: "Updated Save Test"}}) + |> render_change() + + html = + view + |> element(".scripts-save-button") + |> render_click() + + assert html =~ "Updated Save Test" + + saved = Scripts.get_script(script.id) + assert saved.title == "Updated Save Test" + assert saved.version == 2 + end + + test "script editor run executes the script without crashing", %{project: project} do + {:ok, script} = + Scripts.create_script(%{ + project_id: project.id, + title: "Run Test", + kind: :utility, + content: "function main() return 42 end" + }) + + {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) + + render_click(view, "pin_sidebar_item", %{ + "route" => "scripts", + "id" => script.id, + "title" => script.title, + "subtitle" => "draft" + }) + + html = + view + |> element(".scripts-run-button") + |> render_click() + + assert html =~ ~s(data-testid="script-editor") + + reloaded = Scripts.get_script(script.id) + assert reloaded.title == "Run Test" + assert reloaded.version == 1 + end + + test "script editor check syntax validates lua content without saving", %{project: project} do + {:ok, script} = + Scripts.create_script(%{ + project_id: project.id, + title: "Check Test", + kind: :utility, + content: "function main() return 42 end" + }) + + {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) + + render_click(view, "pin_sidebar_item", %{ + "route" => "scripts", + "id" => script.id, + "title" => script.title, + "subtitle" => "draft" + }) + + html = + view + |> element(".scripts-check-button") + |> render_click() + + assert html =~ ~s(data-testid="script-editor") + + reloaded = Scripts.get_script(script.id) + assert reloaded.title == "Check Test" + assert reloaded.version == 1 + end + + test "script editor delete removes the record and published file", %{ + project: project, + temp_dir: temp_dir + } do + {:ok, script} = + Scripts.create_script(%{ + project_id: project.id, + title: "Delete Test", + kind: :utility, + content: "function main() return 42 end" + }) + + assert {:ok, published} = Scripts.publish_script(script.id) + published_path = Path.join(temp_dir, published.file_path) + assert File.exists?(published_path) + + {:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive) + + render_click(view, "pin_sidebar_item", %{ + "route" => "scripts", + "id" => published.id, + "title" => published.title, + "subtitle" => "published" + }) + + view + |> element(".scripts-view-shell .ui-button-danger") + |> render_click() + + assert Repo.get(BDS.Scripts.Script, published.id) == nil + refute File.exists?(published_path) + end + # Sends a message to the LiveView and blocks until it has been processed. # Uses a test ping/pong to guarantee the message was handled before returning. defp send_and_await(view, message) do