test: add tdd tests for group member add functionality
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
90758191f9
commit
a536485b30
7 changed files with 2293 additions and 0 deletions
427
test/mv_web/live/group_live/show_integration_test.exs
Normal file
427
test/mv_web/live/group_live/show_integration_test.exs
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
defmodule MvWeb.GroupLive.ShowIntegrationTest do
|
||||
@moduledoc """
|
||||
Integration tests for Add/Remove Member functionality.
|
||||
Tests data consistency, database operations, and multiple operations.
|
||||
"""
|
||||
|
||||
use MvWeb.ConnCase, async: false
|
||||
import Phoenix.LiveViewTest
|
||||
use Gettext, backend: MvWeb.Gettext
|
||||
|
||||
alias Mv.Membership
|
||||
alias Mv.Fixtures
|
||||
|
||||
describe "data consistency" do
|
||||
test "member appears in group after add (verified in database)", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Alice",
|
||||
last_name: "Smith",
|
||||
email: "alice@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Add member via UI
|
||||
view
|
||||
|> element("button", "Add Member")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_focus()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_change(%{"member_search" => "Alice"})
|
||||
|
||||
view
|
||||
|> element("[data-member-id='#{member.id}']")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("button", "Add")
|
||||
|> render_click()
|
||||
|
||||
# Verify in database
|
||||
require Ash.Query
|
||||
|
||||
query =
|
||||
Mv.Membership.Group
|
||||
|> Ash.Query.filter(slug == ^group.slug)
|
||||
|> Ash.Query.load([:members])
|
||||
|
||||
{:ok, updated_group} = Ash.read_one(query, actor: system_actor, domain: Mv.Membership)
|
||||
|
||||
# Member should be in group
|
||||
assert Enum.any?(updated_group.members, &(&1.id == member.id))
|
||||
end
|
||||
|
||||
test "member disappears from group after remove (verified in database)", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Bob",
|
||||
last_name: "Jones",
|
||||
email: "bob@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Add member to group
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Remove member via UI
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Verify in database
|
||||
require Ash.Query
|
||||
|
||||
query =
|
||||
Mv.Membership.Group
|
||||
|> Ash.Query.filter(slug == ^group.slug)
|
||||
|> Ash.Query.load([:members])
|
||||
|
||||
{:ok, updated_group} = Ash.read_one(query, actor: system_actor, domain: Mv.Membership)
|
||||
|
||||
# Member should NOT be in group
|
||||
refute Enum.any?(updated_group.members, &(&1.id == member.id))
|
||||
end
|
||||
|
||||
test "MemberGroup association is created correctly", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Charlie",
|
||||
last_name: "Brown",
|
||||
email: "charlie@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Add member
|
||||
view
|
||||
|> element("button", "Add Member")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_focus()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_change(%{"member_search" => "Charlie"})
|
||||
|
||||
view
|
||||
|> element("[data-member-id='#{member.id}']")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("button", "Add")
|
||||
|> render_click()
|
||||
|
||||
# Verify MemberGroup association exists
|
||||
require Ash.Query
|
||||
|
||||
{:ok, member_groups} =
|
||||
Ash.read(
|
||||
Mv.Membership.MemberGroup
|
||||
|> Ash.Query.filter(member_id == ^member.id and group_id == ^group.id),
|
||||
actor: system_actor,
|
||||
domain: Mv.Membership
|
||||
)
|
||||
|
||||
assert length(member_groups) == 1
|
||||
assert hd(member_groups).member_id == member.id
|
||||
assert hd(member_groups).group_id == group.id
|
||||
end
|
||||
|
||||
test "MemberGroup association is deleted correctly", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "David",
|
||||
last_name: "Wilson",
|
||||
email: "david@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Add member first
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Remove member
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Verify MemberGroup association is deleted
|
||||
require Ash.Query
|
||||
|
||||
{:ok, member_groups} =
|
||||
Ash.read(
|
||||
Mv.Membership.MemberGroup
|
||||
|> Ash.Query.filter(member_id == ^member.id and group_id == ^group.id),
|
||||
actor: system_actor,
|
||||
domain: Mv.Membership
|
||||
)
|
||||
|
||||
assert member_groups == []
|
||||
end
|
||||
|
||||
test "member itself is NOT deleted (only association)", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Eve",
|
||||
last_name: "Davis",
|
||||
email: "eve@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Add member to group
|
||||
Membership.create_member_group(%{member_id: member.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Remove member from group
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Verify member still exists
|
||||
{:ok, member_after_remove} =
|
||||
Ash.get(Mv.Membership.Member, member.id, actor: system_actor)
|
||||
|
||||
assert member_after_remove.id == member.id
|
||||
assert member_after_remove.first_name == "Eve"
|
||||
end
|
||||
end
|
||||
|
||||
describe "multiple operations" do
|
||||
test "multiple members can be added sequentially", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member1} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Frank",
|
||||
last_name: "Moore",
|
||||
email: "frank@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, member2} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Grace",
|
||||
last_name: "Taylor",
|
||||
email: "grace@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Add first member
|
||||
view
|
||||
|> element("button", "Add Member")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_focus()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_change(%{"member_search" => "Frank"})
|
||||
|
||||
view
|
||||
|> element("[data-member-id='#{member1.id}']")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("button", "Add")
|
||||
|> render_click()
|
||||
|
||||
# Add second member
|
||||
view
|
||||
|> element("button", "Add Member")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_focus()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_change(%{"member_search" => "Grace"})
|
||||
|
||||
view
|
||||
|> element("[data-member-id='#{member2.id}']")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("button", "Add")
|
||||
|> render_click()
|
||||
|
||||
# Both members should be in list
|
||||
html = render(view)
|
||||
assert html =~ "Frank"
|
||||
assert html =~ "Grace"
|
||||
end
|
||||
|
||||
test "multiple members can be removed sequentially", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member1} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Henry",
|
||||
last_name: "Anderson",
|
||||
email: "henry@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, member2} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Isabel",
|
||||
last_name: "Martinez",
|
||||
email: "isabel@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Add both members
|
||||
Membership.create_member_group(%{member_id: member1.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
Membership.create_member_group(%{member_id: member2.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Both should be in list initially
|
||||
assert html =~ "Henry"
|
||||
assert html =~ "Isabel"
|
||||
|
||||
# Remove first member
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Remove second member
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Both should be removed
|
||||
html = render(view)
|
||||
refute html =~ "Henry"
|
||||
refute html =~ "Isabel"
|
||||
end
|
||||
|
||||
test "add and remove can be mixed", %{conn: conn} do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
group = Fixtures.group_fixture()
|
||||
|
||||
{:ok, member1} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Jack",
|
||||
last_name: "White",
|
||||
email: "jack@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, member2} =
|
||||
Membership.create_member(
|
||||
%{
|
||||
first_name: "Kate",
|
||||
last_name: "Black",
|
||||
email: "kate@example.com"
|
||||
},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
# Add member1 first
|
||||
Membership.create_member_group(%{member_id: member1.id, group_id: group.id},
|
||||
actor: system_actor
|
||||
)
|
||||
|
||||
{:ok, view, _html} = live(conn, "/groups/#{group.slug}")
|
||||
|
||||
# Add member2
|
||||
view
|
||||
|> element("button", "Add Member")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_focus()
|
||||
|
||||
view
|
||||
|> element("#member-search-input")
|
||||
|> render_change(%{"member_search" => "Kate"})
|
||||
|
||||
view
|
||||
|> element("[data-member-id='#{member2.id}']")
|
||||
|> render_click()
|
||||
|
||||
view
|
||||
|> element("button", "Add")
|
||||
|> render_click()
|
||||
|
||||
# Remove member1
|
||||
view
|
||||
|> element("button[phx-click='remove_member']", "")
|
||||
|> render_click()
|
||||
|
||||
# Only member2 should remain
|
||||
html = render(view)
|
||||
refute html =~ "Jack"
|
||||
assert html =~ "Kate"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue