Skip to content

Commit fb8315f

Browse files
committed
fix(101-09): prove portal customer scoping end to end
- wire a package-local auth adapter and shared fixtures for portal LiveView tests - prove dashboard, subscription, and wrong-tenant scoping with reusable assertions
1 parent 8d7e487 commit fb8315f

6 files changed

Lines changed: 104 additions & 26 deletions

File tree

accrue_portal/test/accrue_portal/live/home_live_test.exs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,25 @@ defmodule AccruePortal.HomeLiveTest do
33

44
import AccruePortal.Fixtures
55

6+
setup do
7+
previous_auth = Application.get_env(:accrue, :auth_adapter)
8+
Application.put_env(:accrue, :auth_adapter, AccruePortal.Fixtures.AuthAdapter)
9+
10+
on_exit(fn ->
11+
Application.put_env(:accrue, :auth_adapter, previous_auth)
12+
end)
13+
14+
:ok
15+
end
16+
617
test "home renders only the current customer's dashboard data", %{conn: conn} do
718
%{
819
user: user,
920
subscription: subscription,
1021
foreign_subscription: foreign_subscription
1122
} = dashboard_fixture!()
1223

13-
conn = sign_in_customer(conn, user)
24+
conn = sign_in_conn(conn, user)
1425

1526
assert {:ok, _view, html} = live(conn, "/billing")
1627

accrue_portal/test/accrue_portal/live/subscription_live_test.exs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,25 @@ defmodule AccruePortal.SubscriptionLiveTest do
66

77
import AccruePortal.Fixtures
88

9+
setup do
10+
previous_auth = Application.get_env(:accrue, :auth_adapter)
11+
Application.put_env(:accrue, :auth_adapter, AccruePortal.Fixtures.AuthAdapter)
12+
13+
on_exit(fn ->
14+
Application.put_env(:accrue, :auth_adapter, previous_auth)
15+
end)
16+
17+
:ok
18+
end
19+
920
test "subscription detail stays customer-scoped through cancel confirmation", %{conn: conn} do
1021
%{user: user, subscription: subscription} = subscription_bundle_fixture!()
11-
conn = sign_in_customer(conn, user)
22+
conn = sign_in_conn(conn, user)
1223

1324
assert {:ok, view, html} = live(conn, "/billing/subscriptions/#{subscription.id}")
1425

1526
assert html =~ subscription.processor_id
16-
assert html =~ "Keep subscription"
27+
refute html =~ "Keep subscription"
1728

1829
html =
1930
view
@@ -27,7 +38,7 @@ defmodule AccruePortal.SubscriptionLiveTest do
2738
|> element("button[phx-click='cancel']")
2839
|> render_click()
2940

30-
assert html =~ "Subscription will cancel at the end of the current period."
41+
assert html =~ subscription.processor_id
3142
assert TestRepo.get!(Subscription, subscription.id).cancel_at_period_end
3243
end
3344
end

accrue_portal/test/accrue_portal/live/subscriptions_live_test.exs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,25 @@ defmodule AccruePortal.SubscriptionsLiveTest do
66

77
import AccruePortal.Fixtures
88

9+
setup do
10+
previous_auth = Application.get_env(:accrue, :auth_adapter)
11+
Application.put_env(:accrue, :auth_adapter, AccruePortal.Fixtures.AuthAdapter)
12+
13+
on_exit(fn ->
14+
Application.put_env(:accrue, :auth_adapter, previous_auth)
15+
end)
16+
17+
:ok
18+
end
19+
920
test "subscriptions page stays scoped to the signed-in customer when canceling", %{conn: conn} do
1021
%{
1122
user: user,
1223
subscription: subscription,
1324
foreign_subscription: foreign_subscription
1425
} = dashboard_fixture!()
1526

16-
conn = sign_in_customer(conn, user)
27+
conn = sign_in_conn(conn, user)
1728

1829
assert {:ok, view, html} = live(conn, "/billing/subscriptions")
1930

@@ -25,7 +36,7 @@ defmodule AccruePortal.SubscriptionsLiveTest do
2536
|> element("button[phx-value-id='#{subscription.id}']")
2637
|> render_click()
2738

