Merge branch 'main' into feature/export_csv
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:
commit
36e57b24be
102 changed files with 5332 additions and 1219 deletions
102
test/mv_web/live/member_live_authorization_test.exs
Normal file
102
test/mv_web/live/member_live_authorization_test.exs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
defmodule MvWeb.MemberLiveAuthorizationTest do
|
||||
@moduledoc """
|
||||
Tests for UI authorization on Member LiveViews (Index and Show).
|
||||
"""
|
||||
use MvWeb.ConnCase, async: false
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias Mv.Fixtures
|
||||
|
||||
describe "Member Index - Vorstand (read_only)" do
|
||||
@tag role: :read_only
|
||||
test "sees member list but not New Member button", %{conn: conn} do
|
||||
_member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
|
||||
refute has_element?(view, "[data-testid=member-new]")
|
||||
end
|
||||
|
||||
@tag role: :read_only
|
||||
test "does not see Edit or Delete buttons in table", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
|
||||
refute has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
|
||||
refute has_element?(view, "#row-#{member.id} [data-testid=member-delete]")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Member Index - Kassenwart (normal_user)" do
|
||||
@tag role: :normal_user
|
||||
test "sees New Member and Edit buttons", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
|
||||
assert has_element?(view, "[data-testid=member-new]")
|
||||
assert has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
|
||||
end
|
||||
|
||||
@tag role: :normal_user
|
||||
test "does not see Delete button", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
|
||||
refute has_element?(view, "#row-#{member.id} [data-testid=member-delete]")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Member Index - Admin" do
|
||||
@tag role: :admin
|
||||
test "sees New Member, Edit and Delete buttons", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members")
|
||||
|
||||
assert has_element?(view, "[data-testid=member-new]")
|
||||
assert has_element?(view, "#row-#{member.id} [data-testid=member-edit]")
|
||||
assert has_element?(view, "#row-#{member.id} [data-testid=member-delete]")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Member Index - Mitglied (own_data)" do
|
||||
@tag role: :member
|
||||
test "is redirected when accessing /members", %{conn: conn, current_user: user} do
|
||||
assert {:error, {:redirect, %{to: to}}} = live(conn, "/members")
|
||||
assert to == "/users/#{user.id}"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Member Show - Edit button visibility" do
|
||||
@tag role: :admin
|
||||
test "admin sees Edit button", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
assert has_element?(view, "[data-testid=member-edit]")
|
||||
end
|
||||
|
||||
@tag role: :read_only
|
||||
test "read_only does not see Edit button", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
refute has_element?(view, "[data-testid=member-edit]")
|
||||
end
|
||||
|
||||
@tag role: :normal_user
|
||||
test "normal_user sees Edit button", %{conn: conn} do
|
||||
member = Fixtures.member_fixture()
|
||||
|
||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||
|
||||
assert has_element?(view, "[data-testid=member-edit]")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -50,7 +50,7 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
|||
end
|
||||
|
||||
describe "create form" do
|
||||
test "creates new membership fee type", %{conn: conn} do
|
||||
test "creates new membership fee type", %{conn: conn, user: user} do
|
||||
{:ok, view, _html} = live(conn, "/membership_fee_types/new")
|
||||
|
||||
form_data = %{
|
||||
|
|
@ -67,12 +67,13 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
|||
|
||||
assert to == "/membership_fee_types"
|
||||
|
||||
# Verify type was created
|
||||
# Verify type was created (use actor so read is authorized)
|
||||
type =
|
||||
MembershipFeeType
|
||||
|> Ash.Query.filter(name == "New Type")
|
||||
|> Ash.read_one!()
|
||||
|> Ash.read_one!(domain: Mv.MembershipFees, actor: user)
|
||||
|
||||
assert type != nil, "Expected membership fee type to be created"
|
||||
assert type.amount == Decimal.new("75.00")
|
||||
assert type.interval == :yearly
|
||||
end
|
||||
|
|
@ -140,7 +141,7 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
|||
assert html =~ "3" || html =~ "members" || html =~ "Mitglieder"
|
||||
end
|
||||
|
||||
test "amount change can be confirmed", %{conn: conn} do
|
||||
test "amount change can be confirmed", %{conn: conn, user: user} do
|
||||
fee_type = create_fee_type(%{amount: Decimal.new("50.00")})
|
||||
|
||||
{:ok, view, _html} = live(conn, "/membership_fee_types/#{fee_type.id}/edit")
|
||||
|
|
@ -159,12 +160,17 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
|||
|> form("#membership-fee-type-form", %{"membership_fee_type[amount]" => "75.00"})
|
||||
|> render_submit()
|
||||
|
||||
# Amount should be updated
|
||||
updated_type = Ash.read_one!(MembershipFeeType |> Ash.Query.filter(id == ^fee_type.id))
|
||||
# Amount should be updated (use actor so read is authorized)
|
||||
updated_type =
|
||||
MembershipFeeType
|
||||
|> Ash.Query.filter(id == ^fee_type.id)
|
||||
|> Ash.read_one!(domain: Mv.MembershipFees, actor: user)
|
||||
|
||||
assert updated_type != nil
|
||||
assert updated_type.amount == Decimal.new("75.00")
|
||||
end
|
||||
|
||||
test "amount change can be cancelled", %{conn: conn} do
|
||||
test "amount change can be cancelled", %{conn: conn, user: user} do
|
||||
fee_type = create_fee_type(%{amount: Decimal.new("50.00")})
|
||||
|
||||
{:ok, view, _html} = live(conn, "/membership_fee_types/#{fee_type.id}/edit")
|
||||
|
|
@ -178,8 +184,13 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
|||
|> element("button[phx-click='cancel_amount_change']")
|
||||
|> render_click()
|
||||
|
||||
# Amount should remain unchanged
|
||||
updated_type = Ash.read_one!(MembershipFeeType |> Ash.Query.filter(id == ^fee_type.id))
|
||||
# Amount should remain unchanged (use actor so read is authorized)
|
||||
updated_type =
|
||||
MembershipFeeType
|
||||
|> Ash.Query.filter(id == ^fee_type.id)
|
||||
|> Ash.read_one!(domain: Mv.MembershipFees, actor: user)
|
||||
|
||||
assert updated_type != nil
|
||||
assert updated_type.amount == Decimal.new("50.00")
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ defmodule MvWeb.ProfileNavigationTest do
|
|||
end
|
||||
|
||||
@tag :skip
|
||||
# Note: User initials in navbar avatar - see issue #170
|
||||
# credo:disable-for-next-line Credo.Check.Design.TagTODO
|
||||
# TODO: Implement user initials in navbar avatar - see issue #170
|
||||
test "shows user initials in avatar", %{conn: conn} do
|
||||
# Setup: Create and login a user
|
||||
user = create_test_user(%{email: "test.user@example.com"})
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule MvWeb.RoleLive.ShowTest do
|
|||
alias Mv.Authorization
|
||||
alias Mv.Authorization.Role
|
||||
|
||||
# Helper to create a role
|
||||
# Helper to create a role (authorize?: false for test data setup)
|
||||
defp create_role(attrs \\ %{}) do
|
||||
default_attrs = %{
|
||||
name: "Test Role #{System.unique_integer([:positive])}",
|
||||
|
|
@ -28,7 +28,7 @@ defmodule MvWeb.RoleLive.ShowTest do
|
|||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
case Authorization.create_role(attrs) do
|
||||
case Authorization.create_role(attrs, authorize?: false) do
|
||||
{:ok, role} -> role
|
||||
{:error, error} -> raise "Failed to create role: #{inspect(error)}"
|
||||
end
|
||||
|
|
@ -38,7 +38,7 @@ defmodule MvWeb.RoleLive.ShowTest do
|
|||
defp create_admin_user(conn, actor) do
|
||||
# Create admin role
|
||||
admin_role =
|
||||
case Authorization.list_roles() do
|
||||
case Authorization.list_roles(authorize?: false) do
|
||||
{:ok, roles} ->
|
||||
case Enum.find(roles, &(&1.name == "Admin")) do
|
||||
nil ->
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
alias Mv.Authorization
|
||||
alias Mv.Authorization.Role
|
||||
|
||||
# Helper to create a role
|
||||
# Helper to create a role (authorize?: false for test data setup)
|
||||
defp create_role(attrs \\ %{}) do
|
||||
default_attrs = %{
|
||||
name: "Test Role #{System.unique_integer([:positive])}",
|
||||
|
|
@ -19,7 +19,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
case Authorization.create_role(attrs) do
|
||||
case Authorization.create_role(attrs, authorize?: false) do
|
||||
{:ok, role} -> role
|
||||
{:error, error} -> raise "Failed to create role: #{inspect(error)}"
|
||||
end
|
||||
|
|
@ -29,7 +29,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
defp create_admin_user(conn, actor) do
|
||||
# Create admin role
|
||||
admin_role =
|
||||
case Authorization.list_roles() do
|
||||
case Authorization.list_roles(authorize?: false) do
|
||||
{:ok, roles} ->
|
||||
case Enum.find(roles, &(&1.name == "Admin")) do
|
||||
nil ->
|
||||
|
|
@ -332,7 +332,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
assert match?({:error, {:redirect, %{to: "/admin/roles"}}}, result)
|
||||
end
|
||||
|
||||
test "updates role name", %{conn: conn, role: role} do
|
||||
test "updates role name", %{conn: conn, role: role, actor: actor} do
|
||||
{:ok, view, _html} = live(conn, "/admin/roles/#{role.id}/edit?return_to=show")
|
||||
|
||||
attrs = %{
|
||||
|
|
@ -348,7 +348,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
assert_redirect(view, "/admin/roles/#{role.id}")
|
||||
|
||||
# Verify update
|
||||
{:ok, updated_role} = Authorization.get_role(role.id)
|
||||
{:ok, updated_role} = Authorization.get_role(role.id, actor: actor)
|
||||
assert updated_role.name == "Updated Role Name"
|
||||
end
|
||||
|
||||
|
|
@ -377,7 +377,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
assert_redirect(view, "/admin/roles/#{system_role.id}")
|
||||
|
||||
# Verify update
|
||||
{:ok, updated_role} = Authorization.get_role(system_role.id)
|
||||
{:ok, updated_role} = Authorization.get_role(system_role.id, actor: actor)
|
||||
assert updated_role.permission_set_name == "read_only"
|
||||
end
|
||||
end
|
||||
|
|
@ -390,7 +390,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
end
|
||||
|
||||
@tag :slow
|
||||
test "deletes non-system role", %{conn: conn} do
|
||||
test "deletes non-system role", %{conn: conn, actor: actor} do
|
||||
role = create_role()
|
||||
|
||||
{:ok, view, html} = live(conn, "/admin/roles")
|
||||
|
|
@ -404,7 +404,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
|
||||
# Verify deletion by checking database
|
||||
assert {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Query.NotFound{}]}} =
|
||||
Authorization.get_role(role.id)
|
||||
Authorization.get_role(role.id, actor: actor)
|
||||
end
|
||||
|
||||
test "fails to delete system role with error message", %{conn: conn, actor: actor} do
|
||||
|
|
@ -430,7 +430,7 @@ defmodule MvWeb.RoleLiveTest do
|
|||
assert render(view) =~ "System roles cannot be deleted"
|
||||
|
||||
# Role should still exist
|
||||
{:ok, _role} = Authorization.get_role(system_role.id)
|
||||
{:ok, _role} = Authorization.get_role(system_role.id, actor: actor)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
81
test/mv_web/live/user_live_authorization_test.exs
Normal file
81
test/mv_web/live/user_live_authorization_test.exs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
defmodule MvWeb.UserLiveAuthorizationTest do
|
||||
@moduledoc """
|
||||
Tests for UI authorization on User LiveViews (Index and Show).
|
||||
"""
|
||||
use MvWeb.ConnCase, async: false
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias Mv.Fixtures
|
||||
|
||||
describe "User Index - Admin" do
|
||||
@tag role: :admin
|
||||
test "sees New User, Edit and Delete buttons", %{conn: conn} do
|
||||
user = Fixtures.user_with_role_fixture("admin")
|
||||
|
||||
{:ok, view, _html} = live(conn, "/users")
|
||||
|
||||
assert has_element?(view, "[data-testid=user-new]")
|
||||
assert has_element?(view, "#row-#{user.id} [data-testid=user-edit]")
|
||||
assert has_element?(view, "#row-#{user.id} [data-testid=user-delete]")
|
||||
end
|
||||
end
|
||||
|
||||
describe "User Index - Non-Admin is redirected" do
|
||||
@tag role: :read_only
|
||||
test "read_only is redirected when accessing /users", %{conn: conn, current_user: user} do
|
||||
assert {:error, {:redirect, %{to: to}}} = live(conn, "/users")
|
||||
assert to == "/users/#{user.id}"
|
||||
end
|
||||
|
||||
@tag role: :member
|
||||
test "member is redirected when accessing /users", %{conn: conn, current_user: user} do
|
||||
assert {:error, {:redirect, %{to: to}}} = live(conn, "/users")
|
||||
assert to == "/users/#{user.id}"
|
||||
end
|
||||
|
||||
@tag role: :normal_user
|
||||
test "normal_user is redirected when accessing /users", %{conn: conn, current_user: user} do
|
||||
assert {:error, {:redirect, %{to: to}}} = live(conn, "/users")
|
||||
assert to == "/users/#{user.id}"
|
||||
end
|
||||
end
|
||||
|
||||
describe "User Show - own profile" do
|
||||
@tag role: :member
|
||||
test "member sees Edit button on own profile", %{conn: conn, current_user: user} do
|
||||
{:ok, view, _html} = live(conn, "/users/#{user.id}")
|
||||
|
||||
assert has_element?(view, "[data-testid=user-edit]")
|
||||
end
|
||||
|
||||
@tag role: :read_only
|
||||
test "read_only sees Edit button on own profile", %{conn: conn, current_user: user} do
|
||||
{:ok, view, _html} = live(conn, "/users/#{user.id}")
|
||||
|
||||
assert has_element?(view, "[data-testid=user-edit]")
|
||||
end
|
||||
|
||||
@tag role: :admin
|
||||
test "admin sees Edit button on user show", %{conn: conn} do
|
||||
user = Fixtures.user_with_role_fixture("read_only")
|
||||
|
||||
{:ok, view, _html} = live(conn, "/users/#{user.id}")
|
||||
|
||||
assert has_element?(view, "[data-testid=user-edit]")
|
||||
end
|
||||
end
|
||||
|
||||
describe "User Show - other user (non-admin redirected)" do
|
||||
@tag role: :member
|
||||
test "member is redirected when accessing other user's profile", %{
|
||||
conn: conn,
|
||||
current_user: current_user
|
||||
} do
|
||||
other_user = Fixtures.user_with_role_fixture("admin")
|
||||
|
||||
assert {:error, {:redirect, %{to: to}}} = live(conn, "/users/#{other_user.id}")
|
||||
assert to == "/users/#{current_user.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue