Compare commits

..

No commits in common. "feature/reorder-sidebar-menu" and "main" have entirely different histories.

7 changed files with 158 additions and 254 deletions

View file

@ -181,29 +181,6 @@
padding-left: 14px; padding-left: 14px;
} }
/* ============================================
Menu Groups - Disable hover and active on expanded-menu-group header
============================================ */
/* Disable all interactive effects on expanded-menu-group header (no href, not clickable)
Using [role="group"] to increase specificity and avoid !important */
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a) {
pointer-events: none;
cursor: default;
}
/* Higher specificity selector to override DaisyUI menu hover styles
DaisyUI uses :where() which has 0 specificity, but the compiled CSS might have higher specificity
Using [role="group"] attribute selector increases specificity without !important */
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):hover,
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):active,
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):focus {
background-color: transparent;
box-shadow: none;
cursor: default;
color: inherit;
}
/* ============================================ /* ============================================
Elements Only Visible in Expanded State Elements Only Visible in Expanded State
============================================ */ ============================================ */
@ -240,9 +217,7 @@
- Menu has p-2 (8px), so links need 14px additional padding-left */ - Menu has p-2 (8px), so links need 14px additional padding-left */
.sidebar .menu > li > a, .sidebar .menu > li > a,
.sidebar .menu > li > button, .sidebar .menu > li > button {
.sidebar .menu > li.expanded-menu-group > div,
.sidebar .menu > div.collapsed-menu-group > button {
@apply transition-all duration-300; @apply transition-all duration-300;
padding-left: 14px; padding-left: 14px;
} }
@ -251,17 +226,12 @@
- Remove gap so label (which is opacity-0 w-0) doesn't create space - Remove gap so label (which is opacity-0 w-0) doesn't create space
- Keep padding-left at 14px so icons stay centered under logo */ - Keep padding-left at 14px so icons stay centered under logo */
[data-sidebar-expanded="false"] .sidebar .menu > li > a, [data-sidebar-expanded="false"] .sidebar .menu > li > a,
[data-sidebar-expanded="false"] .sidebar .menu > li > button, [data-sidebar-expanded="false"] .sidebar .menu > li > button {
[data-sidebar-expanded="false"] .sidebar .menu > li.expanded-menu-group > div,
[data-sidebar-expanded="false"] .sidebar .menu > div.collapsed-menu-group > button {
@apply gap-0; @apply gap-0;
padding-left: 14px; padding-left: 14px;
padding-right: 14px; /* Center icon horizontally in 64px sidebar */ padding-right: 14px; /* Center icon horizontally in 64px sidebar */
} }
/* ============================================ /* ============================================
Footer Button Alignment - Left Aligned in Collapsed State Footer Button Alignment - Left Aligned in Collapsed State
============================================ */ ============================================ */

View file

@ -12,7 +12,7 @@ config :mv, Mv.Repo,
port: System.get_env("TEST_POSTGRES_PORT", "5000"), port: System.get_env("TEST_POSTGRES_PORT", "5000"),
database: "mv_test#{System.get_env("MIX_TEST_PARTITION")}", database: "mv_test#{System.get_env("MIX_TEST_PARTITION")}",
pool: Ecto.Adapters.SQL.Sandbox, pool: Ecto.Adapters.SQL.Sandbox,
pool_size: System.schedulers_online() * 4 pool_size: System.schedulers_online() * 2
# We don't run a server during test. If one is required, # We don't run a server during test. If one is required,
# you can enable the server option below. # you can enable the server option below.

View file