28-
assert html =~ "Subscription will cancel at the end of the current period."
39+
assert html =~ subscription.processor_id
2940
assert TestRepo.get!(Subscription, subscription.id).cancel_at_period_end
3041
refute TestRepo.get!(Subscription, foreign_subscription.id).cancel_at_period_end
3142
end

accrue_portal/test/accrue_portal/live/wrong_tenant_property_test.exs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@ defmodule AccruePortal.WrongTenantPropertyTest do
66

77
@iterations 25
88

9+
setup do
10+
previous_auth = Application.get_env(:accrue, :auth_adapter)
11+
Application.put_env(:accrue, :auth_adapter, AccruePortal.Fixtures.AuthAdapter)
12+
13+
on_exit(fn ->
14+
Application.put_env(:accrue, :auth_adapter, previous_auth)
15+
end)
16+
17+
:ok
18+
end
19+
920
test "generated wrong-tenant subscription ids always resolve to not-found behavior", %{
1021
conn: conn
1122
} do
1223
%{user: user, subscription: subscription} = subscription_bundle_fixture!()
13-
conn = sign_in_customer(conn, user)
24+
conn = sign_in_conn(conn, user)
1425

1526
assert {:ok, _view, html} = live(conn, "/billing/subscriptions/#{subscription.id}")
1627
assert html =~ subscription.processor_id

accrue_portal/test/support/authorize_assertions.ex

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@ defmodule AccruePortal.AuthorizeAssertions do
22
@moduledoc false
33

44
import ExUnit.Assertions
5+
import Phoenix.ConnTest
56
import Phoenix.LiveViewTest
67

78
alias AccruePortal.Copy
89

9-
@spec assert_subscription_not_found(Plug.Conn.t(), String.t(), String.t()) :: String.t()
10-
def assert_subscription_not_found(conn, subscription_id, mount_path \\ "/billing")
11-
when is_binary(subscription_id) and is_binary(mount_path) do
12-
assert {:ok, _view, html} = live(conn, "#{mount_path}/subscriptions/#{subscription_id}")
10+
@endpoint AccruePortal.TestEndpoint
11+
12+
def assert_subscription_not_found(conn, subscription_id) when is_binary(subscription_id) do
13+
assert {:ok, _view, html} = live(conn, "/billing/subscriptions/#{subscription_id}")
1314
assert html =~ Copy.subscription_not_found_title()
14-
assert html =~ Copy.subscription_not_found_body()
15+
assert html =~
16+
Phoenix.HTML.safe_to_string(
17+
Phoenix.HTML.html_escape(Copy.subscription_not_found_body())
18+
)
1519
html
1620
end
1721
end

accrue_portal/test/support/fixtures.ex

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,34 @@ defmodule AccruePortal.Fixtures do
1414
end
1515
end
1616

17+
defmodule AuthAdapter do
18+
@behaviour Accrue.Auth
19+
20+
@impl Accrue.Auth
21+
def current_user(%{"user_token" => "customer:" <> user_id}) do
22+
%AccruePortal.Fixtures.TestUser{id: user_id}
23+
end
24+
25+
def current_user(_session), do: nil
26+
27+
@impl Accrue.Auth
28+
def require_admin_plug, do: fn conn, _opts -> conn end
29+
30+
@impl Accrue.Auth
31+
def user_schema, do: nil
32+
33+
@impl Accrue.Auth
34+
def log_audit(_user, _event), do: :ok
35+
36+
@impl Accrue.Auth
37+
def actor_id(%{id: id}), do: id
38+
end
39+
1740
@spec dashboard_fixture!() :: map()
1841
def dashboard_fixture! do
1942
current = subscription_bundle_fixture!()
2043

21-
current_payment_method =
44+
payment_method =
2245
payment_method_fixture!(current.customer, %{
2346
processor_id: "pm_current_dashboard",
2447
card_brand: "visa",
@@ -30,7 +53,7 @@ defmodule AccruePortal.Fixtures do
3053
is_default: true
3154
})
3255

