From 6033e33622e5f383cea946aeabc8ebf10dca2b16 Mon Sep 17 00:00:00 2001 From: Simon Date: Mon, 29 Sep 2025 13:07:43 +0200 Subject: [PATCH] test: add tdd tests for #170 --- .../mv_web/components/layouts/navbar_test.exs | 76 +++++++++ test/mv_web/live/profile_navigation_test.exs | 147 ++++++++++++++++++ test/support/conn_case.ex | 9 ++ 3 files changed, 232 insertions(+) create mode 100644 test/mv_web/components/layouts/navbar_test.exs create mode 100644 test/mv_web/live/profile_navigation_test.exs diff --git a/test/mv_web/components/layouts/navbar_test.exs b/test/mv_web/components/layouts/navbar_test.exs new file mode 100644 index 0000000..514d343 --- /dev/null +++ b/test/mv_web/components/layouts/navbar_test.exs @@ -0,0 +1,76 @@ +defmodule MvWeb.Layouts.NavbarTest do + use MvWeb.ConnCase, async: true + import Phoenix.LiveViewTest + + describe "navbar profile section" do + test "renders profile button with correct attributes", %{conn: _conn} do + # Setup: Create a user + user = create_test_user(%{email: "test@example.com"}) + + html = render_component(&MvWeb.Layouts.Navbar.navbar/1, %{ + current_user: user + }) + + # Test dropdown structure + assert html =~ "dropdown-content" + assert html =~ "dropdown-end" + assert html =~ ~s(role="button") + + # Test profile link + assert html =~ ~s(href="/users/#{user.id}") + assert html =~ "Profil" + end + + test "shows user initials in avatar", %{conn: _conn} do + # Setup: Create a user with specific email for testing initials + user = create_test_user(%{email: "test.user@example.com"}) + + html = render_component(&MvWeb.Layouts.Navbar.navbar/1, %{ + current_user: user + }) + + assert html =~ "TU" # Initials from test.user@example.com + end + + test "shows different initials for OIDC user", %{conn: _conn} do + # Setup: Create OIDC user + user_info = %{ + "sub" => "oidc_123", + "preferred_username" => "oidc.user@example.com" + } + oauth_tokens = %{ + "access_token" => "test_token", + "id_token" => "test_id_token" + } + + user = Mv.Accounts.User + |> Ash.Changeset.for_create(:register_with_rauthy, %{ + user_info: user_info, + oauth_tokens: oauth_tokens + }) + |> Ash.create!(domain: Mv.Accounts) + + html = render_component(&MvWeb.Layouts.Navbar.navbar/1, %{ + current_user: user + }) + + assert html =~ "OU" # Initials from oidc.user@example.com + end + + test "includes all required navigation items", %{conn: _conn} do + user = create_test_user(%{email: "test@example.com"}) + + html = render_component(&MvWeb.Layouts.Navbar.navbar/1, %{ + current_user: user + }) + + # Check for all required menu items + assert html =~ "Profil" + assert html =~ "Settings" + assert html =~ "Logout" + + # Check for correct logout path + assert html =~ ~s(href="sign-out") + end + end +end diff --git a/test/mv_web/live/profile_navigation_test.exs b/test/mv_web/live/profile_navigation_test.exs new file mode 100644 index 0000000..fdd725f --- /dev/null +++ b/test/mv_web/live/profile_navigation_test.exs @@ -0,0 +1,147 @@ +defmodule MvWeb.ProfileNavigationTest do + use MvWeb.ConnCase, async: true + import Phoenix.LiveViewTest + + describe "profile navigation" do + test "clicking profile button redirects to current user profile", %{conn: conn} do + # Setup: Create and login a user + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_password_user(conn, user) + {:ok, view, _html} = live(conn, "/") + + # Click the profile button + view |> element("a", "Profil") |> render_click() + + # Verify we're on the profile page + assert_redirected(view, "/users/#{user.id}") + end + + test "profile button is visible on all main pages", %{conn: conn} do + # Setup: Create and login a user + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_password_user(conn, user) + + # Test main routes + for path <- ["/", "/members", "/properties", "/users"] do + {:ok, _view, html} = live(conn, path) + assert html =~ "Profil" + end + end + + test "profile navigation shows correct user data", %{conn: conn} do + # Setup: Create and login a user + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_password_user(conn, user) + + # Navigate to profile + {:ok, view, _html} = live(conn, "/") + view |> element("a", "Profil") |> render_click() + + # Verify profile data + {:ok, _profile_view, html} = live(conn, "/users/#{user.id}") + assert html =~ user.email + assert html =~ "Password Authentication" + assert html =~ "Enabled" + end + end + + describe "navbar" do + test "renders profile button with correct attributes", %{conn: conn} do + # Setup: Create and login a user + user = create_test_user(%{email: "test@example.com"}) + conn = conn_with_password_user(conn, user) + {:ok, _view, html} = live(conn, "/") + + assert html =~ ~s(role="button") + assert html =~ "dropdown-content" + assert html =~ "avatar" + assert html =~ "Profil" + end + + test "shows user initials in avatar", %{conn: conn} do + # Setup: Create and login a user + {:ok, user} = create_test_user(%{email: "test.user@example.com"}) + conn = conn_with_password_user(conn, user) + {:ok, _view, html} = live(conn, "/") + + assert html =~ "TU" # Initials from test.user@example.com + end + end + + describe "profile navigation with OIDC user" do + test "shows correct profile data for OIDC user", %{conn: conn} do + # Setup: Create OIDC user with sub claim + user_info = %{ + "sub" => "oidc_123", + "preferred_username" => "oidc.user@example.com" + } + oauth_tokens = %{ + "access_token" => "test_token", + "id_token" => "test_id_token" + } + + {:ok, user} = Mv.Accounts.User + |> Ash.Changeset.for_create(:register_with_rauthy, %{ + user_info: user_info, + oauth_tokens: oauth_tokens + }) + |> Ash.create!(domain: Mv.Accounts) + + # Login user via OIDC + conn = conn_with_oidc_user(conn, %{ + email: "oidc.user@example.com", + oidc_id: "oidc_123" + }) + + # Navigate to home and click profile + {:ok, view, _html} = live(conn, "/") + view |> element("a", "Profil") |> render_click() + + # Verify we're on the correct profile page with OIDC specific information + {:ok, _profile_view, html} = live(conn, "/users/#{user.id}") + assert html =~ "oidc.user@example.com" + assert html =~ "oidc_123" # OIDC ID should be visible + refute html =~ "Password Authentication" # Should not show password info for OIDC users + end + + test "profile navigation works across different authentication methods", %{conn: conn} do + # Create password user + password_user = create_test_user(%{ + email: "password@example.com", + password: "test_password123" + }) + + # Create OIDC user + user_info = %{ + "sub" => "oidc_789", + "preferred_username" => "oidc@example.com" + } + oauth_tokens = %{ + "access_token" => "test_token", + "id_token" => "test_id_token" + } + {:ok, oidc_user} = Mv.Accounts.User + |> Ash.Changeset.for_create(:register_with_rauthy, %{ + user_info: user_info, + oauth_tokens: oauth_tokens + }) + |> Ash.create!(domain: Mv.Accounts) + + # Test with password user + conn_password = conn_with_password_user(conn, password_user) + {:ok, view_password, _html} = live(conn_password, "/") + view_password |> element("a", "Profil") |> render_click() + assert_redirected(view_password, "/users/#{password_user.id}") + + # Test with OIDC user + conn_oidc = conn_with_oidc_user(conn, %{ + email: "oidc@example.com", + oidc_id: "oidc_789" + }) + {:ok, view_oidc, _html} = live(conn_oidc, "/") + view_oidc |> element("a", "Profil") |> render_click() + assert_redirected(view_oidc, "/users/#{oidc_user.id}") + end + end + +end diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index c51fb61..da2e60d 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -105,6 +105,15 @@ defmodule MvWeb.ConnCase do sign_in_user_via_oidc(conn, user) end + @doc """ + Signs in a user via password authentication and returns a connection with the user authenticated. + """ + def conn_with_password_user(conn, user) do + conn + |> Phoenix.ConnTest.init_test_session(%{}) + |> AshAuthentication.Plug.Helpers.store_in_session(user) + end + setup tags do Mv.DataCase.setup_sandbox(tags) {:ok, conn: Phoenix.ConnTest.build_conn()}