@ -75,23 +75,30 @@ defmodule MvWeb.Layouts.Sidebar do
icon="hero-users" icon="hero-users"
label={gettext("Members")} label={gettext("Members")}
/> />
<.menu_item
href={~p"/users"}
icon="hero-user-circle"
label={gettext("Users")}
/>
<.menu_item
href={~p"/custom_field_values"}
icon="hero-rectangle-group"
label={gettext("Custom Fields")}
/>
<!-- Nested Menu: Contributions -->
<.menu_group
icon="hero-currency-dollar"
label={gettext("Contributions")}
>
<.menu_subitem href="/contribution_types" label={gettext("Contribution Types")} />
<.menu_subitem href="/membership_fee_settings" label={gettext("Settings")} />
</.menu_group>
<.menu_item <.menu_item
href={~p"/membership_fee_types"} href={~p"/settings"}
icon="hero-currency-euro" icon="hero-cog-6-tooth"
label={gettext("Fee Types")} label={gettext("Settings")}
/> />
<!-- Nested Admin Menu -->
<.menu_group icon="hero-cog-6-tooth" label={gettext("Administration")}>
<.menu_subitem href={~p"/users"} label={gettext("Users")} />
<.menu_subitem href={~p"/admin/roles"} label={gettext("Roles")} />
<.menu_subitem
href={~p"/membership_fee_settings"}
label={gettext("Fee Settings")}
/>
<.menu_subitem href={~p"/settings"} label={gettext("Settings")} />
</.menu_group>
</ul> </ul>
""" """
end end
@ -122,41 +129,43 @@ defmodule MvWeb.Layouts.Sidebar do
defp menu_group(assigns) do defp menu_group(assigns) do
~H""" ~H"""
<!-- Expanded Mode: Always open div structure --> <li role="none" class="menu-group">
<li role="none" class="expanded-menu-group"> <!-- Expanded Mode: Details/Summary -->
<div <details class="expanded-menu-group">
class="flex items-center gap-3" <summary
role="group" class="flex items-center gap-3 cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2"
aria-label={@label} role="menuitem"
> aria-haspopup="true"
<.icon name={@icon} class="size-5 shrink-0" aria-hidden="true" /> >
<span class="menu-label">{@label}</span> <.icon name={@icon} class="size-5 shrink-0" aria-hidden="true" />
<span class="menu-label">{@label}</span>
</summary>
<ul role="menu" class="ml-4">
{render_slot(@inner_block)}
</ul>
</details>
<!-- Collapsed Mode: Dropdown -->
<div class="collapsed-menu-group dropdown dropdown-right">
<button
type="button"
tabindex="0"
class="flex items-center w-full p-2 rounded-lg hover:bg-base-300 tooltip tooltip-right focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2"
data-tip={@label}
aria-haspopup="menu"
aria-label={@label}
>
<.icon name={@icon} class="size-5" aria-hidden="true" />
</button>
<ul
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box shadow-lg z-50 min-w-48 p-2 focus:outline-none"
role="menu"
>
<li class="menu-title">{@label}</li>
{render_slot(@inner_block)}
</ul>
</div> </div>
<ul role="menu" class="ml-4">
{render_slot(@inner_block)}
</ul>
</li> </li>
<!-- Collapsed Mode: Dropdown -->
<div class="collapsed-menu-group dropdown dropdown-right">
<button
type="button"
tabindex="0"
class="flex items-center gap-3 px-2 py-1.5 rounded-selector hover:bg-base-300 tooltip tooltip-right focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 cursor-pointer"
role="menuitem"
data-tip={@label}
aria-haspopup="menu"
aria-label={@label}
>
<.icon name={@icon} class="size-5 shrink-0" aria-hidden="true" />
</button>
<ul
class="dropdown-content menu bg-base-100 rounded-box shadow-lg z-50 min-w-48 p-2 focus:outline-none"
role="menu"
>
<li class="menu-title">{@label}</li>
{render_slot(@inner_block)}
</ul>
</div>
""" """
end end

View file

@ -631,6 +631,7 @@ msgstr "Benutzerdefinierter Feldwert erfolgreich %{action}"
msgid "Please select a custom field first" msgid "Please select a custom field first"
msgstr "Bitte wähle zuerst ein Benutzerdefiniertes Feld" msgstr "Bitte wähle zuerst ein Benutzerdefiniertes Feld"
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -914,6 +915,7 @@ msgstr "Beitragsart ändern"
msgid "Contribution Start" msgid "Contribution Start"
msgstr "Beitragsbeginn" msgstr "Beitragsbeginn"
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Contribution Types" msgid "Contribution Types"
@ -924,6 +926,11 @@ msgstr "Beitragsarten"
msgid "Contribution type" msgid "Contribution type"
msgstr "Beitragsart" msgstr "Beitragsart"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions"
msgstr "Beiträge"
#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
msgid "Contributions for %{name}" msgid "Contributions for %{name}"
@ -2181,28 +2188,3 @@ msgstr "Mitglied wurde erfolgreich erstellt"
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member updated successfully" msgid "Member updated successfully"
msgstr "Mitglied wurde erfolgreich aktualisiert" msgstr "Mitglied wurde erfolgreich aktualisiert"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Roles"
msgstr "Rollen"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Fee Settings"
msgstr "Beitragseinstellungen"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Fee Types"
msgstr "Beitragstypen"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Administration"
msgstr "Administration"
#~ #: lib/mv_web/components/layouts/sidebar.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Contributions"
#~ msgstr "Beiträge"

