analytics/test/plausible_web/live/sites_test.exs
Adrian Gruntkowski 9d97dc1912
Move limit enforcement to accepting site ownership transfer (#3612)
* Move limit enforcement to accepting site ownerhsip transfer

* enforce pageview limit on ownership transfer accept

* Refactor plan limit check logic

* Extract `ensure_can_take_ownership` to `Invitations` context and refactor

* Improve styling of exceeded limits notice in invitation dialog and disable button

* styling improvements to notice

* make transfer_ownership return transfer to self error

* do not allow transferring to user without active subscription WIP

* Add missing typespec and improve existing ones

* Fix formatting

* Explicitly label direct match on function argument for clarity

* Slightly refactor `CreateInvitation.bulk_transfer_ownership_direct`

* Exclude quota enforcement tests from small build test suite

* Remove unused return type from `invite_error()` union type

* Do not block plan upgrade when there's pending ownership transfer

* Don't block and only warn about missing features on transfer

* Remove `x-init` attribute used for debugging

* Add tests for `Quota.monthly_pageview_usage/2`

* Test and improve site admin ownership transfer actions

* Extend tests for `AcceptInvitation.transfer_ownership`

* Test transfer ownership controller level accept action error cases

* Test choosing plan by user without sites but with a pending ownership transfer

* Test invitation x-data in sites LV

* Remove sitelocker trigger in invitation acceptance code and simplify logic

* Add Quota test for `user.allow_next_upgrade_override` being set

* ignore pageview limit only when subscribing to plan

* Use sandbox Paddle instance for staging

* Use sandbox paddle key for staging and dev

---------

Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
2023-12-20 14:56:49 +00:00

229 lines
6.4 KiB
Elixir

defmodule PlausibleWeb.Live.SitesTest do
use PlausibleWeb.ConnCase, async: true
import Phoenix.LiveViewTest
import Plausible.Test.Support.HTML
alias Plausible.Repo
setup [:create_user, :log_in]
describe "/sites" do
test "renders empty sites page", %{conn: conn} do
{:ok, _lv, html} = live(conn, "/sites")
assert text(html) =~ "You don't have any sites yet"
end
@tag :full_build_only
test "renders ownership transfer invitation for a case with no plan", %{
conn: conn,
user: user
} do
site = insert(:site)
invitation =
insert(:invitation,
site_id: site.id,
inviter: build(:user),
email: user.email,
role: :owner
)
{:ok, _lv, html} = live(conn, "/sites")
invitation_data = get_invitation_data(html)
assert get_in(invitation_data, ["invitations", invitation.invitation_id, "no_plan"])
end
@tag :full_build_only
test "renders ownership transfer invitation for a case with exceeded limits", %{
conn: conn,
user: user
} do
site = insert(:site)
insert(:growth_subscription, user: user)
# fill site quota
insert_list(10, :site, members: [user])
invitation =
insert(:invitation,
site_id: site.id,
inviter: build(:user),
email: user.email,
role: :owner
)
{:ok, _lv, html} = live(conn, "/sites")
invitation_data = get_invitation_data(html)
assert get_in(invitation_data, ["invitations", invitation.invitation_id, "exceeded_limits"]) ==
"site limit"
end
@tag :full_build_only
test "renders ownership transfer invitation for a case with missing features", %{
conn: conn,
user: user
} do
site = insert(:site, allowed_event_props: ["dummy"])
insert(:growth_subscription, user: user)
invitation =
insert(:invitation,
site_id: site.id,
inviter: build(:user),
email: user.email,
role: :owner
)
{:ok, _lv, html} = live(conn, "/sites")
invitation_data = get_invitation_data(html)
assert get_in(invitation_data, ["invitations", invitation.invitation_id, "missing_features"]) ==
"Custom Properties"
end
test "renders 24h visitors correctly", %{conn: conn, user: user} do
site = insert(:site, members: [user])
populate_stats(site, [build(:pageview), build(:pageview), build(:pageview)])
{:ok, _lv, html} = live(conn, "/sites")
site_card = text_of_element(html, "li[data-domain=\"#{site.domain}\"]")
assert site_card =~ "3 visitors in last 24h"
assert site_card =~ site.domain
end
test "filters by domain", %{conn: conn, user: user} do
_site1 = insert(:site, domain: "first.example.com", members: [user])
_site2 = insert(:site, domain: "second.example.com", members: [user])
_site3 = insert(:site, domain: "first-another.example.com", members: [user])
{:ok, lv, _html} = live(conn, "/sites")
type_into_input(lv, "filter_text", "firs")
html = render(lv)
assert html =~ "first.example.com"
assert html =~ "first-another.example.com"
refute html =~ "second.example.com"
end
test "filtering plays well with pagination", %{conn: conn, user: user} do
_site1 = insert(:site, domain: "first.another.example.com", members: [user])
_site2 = insert(:site, domain: "second.example.com", members: [user])
_site3 = insert(:site, domain: "third.another.example.com", members: [user])
{:ok, lv, html} = live(conn, "/sites?page_size=2")
assert html =~ "first.another.example.com"
assert html =~ "second.example.com"
refute html =~ "third.another.example.com"
assert html =~ "page=2"
refute html =~ "page=1"
type_into_input(lv, "filter_text", "anot")
html = render(lv)
assert html =~ "first.another.example.com"
refute html =~ "second.example.com"
assert html =~ "third.another.example.com"
refute html =~ "page=1"
refute html =~ "page=2"
end
end
describe "pinning" do
test "renders pin site option when site not pinned", %{conn: conn, user: user} do
site = insert(:site, members: [user])
{:ok, _lv, html} = live(conn, "/sites")
assert text_of_element(
html,
~s/li[data-domain="#{site.domain}"] a[phx-value-domain]/
) == "Pin Site"
end
test "site state changes when pin toggled", %{conn: conn, user: user} do
site = insert(:site, members: [user])
{:ok, lv, _html} = live(conn, "/sites")
button_selector = ~s/li[data-domain="#{site.domain}"] a[phx-value-domain]/
html =
lv
|> element(button_selector)
|> render_click()
assert html =~ "Site pinned"
assert text_of_element(html, button_selector) == "Unpin Site"
html =
lv
|> element(button_selector)
|> render_click()
assert html =~ "Site unpinned"
assert text_of_element(html, button_selector) == "Pin Site"
end
test "shows error when pins limit hit", %{conn: conn, user: user} do
for _ <- 1..9 do
site = insert(:site, members: [user])
assert {:ok, _} = Plausible.Sites.toggle_pin(user, site)
end
site = insert(:site, members: [user])
{:ok, lv, _html} = live(conn, "/sites")
button_selector = ~s/li[data-domain="#{site.domain}"] a[phx-value-domain]/
html =
lv
|> element(button_selector)
|> render_click()
assert text(html) =~ "Looks like you've hit the pinned sites limit!"
end
test "does not allow pinning site user doesn't have access to", %{conn: conn, user: user} do
site = insert(:site)
{:ok, lv, _html} = live(conn, "/sites")
render_click(lv, "pin-toggle", %{"domain" => site.domain})
refute Repo.get_by(Plausible.Site.UserPreference, user_id: user.id, site_id: site.id)
end
end
defp type_into_input(lv, id, text) do
lv
|> element("form")
|> render_change(%{id => text})
end
defp get_invitation_data(html) do
html
|> text_of_attr("div[x-data]", "x-data")
|> String.trim("dropdown")
|> String.replace("selectedInvitation:", "\"selectedInvitation\":")
|> String.replace("invitationOpen:", "\"invitationOpen\":")
|> String.replace("invitations:", "\"invitations\":")
|> Jason.decode!()
end
end