11from fastapi .testclient import TestClient
22from httpx import Response
3- from sqlmodel import Session
4- from unittest .mock import patch
5-
3+ from sqlmodel import Session , select
4+ from unittest .mock import patch , MagicMock
5+ from tests . conftest import SetupError
66from main import app
7- from utils .models import User , Role
7+ from utils .models import User , Role , Organization
88from utils .images import InvalidImageError
9+ import re
10+ import pytest
911
1012# Mock data for consistent testing
1113MOCK_IMAGE_DATA = b"processed fake image data"
@@ -57,7 +59,9 @@ def test_update_profile_unauthorized(unauth_client: TestClient):
5759
5860
5961@patch ('routers.user.validate_and_process_image' )
60- def test_update_profile_authorized (mock_validate , auth_client : TestClient , test_user : User , session : Session ):
62+ def test_update_profile_authorized (
63+ mock_validate : MagicMock , auth_client : TestClient , test_user : User , session : Session
64+ ):
6165 """Test that authorized users can edit their profile"""
6266
6367 # Configure mock to return processed image data
@@ -157,7 +161,9 @@ def test_delete_account_success(auth_client: TestClient, test_user: User, sessio
157161
158162
159163@patch ('routers.user.validate_and_process_image' )
160- def test_get_avatar_authorized (mock_validate , auth_client : TestClient , test_user : User ):
164+ def test_get_avatar_authorized (
165+ mock_validate : MagicMock , auth_client : TestClient , test_user : User
166+ ):
161167 """Test getting user avatar"""
162168 # Configure mock to return processed image data
163169 mock_validate .return_value = (MOCK_IMAGE_DATA , MOCK_CONTENT_TYPE )
@@ -194,7 +200,9 @@ def test_get_avatar_unauthorized(unauth_client: TestClient):
194200
195201# Add new test for invalid image
196202@patch ('routers.user.validate_and_process_image' )
197- def test_update_profile_invalid_image (mock_validate , auth_client : TestClient ):
203+ def test_update_profile_invalid_image (
204+ mock_validate : MagicMock , auth_client : TestClient
205+ ):
198206 """Test that invalid images are rejected"""
199207 # Configure mock to raise InvalidImageError
200208 mock_validate .side_effect = InvalidImageError ("Invalid test image" )
@@ -214,8 +222,13 @@ def test_update_profile_invalid_image(mock_validate, auth_client: TestClient):
214222
215223# --- Multi-Organization Profile Tests ---
216224
217- def test_profile_displays_multiple_organizations (auth_client , test_user , session , test_organization , second_test_organization ):
225+ def test_profile_displays_multiple_organizations (
226+ auth_client : TestClient , test_user : User , session : Session , test_organization : Organization , second_test_organization : Organization
227+ ):
218228 """Test that a user's profile page displays all organizations they belong to"""
229+ if second_test_organization .id is None :
230+ raise SetupError ("Second test organization ID is None" )
231+
219232 # Ensure test_user is part of both organizations
220233 # First org should already be set up through the org_owner fixture
221234 # Now add to second org
@@ -226,50 +239,47 @@ def test_profile_displays_multiple_organizations(auth_client, test_user, session
226239 test_user .roles .append (member_role )
227240 session .add (member_role )
228241 session .commit ()
229-
242+
230243 # Visit profile page
231244 response = auth_client .get ("/user/profile" )
232245 assert response .status_code == 200
233-
246+
234247 # Check that both organizations are displayed
235248 assert test_organization .name in response .text
236249 assert second_test_organization .name in response .text
237250
238251
239- def test_profile_displays_organization_list (auth_client , test_user , session , test_organization ):
252+ def test_profile_displays_organization_list (
253+ auth_client_owner : TestClient , session : Session , test_organization : Organization
254+ ):
240255 """Test that the profile page shows organizations in a macro-rendered list"""
241- response = auth_client .get ("/user/profile" )
256+
257+ response = auth_client_owner .get ("/user/profile" )
242258 assert response .status_code == 200
243259
244- # Check that organizations are rendered in a list
245- assert "Organizations" in response .text
246- assert test_organization .name in response .text
247- assert f"/organizations/{ test_organization .id } " in response .text
248-
249-
250- def test_profile_organization_roles (auth_client , test_user , session , test_organization , second_test_organization ):
251- """Test that the profile shows the user's roles in each organization"""
252- # Add user to a second organization with a different role
253- admin_role = Role (
254- name = "Administrator" ,
255- organization_id = second_test_organization .id
260+ # Find the entire Organizations card section using regex
261+ # This regex looks for the card div, the header with "Organizations" and the button,
262+ # and captures everything until the next card's div or the end of the container
263+ org_section_match = re .search (
264+ r'(<div class="card mb-4">\s*<div class="card-header.*?">\s*Organizations\s*<button.*?</div>.*?<div class="card-body">.*?</div>\s*</div>)' ,
265+ response .text ,
266+ re .DOTALL # Allow . to match newline characters
256267 )
257- test_user .roles .append (admin_role )
258- session .add (admin_role )
259- session .commit ()
260268
261- # Visit profile page
262- response = auth_client .get ("/user/profile" )
263- assert response .status_code == 200
269+ # Check that the organizations section was found
270+ assert org_section_match , "Organizations card section not found in profile HTML"
264271
265- # Check that both organizations and roles are displayed
266- assert test_organization .name in response .text
267- assert second_test_organization .name in response .text
268- assert "Owner" in response .text # From the first org
269- assert "Administrator" in response .text # From the second org
272+ # Extract the matched HTML for the organizations section
273+ org_section_html = org_section_match .group (1 )
274+
275+ # Check that the organization name and link are rendered within this specific section
276+ assert test_organization .name in org_section_html , f"Organization name '{ test_organization .name } ' not found within the organizations card section"
277+ assert f"/organizations/{ test_organization .id } " in org_section_html , f"Organization link '/organizations/{ test_organization .id } ' not found within the organizations card section"
270278
271279
272- def test_profile_no_organizations (auth_client , session , test_user ):
280+ def test_profile_no_organizations (
281+ auth_client : TestClient , test_user : User , session : Session
282+ ):
273283 """Test profile display when user has no organizations"""
274284 # Remove user from all orgs by clearing roles
275285 test_user .roles = []
0 commit comments