View file

@ -632,6 +632,7 @@ msgstr ""
msgid "Please select a custom field first" msgid "Please select a custom field first"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
@ -915,6 +916,7 @@ msgstr ""
msgid "Contribution Start" msgid "Contribution Start"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Contribution Types" msgid "Contribution Types"
@ -925,6 +927,11 @@ msgstr ""
msgid "Contribution type" msgid "Contribution type"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Contributions"
msgstr ""
#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Contributions for %{name}" msgid "Contributions for %{name}"
@ -2182,23 +2189,3 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member updated successfully" msgid "Member updated successfully"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Roles"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Fee Settings"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Fee Types"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Administration"
msgstr ""

View file

@ -632,6 +632,7 @@ msgstr ""
msgid "Please select a custom field first" msgid "Please select a custom field first"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex #: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex #: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy #, elixir-autogen, elixir-format, fuzzy
@ -915,6 +916,7 @@ msgstr ""
msgid "Contribution Start" msgid "Contribution Start"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex #: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Contribution Types" msgid "Contribution Types"
@ -925,6 +927,11 @@ msgstr ""
msgid "Contribution type" msgid "Contribution type"
msgstr "" msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Contributions"
msgstr ""
#: lib/mv_web/live/contribution_period_live/show.ex #: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Contributions for %{name}" msgid "Contributions for %{name}"
@ -2182,33 +2189,3 @@ msgstr "Member created successfully"
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Member updated successfully" msgid "Member updated successfully"
msgstr "Member updated successfully" msgstr "Member updated successfully"
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Roles"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Fee Settings"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Fee Types"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#, elixir-autogen, elixir-format
msgid "Administration"
msgstr ""
#~ #: lib/mv_web/components/layouts/sidebar.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Admin"
#~ msgstr ""
#~ #: lib/mv_web/components/layouts/sidebar.ex
#~ #, elixir-autogen, elixir-format
#~ msgid "Contributions"
#~ msgstr ""

View file

