defmodule PlausibleWeb.Live.SharedLinkSettingsTest do use PlausibleWeb.ConnCase, async: true import Phoenix.LiveViewTest describe "SharedLinkSettings LiveView" do setup [:create_user, :log_in, :create_site] setup %{user: user, site: site} do subscribe_to_growth_plan(user) {:ok, session: %{"site_id" => site.id, "domain" => site.domain}} end test "guest editors should be able to access shared link settings", %{ site: site, conn: conn, session: session } do insert(:shared_link, site: site, name: "Link 1") guest_user = new_user() add_guest(site, user: guest_user, role: :editor) {:ok, conn: conn} = log_in(%{user: guest_user, conn: conn}) lv = get_liveview(conn, session) lock_notice = render(lv) |> text_of_element("#lock-notice") refute lock_notice =~ "upgrade your subscription" end test "allows shared link deletion", %{conn: conn, site: site, session: session} do link1 = insert(:shared_link, site: site, name: "Link 1") link2 = insert(:shared_link, site: site, name: "Link 2") lv = get_liveview(conn, session) html = render(lv) assert html =~ "Link 1" assert html =~ "Link 2" html = lv |> element(~s/button[phx-click="delete-shared-link"][phx-value-slug="#{link1.slug}"]/) |> render_click() refute html =~ "Link 1" assert html =~ "Link 2" assert html =~ "Shared link deleted" # Verify it's actually deleted from database refute Plausible.Repo.get_by(Plausible.Site.SharedLink, slug: link1.slug) assert Plausible.Repo.get_by(Plausible.Site.SharedLink, slug: link2.slug) end test "shows success message when link is deleted", %{conn: conn, site: site, session: session} do link = insert(:shared_link, site: site, name: "Test Link") lv = get_liveview(conn, session) html = lv |> element(~s/button[phx-click="delete-shared-link"][phx-value-slug="#{link.slug}"]/) |> render_click() assert html =~ "Shared link deleted" refute html =~ "Test Link" end test "shows error message when trying to delete non-existent link (race condition)", %{ conn: conn, site: site, session: session } do # Simulate race condition: link exists when page loads, but is deleted # by another user/process before we click delete link = insert(:shared_link, site: site, name: "Test Link") lv = get_liveview(conn, session) html = render(lv) assert html =~ "Test Link" Plausible.Repo.delete!(link) html = lv |> element(~s/button[phx-click="delete-shared-link"][phx-value-slug="#{link.slug}"]/) |> render_click() assert html =~ "Could not find Shared Link" end test "displays shared links with password indicators", %{ conn: conn, site: site, session: session } do link_with_password = insert(:shared_link, site: site, name: "Protected", password: "secret") link_without_password = insert(:shared_link, site: site, name: "Public") lv = get_liveview(conn, session) html = render(lv) assert html =~ "Protected" assert html =~ "value=\"#{Plausible.Sites.shared_link_url(site, link_with_password)}\"" assert html =~ "Public" assert html =~ "value=\"#{Plausible.Sites.shared_link_url(site, link_without_password)}\"" # Check for lock icons assert element_exists?(html, ~s|svg|) end test "displays empty state when no shared links", %{conn: conn, session: session} do lv = get_liveview(conn, session) html = render(lv) assert html =~ "Create your first shared link" end test "cannot edit shared link from another site by passing its slug as a param", %{ conn: conn, site: site, session: session } do _own_link = insert(:shared_link, site: site, name: "Own Link") victim_site = insert(:site) victim_link = insert(:shared_link, site: victim_site, name: "Victim Link") lv = get_liveview(conn, session) html = render_click(lv, "edit-shared-link", %{"slug" => victim_link.slug}) refute html =~ "Edit shared link" assert html =~ "Could not find Shared Link" # Verify the victim's shared link is unchanged in the database reloaded = Plausible.Repo.reload!(victim_link) assert reloaded.name == "Victim Link" end end defp get_liveview(conn, session) do {:ok, lv, _html} = live_isolated(conn, PlausibleWeb.Live.SharedLinkSettings, session: session) lv end end