feat: step 11 done

This commit is contained in:
2026-04-29 19:24:45 +02:00
parent 4ae6c55e83
commit 155fda8b81
6 changed files with 284 additions and 9 deletions

View File

@@ -4,6 +4,7 @@ defmodule BDS.CliSyncTest do
import Ecto.Query
alias BDS.CliSync
alias BDS.CliSync.Watcher
alias BDS.Repo
setup do
@@ -24,6 +25,25 @@ defmodule BDS.CliSyncTest do
assert is_integer(seen_notification.seen_at)
end
test "watcher broadcasts entity change events after database mutations are detected" do
Ecto.Adapters.SQL.Sandbox.mode(BDS.Repo, {:shared, self()})
Phoenix.PubSub.subscribe(BDS.PubSub, Watcher.topic())
watcher =
start_supervised!({Watcher, poll_interval_ms: 60_000, debounce_ms: 0})
Ecto.Adapters.SQL.Sandbox.allow(BDS.Repo, self(), watcher)
assert {:ok, notification} = CliSync.cli_mutation_performed("post", "post-1", :updated)
:ok = Watcher.poll_now(watcher)
assert_receive {:entity_changed, %{entity: "post", entity_id: "post-1", action: :updated}}, 500
seen_notification = Repo.get!(BDS.CliSync.Notification, notification.id)
assert is_integer(seen_notification.seen_at)
end
test "processed notifications are pruned after one hour and unprocessed notifications after one day" do
now = BDS.Persistence.now_ms()

View File

@@ -6,6 +6,7 @@ defmodule BDS.Desktop.ShellLiveTest do
alias BDS.Persistence
alias BDS.AI
alias BDS.CliSync.Watcher
alias BDS.Menu
alias BDS.Media
alias BDS.Metadata
@@ -203,6 +204,71 @@ defmodule BDS.Desktop.ShellLiveTest do
assert html =~ ~s(data-tab-id="#{created_definition.id}")
end
test "shell live refreshes the posts sidebar when the CLI watcher broadcasts an entity change", %{project: project} do
{:ok, view, html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
refute html =~ "CLI Added Post"
assert {:ok, post} = Posts.create_post(%{project_id: project.id, title: "CLI Added Post"})
Phoenix.PubSub.broadcast(BDS.PubSub, Watcher.topic(), {:entity_changed, %{entity: "post", entity_id: post.id, action: :created}})
assert render(view) =~ "CLI Added Post"
end
test "shell live closes stale post and media tabs when the CLI watcher broadcasts deletions", %{project: project, temp_dir: temp_dir} do
assert {:ok, post} = Posts.create_post(%{project_id: project.id, title: "CLI Delete Post"})
source_path = Path.join(temp_dir, "cli-delete-media.txt")
File.write!(source_path, "media body")
assert {:ok, media} =
Media.import_media(%{
project_id: project.id,
source_path: source_path,
title: "CLI Delete Media"
})
{:ok, view, _html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)
html =
view
|> element("[data-testid='sidebar-open-item'][data-item-id='#{post.id}']")
|> render_click()
assert html =~ ~s(data-tab-type="post")
assert html =~ ~s(data-tab-id="#{post.id}")
assert {:ok, :deleted} = Posts.delete_post(post.id)
Phoenix.PubSub.broadcast(BDS.PubSub, Watcher.topic(), {:entity_changed, %{entity: "post", entity_id: post.id, action: :deleted}})
html = render(view)
refute html =~ ~s(data-tab-type="post")
refute html =~ "CLI Delete Post"
_html =
view
|> element("[data-testid='activity-button'][data-view='media']")
|> render_click()
html =
view
|> element("[data-testid='sidebar-open-item'][data-item-id='#{media.id}']")
|> render_click()
assert html =~ ~s(data-tab-type="media")
assert html =~ ~s(data-tab-id="#{media.id}")
assert {:ok, :deleted} = Media.delete_media(media.id)
Phoenix.PubSub.broadcast(BDS.PubSub, Watcher.topic(), {:entity_changed, %{entity: "media", entity_id: media.id, action: :deleted}})
html = render(view)
refute html =~ ~s(data-tab-type="media")
refute html =~ "CLI Delete Media"
end
test "shell live owns pane visibility and activity selection on the server" do
{:ok, view, html} = live_isolated(build_conn(), BDS.Desktop.ShellLive)