@ -122,34 +122,35 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T2.2: does not render menu items when current_user is nil" do test "T2.2: does not render menu items when current_user is nil" do
html = render_sidebar(guest_assigns()) html = render_sidebar(guest_assigns())
# Navigation menu should not be rendered # Navigation links should not be rendered
refute html =~ ~s(role="menubar") refute html =~ ~s(href="/members")
refute html =~ ~s(role="menuitem") refute html =~ ~s(href="/users")
refute html =~ ~s(href="/settings")
refute html =~ ~s(href="/contribution_types")
# Footer section should not be rendered # Footer section should not be rendered
refute html =~ "theme-controller"
refute html =~ "locale-select" refute html =~ "locale-select"
refute html =~ "theme-controller"
end end
test "T2.3: renders menu items when current_user is present" do test "T2.3: renders menu items when current_user is present" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check that menu structure exists # Check for Members link
assert html =~ ~s(role="menubar") assert html =~ ~s(href="/members")
assert html =~ ~s(role="menuitem")
# Check that top-level menu items exist (at least one) # Check for Users link
# Count menu items with tooltips (top-level items have tooltips) assert html =~ ~s(href="/users")
menu_item_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
assert menu_item_count > 0, "Should have at least one top-level menu item"
# Check that nested menu groups exist # Check for Custom Fields link
assert html =~ ~s(<li role="none" class="expanded-menu-group">) assert html =~ ~s(href="/custom_field_values")
assert html =~ ~s(role="group")
assert has_class?(html, "expanded-menu-group")
# Check that nested menu items exist # Check for Contributions section
assert html =~ ~s(role="menu") assert html =~ ~s(href="/contribution_types")
assert html =~ ~s(href="/membership_fee_settings")
# Check for Settings link (placeholder)
assert html =~ ~s(href="/settings")
end end
test "T2.4: renders sidebar with main-sidebar ID" do test "T2.4: renders sidebar with main-sidebar ID" do
@ -173,59 +174,51 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T3.1: renders flat menu items with icons and labels" do test "T3.1: renders flat menu items with icons and labels" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check that top-level menu items have structure # Check for Members link with icon
# Top-level items have tooltips assert html =~ ~s(href="/members")
assert html =~ "hero-users"
# Check for Users link with icon
assert html =~ ~s(href="/users")
assert html =~ "hero-user-circle"
# Check for Custom Fields link with icon
assert html =~ ~s(href="/custom_field_values")
assert html =~ "hero-rectangle-group"
# Check for Settings link with icon
assert html =~ ~s(href="/settings")
assert html =~ "hero-cog-6-tooth"
# Check for tooltips (data-tip attribute)
assert html =~ "data-tip=" assert html =~ "data-tip="
assert has_class?(html, "tooltip")
assert has_class?(html, "tooltip-right")
# Check that menu items have icons (hero-* classes)
assert html =~ ~r/hero-\w+/
# Check that menu items have labels
assert has_class?(html, "menu-label")
# Check that menu items have links
assert html =~ ~s(role="menuitem")
end end
test "T3.2: renders nested menu with details element for expanded state" do test "T3.2: renders nested menu with details element for expanded state" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check for nested menu structure # Check for Contributions section structure with details
assert html =~ ~s(<li role="none" class="expanded-menu-group">) assert html =~ "<details"
assert html =~ ~s(role="group")
assert html =~ ~s(aria-label="Administration")
assert has_class?(html, "expanded-menu-group") assert has_class?(html, "expanded-menu-group")
# Check that nested menu has subitems # Check for contribution links
assert html =~ ~s(role="menu") assert html =~ ~s(href="/contribution_types")
assert html =~ ~s(href="/membership_fee_settings")
# Check that subitems exist (at least one link in nested menu)
# Submenu items have role="menuitem" but no data-tip attribute
# (Top-level items have data-tip, nested items don't)
# Count menuitems vs data-tips - nested items don't have data-tip
menuitem_count = html |> String.split(~s(role="menuitem")) |> length() |> Kernel.-(1)
data_tip_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
# There should be more menuitems than data-tips (nested items don't have data-tip)
assert menuitem_count > data_tip_count,
"Should have nested menu items (menuitems without data-tip)"
end end
test "T3.3: renders nested menu with dropdown for collapsed state" do test "T3.3: renders nested menu with dropdown for collapsed state" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check for collapsed dropdown structure # Check for collapsed dropdown container
assert has_class?(html, "collapsed-menu-group") assert has_class?(html, "collapsed-menu-group")
assert has_class?(html, "dropdown") assert has_class?(html, "dropdown")
assert has_class?(html, "dropdown-right") assert has_class?(html, "dropdown-right")
# Check for dropdown-content
assert has_class?(html, "dropdown-content") assert has_class?(html, "dropdown-content")
# Check that dropdown button has icon (any hero icon) # Check for icon button
assert html =~ ~r/hero-\w+/ assert html =~ "hero-currency-dollar"
# Check ARIA attributes
assert html =~ ~s(aria-haspopup="menu") assert html =~ ~s(aria-haspopup="menu")
end end
end end
@ -353,9 +346,8 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T5.4: nested menu has correct ARIA attributes" do test "T5.4: nested menu has correct ARIA attributes" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Expanded mode should have role="group" with aria-label # Details summary should have haspopup
assert html =~ ~s(role="group") assert html =~ ~s(aria-haspopup="true")
assert html =~ ~s(aria-label="Administration")
# Dropdown button should have haspopup # Dropdown button should have haspopup
assert html =~ ~s(aria-haspopup="menu") assert html =~ ~s(aria-haspopup="menu")
@ -422,17 +414,17 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T7.1: renders hero icons for menu items" do test "T7.1: renders hero icons for menu items" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check that hero icons are present (pattern matching) # Check for hero icons
assert html =~ ~r/hero-\w+/ assert html =~ "hero-users"
assert html =~ "hero-user-circle"
# Check that icons have aria-hidden assert html =~ "hero-rectangle-group"
assert html =~ ~s(aria-hidden="true") assert html =~ "hero-currency-dollar"
assert html =~ "hero-cog-6-tooth"
# Check for specific structural icons (toggle, theme) that should always exist
assert html =~ "hero-chevron-left" assert html =~ "hero-chevron-left"
assert html =~ "hero-chevron-right" assert html =~ "hero-chevron-right"
assert html =~ "hero-sun"
assert html =~ "hero-moon" # Icons should have aria-hidden
assert html =~ ~s(aria-hidden="true")
end end
test "T7.2: renders icons for theme toggle" do test "T7.2: renders icons for theme toggle" do
@ -511,25 +503,26 @@ defmodule MvWeb.Layouts.SidebarTest do
# Header section # Header section
assert html =~ "Mila Logo" assert html =~ "Mila Logo"
assert html =~ ~s(src="/images/mila.svg")
# Navigation section # Navigation section
assert html =~ ~s(role="menubar") assert html =~ ~s(role="menubar")
assert html =~ ~s(id="main-sidebar")
# Check that menu has items (at least one top-level item)
assert html =~ ~s(role="menuitem")
# Check that nested menus exist
assert html =~ ~s(<li role="none" class="expanded-menu-group">)
assert html =~ ~s(role="group")
# Footer section # Footer section
assert html =~ "theme-controller" assert html =~ "theme-controller"
assert html =~ ~s(action="/set_locale")
# Check that critical navigation exists (at least /members) # All expected links
assert html =~ ~s(href="/members"), "Critical /members route should exist" expected_links = [
"/members",
"/users",
"/custom_field_values",
"/contribution_types",
"/membership_fee_settings",
"/sign-out"
]
for link <- expected_links do
assert html =~ ~s(href="#{link}"), "Missing link: #{link}"
end
end end
end end
@ -628,10 +621,9 @@ defmodule MvWeb.Layouts.SidebarTest do
test "renders expanded menu group" do test "renders expanded menu group" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# expanded-menu-group structure present # details/summary present
assert html =~ ~s(<li role="none" class="expanded-menu-group">) assert html =~ "<details"
assert html =~ ~s(role="group") assert html =~ "<summary"
assert html =~ ~s(aria-label="Administration")
assert has_class?(html, "expanded-menu-group") assert has_class?(html, "expanded-menu-group")
end end
@ -647,21 +639,9 @@ defmodule MvWeb.Layouts.SidebarTest do
test "renders submenu items" do test "renders submenu items" do
html = render_sidebar(authenticated_assigns()) html = render_sidebar(authenticated_assigns())
# Check that nested menu structure exists # Inner_block items rendered
assert html =~ ~s(role="menu") assert html =~ ~s(href="/contribution_types")
assert html =~ ~s(href="/membership_fee_settings")
# Check that subitems are rendered (links within nested menu)
# Submenu items have role="menuitem" but no data-tip attribute
# (Top-level items have data-tip, nested items don't)
# Count menuitems vs data-tips - nested items don't have data-tip
menuitem_count = html |> String.split(~s(role="menuitem")) |> length() |> Kernel.-(1)
data_tip_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
# There should be more menuitems than data-tips (nested items don't have data-tip)
assert menuitem_count > data_tip_count,
"Should have nested menu items (menuitems without data-tip)"
# Verify nested menu structure exists
assert html =~ ~s(role="menu") assert html =~ ~s(role="menu")
end end
end end
@ -841,10 +821,9 @@ defmodule MvWeb.Layouts.SidebarTest do
assert has_class?(html, "expanded-menu-group") assert has_class?(html, "expanded-menu-group")
assert has_class?(html, "collapsed-menu-group") assert has_class?(html, "collapsed-menu-group")
# Expanded menu group should have correct structure # Details element should not have duplicate hover classes
# (CSS handles hover effects, but we verify structure) # (CSS handles this, but we verify structure)
assert html =~ ~s(<li role="none" class="expanded-menu-group">) assert html =~ "<details"
assert html =~ ~s(role="group")
end end
test "tooltips only visible when collapsed" do test "tooltips only visible when collapsed" do