256 lines
7.9 KiB
Elixir
256 lines
7.9 KiB
Elixir
defmodule MvWeb.CustomFieldLive.DeletionTest do
|
|
@moduledoc """
|
|
Tests for CustomFieldLive.IndexComponent deletion modal and slug confirmation.
|
|
Tests the custom field management component embedded in the settings page.
|
|
|
|
Tests cover:
|
|
- Opening deletion confirmation modal
|
|
- Displaying correct member count
|
|
- Slug confirmation input
|
|
- Successful deletion with correct slug
|
|
- Failed deletion with incorrect slug
|
|
- Canceling deletion
|
|
- Button states (enabled/disabled based on slug match)
|
|
"""
|
|
use MvWeb.ConnCase, async: true
|
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
alias Mv.Membership.{CustomField, CustomFieldValue, Member}
|
|
|
|
setup do
|
|
# Create admin user for testing
|
|
{:ok, user} =
|
|
Mv.Accounts.User
|
|
|> Ash.Changeset.for_create(:register_with_password, %{
|
|
email: "admin#{System.unique_integer([:positive])}@mv.local",
|
|
password: "testpassword123"
|
|
})
|
|
|> Ash.create()
|
|
|
|
conn = log_in_user(build_conn(), user)
|
|
%{conn: conn, user: user}
|
|
end
|
|
|
|
describe "delete button and modal" do
|
|
test "opens modal with correct member count when delete is clicked", %{conn: conn} do
|
|
{:ok, member} = create_member()
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
|
|
# Create custom field value
|
|
create_custom_field_value(member, custom_field, "test")
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
# Click delete button - find the delete link within the component
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Modal should be visible
|
|
assert has_element?(view, "#delete-custom-field-modal")
|
|
|
|
# Should show correct member count (1 member)
|
|
assert render(view) =~ "1 member has a value assigned for this custom field"
|
|
|
|
# Should show the slug
|
|
assert render(view) =~ custom_field.slug
|
|
end
|
|
|
|
test "shows correct plural form for multiple members", %{conn: conn} do
|
|
{:ok, member1} = create_member()
|
|
{:ok, member2} = create_member()
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
|
|
# Create values for both members
|
|
create_custom_field_value(member1, custom_field, "test1")
|
|
create_custom_field_value(member2, custom_field, "test2")
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Should show plural form
|
|
assert render(view) =~ "2 members have values assigned for this custom field"
|
|
end
|
|
|
|
test "shows 0 members for custom field without values", %{conn: conn} do
|
|
{:ok, _custom_field} = create_custom_field("test_field", :string)
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Should show 0 members
|
|
assert render(view) =~ "0 members have values assigned for this custom field"
|
|
end
|
|
end
|
|
|
|
describe "slug confirmation input" do
|
|
test "updates confirmation state when typing", %{conn: conn} do
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Type in slug input - use element to find the form with phx-target
|
|
view
|
|
|> element("#delete-custom-field-modal form")
|
|
|> render_change(%{"slug" => custom_field.slug})
|
|
|
|
# Confirm button should be enabled now (no disabled attribute)
|
|
html = render(view)
|
|
refute html =~ ~r/disabled(?:=""|(?!\w))/
|
|
end
|
|
|
|
test "delete button is disabled when slug doesn't match", %{conn: conn} do
|
|
{:ok, _custom_field} = create_custom_field("test_field", :string)
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Type wrong slug - use element to find the form with phx-target
|
|
view
|
|
|> element("#delete-custom-field-modal form")
|
|
|> render_change(%{"slug" => "wrong-slug"})
|
|
|
|
# Button should be disabled
|
|
html = render(view)
|
|
assert html =~ ~r/disabled(?:=""|(?!\w))/
|
|
end
|
|
end
|
|
|
|
describe "confirm deletion" do
|
|
test "successfully deletes custom field with correct slug", %{conn: conn} do
|
|
{:ok, member} = create_member()
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
{:ok, custom_field_value} = create_custom_field_value(member, custom_field, "test")
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
# Open modal
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Enter correct slug - use element to find the form with phx-target
|
|
view
|
|
|> element("#delete-custom-field-modal form")
|
|
|> render_change(%{"slug" => custom_field.slug})
|
|
|
|
# Click confirm
|
|
view
|
|
|> element("#delete-custom-field-modal button", "Delete Custom Field and All Values")
|
|
|> render_click()
|
|
|
|
# Should show success message
|
|
assert render(view) =~ "Custom field deleted successfully"
|
|
|
|
# Custom field should be gone from database
|
|
assert {:error, _} = Ash.get(CustomField, custom_field.id)
|
|
|
|
# Custom field value should also be gone (CASCADE)
|
|
assert {:error, _} = Ash.get(CustomFieldValue, custom_field_value.id)
|
|
|
|
# Member should still exist
|
|
assert {:ok, _} = Ash.get(Member, member.id)
|
|
end
|
|
|
|
test "button remains disabled and custom field not deleted when slug doesn't match", %{
|
|
conn: conn
|
|
} do
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Enter wrong slug - use element to find the form with phx-target
|
|
view
|
|
|> element("#delete-custom-field-modal form")
|
|
|> render_change(%{"slug" => "wrong-slug"})
|
|
|
|
# Button should be disabled and we cannot click it
|
|
# The test verifies that the button is properly disabled in the UI
|
|
html = render(view)
|
|
assert html =~ ~r/disabled(?:=""|(?!\w))/
|
|
|
|
# Custom field should still exist since deletion couldn't proceed
|
|
assert {:ok, _} = Ash.get(CustomField, custom_field.id)
|
|
end
|
|
end
|
|
|
|
describe "cancel deletion" do
|
|
test "closes modal without deleting", %{conn: conn} do
|
|
{:ok, custom_field} = create_custom_field("test_field", :string)
|
|
|
|
{:ok, view, _html} = live(conn, ~p"/settings")
|
|
|
|
view
|
|
|> element("#custom-fields-component a", "Delete")
|
|
|> render_click()
|
|
|
|
# Modal should be visible
|
|
assert has_element?(view, "#delete-custom-field-modal")
|
|
|
|
# Click cancel
|
|
view
|
|
|> element("#delete-custom-field-modal button", "Cancel")
|
|
|> render_click()
|
|
|
|
# Modal should be gone
|
|
refute has_element?(view, "#delete-custom-field-modal")
|
|
|
|
# Custom field should still exist
|
|
assert {:ok, _} = Ash.get(CustomField, custom_field.id)
|
|
end
|
|
end
|
|
|
|
# Helper functions
|
|
defp create_member do
|
|
Member
|
|
|> Ash.Changeset.for_create(:create_member, %{
|
|
first_name: "Test",
|
|
last_name: "User#{System.unique_integer([:positive])}",
|
|
email: "test#{System.unique_integer([:positive])}@example.com"
|
|
})
|
|
|> Ash.create()
|
|
end
|
|
|
|
defp create_custom_field(name, value_type) do
|
|
CustomField
|
|
|> Ash.Changeset.for_create(:create, %{
|
|
name: "#{name}_#{System.unique_integer([:positive])}",
|
|
value_type: value_type
|
|
})
|
|
|> Ash.create()
|
|
end
|
|
|
|
defp create_custom_field_value(member, custom_field, value) do
|
|
CustomFieldValue
|
|
|> Ash.Changeset.for_create(:create, %{
|
|
member_id: member.id,
|
|
custom_field_id: custom_field.id,
|
|
value: %{"_union_type" => "string", "_union_value" => value}
|
|
})
|
|
|> Ash.create()
|
|
end
|
|
|
|
defp log_in_user(conn, user) do
|
|
conn
|
|
|> Phoenix.ConnTest.init_test_session(%{})
|
|
|> AshAuthentication.Plug.Helpers.store_in_session(user)
|
|
end
|
|
end
|