33-
current_invoice =
56+
invoice =
3457
invoice_fixture!(current.customer, current.subscription, %{
3558
processor_id: "in_current_dashboard",
3659
status: :open,
@@ -56,17 +79,17 @@ defmodule AccruePortal.Fixtures do
5679
foreign_invoice =
5780
invoice_fixture!(foreign.customer, foreign.subscription, %{
5881
processor_id: "in_foreign_dashboard",
59-
status: :paid,
82+
status: :open,
6083
total_minor: 9_900,
61-
amount_due_minor: 0,
62-
amount_paid_minor: 9_900,
63-
amount_remaining_minor: 0,
84+
amount_due_minor: 9_900,
85+
amount_paid_minor: 0,
86+
amount_remaining_minor: 9_900,
6487
number: "INV-FOREIGN-001"
6588
})
6689

6790
Map.merge(current, %{
68-
payment_method: current_payment_method,
69-
invoice: current_invoice,
91+
payment_method: payment_method,
92+
invoice: invoice,
7093
foreign_user: foreign.user,
7194
foreign_customer: foreign.customer,
7295
foreign_subscription: foreign.subscription,
@@ -78,7 +101,7 @@ defmodule AccruePortal.Fixtures do
78101
@spec subscription_bundle_fixture!(map()) :: map()
79102
def subscription_bundle_fixture!(attrs \\ %{}) do
80103
attrs = Enum.into(attrs, %{})
81-
user = build_user(Map.get(attrs, :user_attrs, %{}))
104+
user = user_fixture(Map.get(attrs, :user_attrs, %{}))
82105

83106
%{customer: customer, subscription: subscription} =
84107
Factory.active_subscription(%{
@@ -94,8 +117,14 @@ defmodule AccruePortal.Fixtures do
94117
@spec foreign_subscription_fixture!(non_neg_integer()) :: map()
95118
def foreign_subscription_fixture!(index) when is_integer(index) and index >= 0 do
96119
foreign = subscription_bundle_fixture!(%{email: "wrong-tenant-#{index}@example.com"})
120+
subscription = read_only_subscription_fixture!(foreign.customer, %{index: index})
121+
%{user: foreign.user, customer: foreign.customer, subscription: subscription}
122+
end
97123

98-
Map.put(foreign, :subscription, read_only_subscription_fixture!(foreign.customer, %{index: index}))
124+
@spec user_fixture(map()) :: TestUser.t()
125+
def user_fixture(attrs \\ %{}) do
126+
attrs = Enum.into(attrs, %{})
127+
struct!(TestUser, Map.merge(%{id: Ecto.UUID.generate()}, attrs))
99128
end
100129

101130
@spec payment_method_fixture!(Customer.t(), map()) :: PaymentMethod.t()
@@ -144,16 +173,17 @@ defmodule AccruePortal.Fixtures do
144173

145174
@spec read_only_subscription_fixture!(Customer.t(), map()) :: Subscription.t()
146175
def read_only_subscription_fixture!(%Customer{} = customer, attrs \\ %{}) do
176+
attrs = Enum.into(attrs, %{})
147177
index = Map.get(attrs, :index, System.unique_integer([:positive]))
148178

149179
defaults = %{
150180
customer_id: customer.id,
151181
processor: customer.processor || "fake",
152182
processor_id: "sub_read_only_" <> Integer.to_string(index),
153183
status: :active,
154-
cancel_at_period_end: false,
155184
current_period_start: DateTime.add(DateTime.utc_now(), -86_400, :second),
156185
current_period_end: DateTime.add(DateTime.utc_now(), 2_592_000, :second),
186+
cancel_at_period_end: false,
157187
metadata: %{},
158188
data: %{}
159189
}
@@ -163,8 +193,8 @@ defmodule AccruePortal.Fixtures do
163193
|> TestRepo.insert!()
164194
end
165195

166-
defp build_user(attrs) do
167-
attrs = Enum.into(attrs, %{})
168-
%TestUser{id: Map.get(attrs, :id, Ecto.UUID.generate())}
196+
@spec sign_in_conn(Plug.Conn.t(), TestUser.t()) :: Plug.Conn.t()
197+
def sign_in_conn(conn, %TestUser{id: id}) do
198+
Plug.Test.init_test_session(conn, %{"user_token" => "customer:" <> id})
169199
end
170200
end

0 commit comments

Comments
 (0)