mirror of
https://codeberg.org/JasterV/spazio-solazzo.git
synced 2026-04-26 18:20:03 +00:00
write tests & update UI
This commit is contained in:
parent
b7e47f1093
commit
e23ddfd10e
12 changed files with 279 additions and 114 deletions
|
|
@ -106,14 +106,15 @@
|
|||
name="phone_number"
|
||||
id="phone_number"
|
||||
class="w-full pl-11 pr-4 py-3 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-shadow"
|
||||
placeholder="+39"
|
||||
placeholder="+39 123456789"
|
||||
/>
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none">
|
||||
<.icon name="hero-phone" class="size-5 text-slate-400 dark:text-slate-500" />
|
||||
</div>
|
||||
<!-- TODO: Add a text here letting the user know that their phone number won't be used for any commercial purposes -->
|
||||
<!-- but only to contact them personally in case of any problems with a booking -->
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-slate-500 dark:text-slate-400">
|
||||
Your number will only be used to contact you personally about booking issues, never for marketing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<label class="flex items-start gap-3 cursor-pointer group p-3 rounded-lg hover:bg-slate-50 dark:hover:bg-slate-900/50 transition-colors">
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ defmodule SpazioSolazzoWeb.AssetBookingLive do
|
|||
{:noreply, assign(socket, show_success_modal: false)}
|
||||
end
|
||||
|
||||
def handle_info({:create_booking, comment}, socket) do
|
||||
def handle_info({:create_booking, booking_data}, socket) do
|
||||
current_user = socket.assigns.current_user
|
||||
|
||||
result =
|
||||
|
|
@ -64,10 +64,10 @@ defmodule SpazioSolazzoWeb.AssetBookingLive do
|
|||
socket.assigns.asset.id,
|
||||
current_user.id,
|
||||
socket.assigns.selected_date,
|
||||
current_user.name,
|
||||
booking_data.customer_name,
|
||||
current_user.email,
|
||||
current_user.phone_number,
|
||||
comment
|
||||
booking_data.customer_phone,
|
||||
booking_data.customer_comment
|
||||
)
|
||||
|
||||
case result do
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ defmodule SpazioSolazzoWeb.BookingFormLiveComponent do
|
|||
|
||||
def update(assigns, socket) do
|
||||
initial_data = %{
|
||||
"customer_name" => assigns.current_user.name,
|
||||
"customer_phone" => assigns.current_user.phone_number || "",
|
||||
"customer_comment" => ""
|
||||
}
|
||||
|
||||
|
|
@ -25,12 +27,16 @@ defmodule SpazioSolazzoWeb.BookingFormLiveComponent do
|
|||
end
|
||||
|
||||
def handle_event("submit_booking", params, socket) do
|
||||
comment = params["customer_comment"] || ""
|
||||
send(self(), {:create_booking, comment})
|
||||
booking_data = %{
|
||||
customer_name: params["customer_name"] || "",
|
||||
customer_phone: params["customer_phone"] || "",
|
||||
customer_comment: params["customer_comment"] || ""
|
||||
}
|
||||
|
||||
send(self(), {:create_booking, booking_data})
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
# TODO: Make name and phone fields editable
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div>
|
||||
|
|
@ -54,16 +60,25 @@ defmodule SpazioSolazzoWeb.BookingFormLiveComponent do
|
|||
>
|
||||
<div class="mt-6 space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Name
|
||||
<label
|
||||
for="customer_name"
|
||||
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"
|
||||
>
|
||||
Name <span class="text-rose-500">*</span>
|
||||
</label>
|
||||
<div class="flex items-center gap-3 p-4 bg-gradient-to-r from-slate-50 to-sky-50/50 dark:from-slate-900 dark:to-slate-800 rounded-xl border border-slate-200 dark:border-slate-700">
|
||||
<div class="flex-shrink-0">
|
||||
<.icon name="hero-user" class="size-5 text-sky-600 dark:text-sky-400" />
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
name="customer_name"
|
||||
id="customer_name"
|
||||
value={@form[:customer_name].value}
|
||||
required
|
||||
class="w-full pl-11 pr-4 py-3 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-shadow"
|
||||
placeholder="Your full name"
|
||||
/>
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none">
|
||||
<.icon name="hero-user" class="size-5 text-slate-400 dark:text-slate-500" />
|
||||
</div>
|
||||
<span class="text-sm font-medium text-slate-700 dark:text-slate-300 truncate">
|
||||
{@current_user.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -82,26 +97,56 @@ defmodule SpazioSolazzoWeb.BookingFormLiveComponent do
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Phone
|
||||
<label
|
||||
for="customer_phone"
|
||||
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"
|
||||
>
|
||||
Phone (Optional)
|
||||
</label>
|
||||
<div class="flex items-center gap-3 p-4 bg-gradient-to-r from-slate-50 to-sky-50/50 dark:from-slate-900 dark:to-slate-800 rounded-xl border border-slate-200 dark:border-slate-700">
|
||||
<div class="flex-shrink-0">
|
||||
<.icon name="hero-phone" class="size-5 text-sky-600 dark:text-sky-400" />
|
||||
<div class="relative">
|
||||
<input
|
||||
type="tel"
|
||||
name="customer_phone"
|
||||
id="customer_phone"
|
||||
value={@form[:customer_phone].value}
|
||||
class="w-full pl-11 pr-4 py-3 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-shadow"
|
||||
placeholder="+39 123456789"
|
||||
/>
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none">
|
||||
<.icon name="hero-phone" class="size-5 text-slate-400 dark:text-slate-500" />
|
||||
</div>
|
||||
<span class="text-sm font-medium text-slate-700 dark:text-slate-300 truncate">
|
||||
{@current_user.phone_number || "-"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.input
|
||||
field={@form[:customer_comment]}
|
||||
type="textarea"
|
||||
label="Comments (Optional)"
|
||||
placeholder="Any special requests or notes..."
|
||||
rows="4"
|
||||
/>
|
||||
<div>
|
||||
<label
|
||||
for="customer_comment"
|
||||
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"
|
||||
>
|
||||
Comments (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
name="customer_comment"
|
||||
id="customer_comment"
|
||||
placeholder="Any special requests or notes..."
|
||||
rows="4"
|
||||
class="w-full px-4 py-3 rounded-xl border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 placeholder-slate-400 dark:placeholder-slate-500 focus:ring-2 focus:ring-sky-500 focus:border-transparent transition-shadow resize-none"
|
||||
>{@form[:customer_comment].value}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 p-4 bg-sky-50 dark:bg-sky-900/20 border border-sky-200 dark:border-sky-800 rounded-xl">
|
||||
<div class="flex gap-3">
|
||||
<div class="flex-shrink-0">
|
||||
<.icon name="hero-information-circle" class="size-5 text-sky-600 dark:text-sky-400" />
|
||||
</div>
|
||||
<div class="text-xs text-slate-600 dark:text-slate-300 space-y-1">
|
||||
<ul class="list-disc list-inside space-y-0.5 ml-1">
|
||||
<li>Cancel anytime with no commitment</li>
|
||||
<li>Payment upon arrival only</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
field={@profile_form[:phone_number]}
|
||||
type="tel"
|
||||
label="Phone Number"
|
||||
placeholder="+39"
|
||||
placeholder="+39 123456789"
|
||||
class="w-full bg-slate-50 dark:bg-slate-900/50 border-slate-200 dark:border-slate-700 rounded-xl px-4 py-3 text-slate-900 dark:text-white focus:ring-2 focus:ring-primary focus:border-transparent transition-all outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
|
||||
describe "update_profile" do
|
||||
test "allows user to update their own name and phone_number" do
|
||||
user = create_test_user("test@example.com")
|
||||
user = register_user("test@example.com")
|
||||
|
||||
{:ok, updated_user} =
|
||||
Accounts.update_profile(user, "Updated Name", "+9876543210", actor: user)
|
||||
|
|
@ -20,8 +20,8 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
end
|
||||
|
||||
test "prevents user from updating another user's profile" do
|
||||
user1 = create_test_user("user1@example.com")
|
||||
user2 = create_test_user("user2@example.com")
|
||||
user1 = register_user("user1@example.com")
|
||||
user2 = register_user("user2@example.com")
|
||||
|
||||
result =
|
||||
Accounts.update_profile(user2, "Hacker", "1235837", actor: user1)
|
||||
|
|
@ -30,7 +30,7 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
end
|
||||
|
||||
test "validates that name is present" do
|
||||
user = create_test_user("test@example.com")
|
||||
user = register_user("test@example.com")
|
||||
|
||||
result =
|
||||
Accounts.update_profile(user, "", "+9876543210", actor: user)
|
||||
|
|
@ -42,7 +42,7 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
|
||||
describe "terminate_account with delete_history: false (anonymization)" do
|
||||
test "deletes user but preserves bookings with nullified user_id" do
|
||||
user = create_test_user("delete@example.com")
|
||||
user = register_user("delete@example.com")
|
||||
{_space, asset, time_slot} = create_booking_fixtures()
|
||||
|
||||
{:ok, booking1} =
|
||||
|
|
@ -87,7 +87,7 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
end
|
||||
|
||||
test "cancels future confirmed bookings before anonymizing" do
|
||||
user = create_test_user("cancel@example.com")
|
||||
user = register_user("cancel@example.com")
|
||||
{_space, asset, time_slot} = create_booking_fixtures()
|
||||
|
||||
future_date = Date.add(Date.utc_today(), 7)
|
||||
|
|
@ -133,7 +133,7 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
|
||||
describe "terminate_account with delete_history: true (hard delete)" do
|
||||
test "deletes user and all associated bookings permanently" do
|
||||
user = create_test_user("harddelete@example.com")
|
||||
user = register_user("harddelete@example.com")
|
||||
{_space, asset, time_slot} = create_booking_fixtures()
|
||||
|
||||
{:ok, booking1} =
|
||||
|
|
@ -173,8 +173,8 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
|
||||
describe "terminate_account authorization" do
|
||||
test "prevents user from deleting another user's account" do
|
||||
user1 = create_test_user("user1@example.com")
|
||||
user2 = create_test_user("user2@example.com")
|
||||
user1 = register_user("user1@example.com")
|
||||
user2 = register_user("user2@example.com")
|
||||
|
||||
result = Accounts.terminate_account(user2, false, actor: user1)
|
||||
|
||||
|
|
@ -182,18 +182,6 @@ defmodule SpazioSolazzo.Accounts.UserTest do
|
|||
end
|
||||
end
|
||||
|
||||
defp create_test_user(email) do
|
||||
{:ok, user} =
|
||||
SpazioSolazzo.Repo.insert(%User{
|
||||
id: Ash.UUID.generate(),
|
||||
email: email,
|
||||
name: "Test User",
|
||||
phone_number: "+1234567890"
|
||||
})
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
defp create_booking_fixtures do
|
||||
unique_id = :erlang.unique_integer([:positive, :monotonic])
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
alias SpazioSolazzo.BookingSystem.Booking
|
||||
alias SpazioSolazzo.Accounts.User
|
||||
|
||||
alias SpazioSolazzo.BookingSystem.Booking.EmailWorker
|
||||
|
||||
setup do
|
||||
|
|
@ -20,13 +18,7 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
space.id
|
||||
)
|
||||
|
||||
{:ok, user} =
|
||||
SpazioSolazzo.Repo.insert(%User{
|
||||
id: Ash.UUID.generate(),
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
phone_number: "+1234567890"
|
||||
})
|
||||
user = register_user("test@example.com")
|
||||
|
||||
%{space: space, asset: asset, time_slot: time_slot, user: user}
|
||||
end
|
||||
|
|
@ -236,7 +228,7 @@ defmodule SpazioSolazzo.BookingSystem.BookingTest do
|
|||
# Load the booking with the user relationship
|
||||
{:ok, booking_with_user} = Ash.load(booking, :user, authorize?: false)
|
||||
assert booking_with_user.user.id == user.id
|
||||
assert to_string(booking_with_user.user.email) == user.email
|
||||
assert booking_with_user.user.email == user.email
|
||||
assert booking_with_user.user.name == user.name
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ defmodule SpazioSolazzoWeb.BookingControllerTest do
|
|||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
alias SpazioSolazzo.BookingSystem.Booking.Token
|
||||
alias SpazioSolazzo.Accounts.User
|
||||
|
||||
setup do
|
||||
unique_id = :erlang.unique_integer([:positive, :monotonic])
|
||||
|
|
@ -21,13 +20,7 @@ defmodule SpazioSolazzoWeb.BookingControllerTest do
|
|||
space.id
|
||||
)
|
||||
|
||||
{:ok, user} =
|
||||
SpazioSolazzo.Repo.insert(%User{
|
||||
id: Ash.UUID.generate(),
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
phone_number: "+1234567890"
|
||||
})
|
||||
user = register_user("test@example.com", "Test User", "+1234567890")
|
||||
|
||||
%{space: space, asset: asset, time_slot: time_slot, user: user}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ defmodule SpazioSolazzoWeb.BookingLive.AssetBookingTest do
|
|||
import Phoenix.LiveViewTest
|
||||
|
||||
alias SpazioSolazzo.BookingSystem
|
||||
alias SpazioSolazzo.Accounts.User
|
||||
|
||||
setup %{conn: conn} do
|
||||
{:ok, space} = BookingSystem.create_space("TestSpace", "test-space", "Test description")
|
||||
|
|
@ -20,28 +19,12 @@ defmodule SpazioSolazzoWeb.BookingLive.AssetBookingTest do
|
|||
space.id
|
||||
)
|
||||
|
||||
conn = Plug.Test.init_test_session(conn, %{})
|
||||
conn = log_in_user(conn)
|
||||
user = register_user("test@example.com", "Test User", "+1234567890")
|
||||
conn = log_in_user(conn, user)
|
||||
|
||||
%{space: space, asset: asset, slot: slot, conn: conn}
|
||||
end
|
||||
|
||||
defp log_in_user(conn) do
|
||||
{:ok, user} =
|
||||
SpazioSolazzo.Repo.insert(%User{
|
||||
id: Ash.UUID.generate(),
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
phone_number: "+1234567890"
|
||||
})
|
||||
|
||||
{:ok, token, _claims} = AshAuthentication.Jwt.token_for_user(user)
|
||||
|
||||
conn
|
||||
|> Plug.Test.init_test_session(%{})
|
||||
|> Plug.Conn.put_session("user_token", token)
|
||||
end
|
||||
|
||||
describe "AssetBooking mount" do
|
||||
test "renders asset booking page with available time slots", %{
|
||||
conn: conn,
|
||||
|
|
@ -105,7 +88,11 @@ defmodule SpazioSolazzoWeb.BookingLive.AssetBookingTest do
|
|||
|
||||
view
|
||||
|> element("#booking-form")
|
||||
|> render_submit(%{"customer_comment" => "test comment"})
|
||||
|> render_submit(%{
|
||||
"customer_name" => "Test User",
|
||||
"customer_phone" => "+1234567890",
|
||||
"customer_comment" => "test comment"
|
||||
})
|
||||
|
||||
assert has_element?(view, "#success-modal")
|
||||
|
||||
|
|
@ -224,4 +211,113 @@ defmodule SpazioSolazzoWeb.BookingLive.AssetBookingTest do
|
|||
assert html =~ ~s(<div class="p-2"></div>)
|
||||
end
|
||||
end
|
||||
|
||||
describe "AssetBooking without phone number" do
|
||||
setup %{conn: conn} do
|
||||
# Create a separate connection with a user without phone number
|
||||
user = register_user("nophone@example.com", "User Without Phone", nil)
|
||||
conn = log_in_user(conn, user)
|
||||
|
||||
%{conn: conn}
|
||||
end
|
||||
|
||||
test "user without phone number can view booking form", %{conn: conn, asset: asset} do
|
||||
{:ok, view, _html} = live(conn, ~p"/book/asset/#{asset.id}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='select_slot']")
|
||||
|> render_click()
|
||||
|
||||
assert has_element?(view, "#booking-modal")
|
||||
assert has_element?(view, "input[name='customer_name']")
|
||||
assert has_element?(view, "input[name='customer_phone']")
|
||||
assert has_element?(view, "textarea[name='customer_comment']")
|
||||
end
|
||||
|
||||
test "user without phone number can create booking without providing phone", %{
|
||||
conn: conn,
|
||||
asset: asset
|
||||
} do
|
||||
{:ok, view, _html} = live(conn, ~p"/book/asset/#{asset.id}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='select_slot']")
|
||||
|> render_click()
|
||||
|
||||
assert has_element?(view, "#booking-modal")
|
||||
|
||||
# Submit booking with name but no phone
|
||||
view
|
||||
|> element("#booking-form")
|
||||
|> render_submit(%{
|
||||
"customer_name" => "User Without Phone",
|
||||
"customer_phone" => "",
|
||||
"customer_comment" => "test comment"
|
||||
})
|
||||
|
||||
assert has_element?(view, "#success-modal")
|
||||
|
||||
assert {:ok, [booking]} =
|
||||
BookingSystem.list_active_asset_bookings_by_date(asset.id, Date.utc_today())
|
||||
|
||||
assert booking.customer_email == "nophone@example.com"
|
||||
assert booking.customer_name == "User Without Phone"
|
||||
assert booking.customer_phone == nil or booking.customer_phone == ""
|
||||
assert booking.customer_comment == "test comment"
|
||||
end
|
||||
|
||||
test "user without phone number can edit name in booking form", %{
|
||||
conn: conn,
|
||||
asset: asset
|
||||
} do
|
||||
{:ok, view, _html} = live(conn, ~p"/book/asset/#{asset.id}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='select_slot']")
|
||||
|> render_click()
|
||||
|
||||
# Change the name
|
||||
view
|
||||
|> element("#booking-form")
|
||||
|> render_submit(%{
|
||||
"customer_name" => "Different Name",
|
||||
"customer_phone" => "",
|
||||
"customer_comment" => ""
|
||||
})
|
||||
|
||||
assert has_element?(view, "#success-modal")
|
||||
|
||||
assert {:ok, [booking]} =
|
||||
BookingSystem.list_active_asset_bookings_by_date(asset.id, Date.utc_today())
|
||||
|
||||
assert booking.customer_name == "Different Name"
|
||||
end
|
||||
|
||||
test "user without phone number can optionally add phone during booking", %{
|
||||
conn: conn,
|
||||
asset: asset
|
||||
} do
|
||||
{:ok, view, _html} = live(conn, ~p"/book/asset/#{asset.id}")
|
||||
|
||||
view
|
||||
|> element("button[phx-click='select_slot']")
|
||||
|> render_click()
|
||||
|
||||
# Add phone number during booking
|
||||
view
|
||||
|> element("#booking-form")
|
||||
|> render_submit(%{
|
||||
"customer_name" => "User Without Phone",
|
||||
"customer_phone" => "+39 123 456 789",
|
||||
"customer_comment" => ""
|
||||
})
|
||||
|
||||
assert has_element?(view, "#success-modal")
|
||||
|
||||
assert {:ok, [booking]} =
|
||||
BookingSystem.list_active_asset_bookings_by_date(asset.id, Date.utc_today())
|
||||
|
||||
assert booking.customer_phone == "+39 123 456 789"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ defmodule SpazioSolazzoWeb.ProfileLiveTest do
|
|||
alias SpazioSolazzo.BookingSystem.Booking
|
||||
|
||||
setup %{conn: conn} do
|
||||
conn = Plug.Test.init_test_session(conn, %{})
|
||||
{conn, user} = log_in_user(conn)
|
||||
user = register_user("test@example.com", "Test User", "+123456789")
|
||||
conn = log_in_user(conn, user)
|
||||
|
||||
%{user: user, conn: conn}
|
||||
end
|
||||
|
||||
|
|
@ -191,25 +192,6 @@ defmodule SpazioSolazzoWeb.ProfileLiveTest do
|
|||
end
|
||||
end
|
||||
|
||||
defp log_in_user(conn) do
|
||||
user =
|
||||
SpazioSolazzo.Repo.insert!(%User{
|
||||
id: Ash.UUID.generate(),
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
phone_number: "+1234567890"
|
||||
})
|
||||
|
||||
{:ok, token, _claims} = AshAuthentication.Jwt.token_for_user(user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> Plug.Test.init_test_session(%{})
|
||||
|> Plug.Conn.put_session("user_token", token)
|
||||
|
||||
{conn, user}
|
||||
end
|
||||
|
||||
defp create_booking_fixtures do
|
||||
unique_id = :erlang.unique_integer([:positive, :monotonic])
|
||||
|
||||
|
|
|
|||
64
test/support/auth_helpers.ex
Normal file
64
test/support/auth_helpers.ex
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
defmodule SpazioSolazzo.AuthHelpers do
|
||||
@moduledoc """
|
||||
Authentication helper functions for tests.
|
||||
|
||||
Provides utilities to create and authenticate users via the magic link flow,
|
||||
simulating realistic authentication behavior in tests.
|
||||
"""
|
||||
|
||||
alias SpazioSolazzo.Accounts
|
||||
|
||||
@doc """
|
||||
Creates a test session and logs the user into it.
|
||||
|
||||
## Parameters
|
||||
|
||||
- `conn` - The test connection
|
||||
- `user` - User to log in
|
||||
|
||||
## Examples
|
||||
|
||||
conn = log_in_user(conn, user)
|
||||
"""
|
||||
def log_in_user(conn, user) do
|
||||
conn
|
||||
|> Plug.Test.init_test_session(%{})
|
||||
|> AshAuthentication.Phoenix.Plug.store_in_session(user)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a user via magic link authentication without attaching to a connection.
|
||||
|
||||
Useful for tests that need a user object but don't need an authenticated connection.
|
||||
|
||||
## Parameters
|
||||
|
||||
- `email` - User's email address
|
||||
- `name` - Optional user's full name (defaults to "Test User")
|
||||
- `phone_number` - Optional phone number (defaults to nil)
|
||||
|
||||
## Examples
|
||||
|
||||
user = register_user("test@example.com", "Test User", "+1234567890")
|
||||
user = register_user("user@example.com", "User Name")
|
||||
user = register_user("user@example.com")
|
||||
"""
|
||||
def register_user(email, name \\ "Test user", phone_number \\ nil) do
|
||||
strategy = AshAuthentication.Info.strategy!(SpazioSolazzo.Accounts.User, :magic_link)
|
||||
|
||||
{:ok, token} =
|
||||
AshAuthentication.Strategy.MagicLink.request_token_for_identity(strategy, email)
|
||||
|
||||
# Sign in with magic link
|
||||
{:ok, user} =
|
||||
Accounts.sign_in_with_magic_link(
|
||||
token,
|
||||
false,
|
||||
name,
|
||||
phone_number,
|
||||
authorize?: false
|
||||
)
|
||||
|
||||
user
|
||||
end
|
||||
end
|
||||
|
|
@ -31,6 +31,9 @@ defmodule SpazioSolazzoWeb.ConnCase do
|
|||
|
||||
# Import DataCase helpers for email testing
|
||||
import SpazioSolazzo.DataCase, only: [pop_email: 0, pop_email: 2]
|
||||
|
||||
# Import authentication helpers
|
||||
import SpazioSolazzo.AuthHelpers
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ defmodule SpazioSolazzo.DataCase do
|
|||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
import SpazioSolazzo.DataCase
|
||||
import SpazioSolazzo.AuthHelpers
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue