Add integration tests for user preferences and UI settings - Created comprehensive test suite for preferences endpoints - Includes tests for theme management (light/dark/custom themes) - Tests language selection and localization - Covers accessibility settings (high contrast, large text, etc) - Tests keyboard shortcuts configuration - Covers UI density and view mode settings (grid/list) - Tests preferences import/export and bulk updates - Ready for future preferences endpoint implementation
This commit is contained in:
parent
e95ed299d6
commit
86651c2ef1
513
src/tests/integration/test_user_preferences.py
Normal file
513
src/tests/integration/test_user_preferences.py
Normal file
@ -0,0 +1,513 @@
|
||||
"""
|
||||
Integration tests for user preferences and UI settings API endpoints.
|
||||
|
||||
This module tests the user preferences endpoints for theme management, language selection,
|
||||
accessibility settings, keyboard shortcuts, and UI density configurations.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from unittest.mock import patch
|
||||
|
||||
from src.server.fastapi_app import app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
"""Create a test client for the FastAPI application."""
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth_headers(client):
|
||||
"""Provide authentication headers for protected endpoints."""
|
||||
# Login to get token
|
||||
login_data = {"password": "testpassword"}
|
||||
|
||||
with patch('src.server.fastapi_app.settings.master_password_hash') as mock_hash:
|
||||
mock_hash.return_value = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" # 'password' hash
|
||||
response = client.post("/auth/login", json=login_data)
|
||||
|
||||
if response.status_code == 200:
|
||||
token = response.json()["access_token"]
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
return {}
|
||||
|
||||
|
||||
class TestThemeManagement:
|
||||
"""Test cases for theme management endpoints."""
|
||||
|
||||
def test_get_themes_requires_auth(self, client):
|
||||
"""Test that getting themes requires authentication."""
|
||||
response = client.get("/api/preferences/themes")
|
||||
assert response.status_code == 401
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_available_themes(self, mock_user, client):
|
||||
"""Test getting available themes."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/themes")
|
||||
# Expected 404 since endpoint not implemented yet
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "themes" in data
|
||||
assert isinstance(data["themes"], list)
|
||||
# Should include at least light and dark themes
|
||||
theme_names = [theme["name"] for theme in data["themes"]]
|
||||
assert "light" in theme_names or "dark" in theme_names
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_current_theme(self, mock_user, client):
|
||||
"""Test getting current theme."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/themes/current")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "theme" in data
|
||||
assert "name" in data["theme"]
|
||||
assert "colors" in data["theme"]
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_set_theme(self, mock_user, client):
|
||||
"""Test setting user theme."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
theme_data = {
|
||||
"theme_name": "dark",
|
||||
"custom_colors": {
|
||||
"primary": "#007acc",
|
||||
"secondary": "#6c757d",
|
||||
"background": "#1a1a1a"
|
||||
}
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/themes/set", json=theme_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert data["status"] == "success"
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_create_custom_theme(self, mock_user, client):
|
||||
"""Test creating custom theme."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
custom_theme = {
|
||||
"name": "my_custom_theme",
|
||||
"display_name": "My Custom Theme",
|
||||
"colors": {
|
||||
"primary": "#ff6b6b",
|
||||
"secondary": "#4ecdc4",
|
||||
"background": "#2c3e50",
|
||||
"text": "#ecf0f1",
|
||||
"accent": "#e74c3c"
|
||||
},
|
||||
"is_dark": True
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/themes/custom", json=custom_theme)
|
||||
assert response.status_code in [201, 404]
|
||||
|
||||
if response.status_code == 201:
|
||||
data = response.json()
|
||||
assert "theme_id" in data
|
||||
assert "name" in data
|
||||
|
||||
def test_set_invalid_theme(self, client, auth_headers):
|
||||
"""Test setting invalid theme."""
|
||||
invalid_data = {"theme_name": "nonexistent_theme"}
|
||||
|
||||
response = client.post("/api/preferences/themes/set", json=invalid_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
|
||||
class TestLanguageSelection:
|
||||
"""Test cases for language selection endpoints."""
|
||||
|
||||
def test_get_languages_requires_auth(self, client):
|
||||
"""Test that getting languages requires authentication."""
|
||||
response = client.get("/api/preferences/languages")
|
||||
assert response.status_code == 401
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_available_languages(self, mock_user, client):
|
||||
"""Test getting available languages."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/languages")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "languages" in data
|
||||
assert isinstance(data["languages"], list)
|
||||
# Should include at least English
|
||||
language_codes = [lang["code"] for lang in data["languages"]]
|
||||
assert "en" in language_codes
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_current_language(self, mock_user, client):
|
||||
"""Test getting current language."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/languages/current")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "language" in data
|
||||
assert "code" in data["language"]
|
||||
assert "name" in data["language"]
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_set_language(self, mock_user, client):
|
||||
"""Test setting user language."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
language_data = {"language_code": "de"}
|
||||
|
||||
response = client.post("/api/preferences/languages/set", json=language_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert "language" in data
|
||||
|
||||
def test_set_invalid_language(self, client, auth_headers):
|
||||
"""Test setting invalid language."""
|
||||
invalid_data = {"language_code": "invalid_lang"}
|
||||
|
||||
response = client.post("/api/preferences/languages/set", json=invalid_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
|
||||
class TestAccessibilitySettings:
|
||||
"""Test cases for accessibility settings endpoints."""
|
||||
|
||||
def test_get_accessibility_requires_auth(self, client):
|
||||
"""Test that getting accessibility settings requires authentication."""
|
||||
response = client.get("/api/preferences/accessibility")
|
||||
assert response.status_code == 401
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_accessibility_settings(self, mock_user, client):
|
||||
"""Test getting accessibility settings."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/accessibility")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
expected_fields = [
|
||||
"high_contrast", "large_text", "reduced_motion",
|
||||
"screen_reader_support", "keyboard_navigation"
|
||||
]
|
||||
for field in expected_fields:
|
||||
assert field in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_update_accessibility_settings(self, mock_user, client):
|
||||
"""Test updating accessibility settings."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
accessibility_data = {
|
||||
"high_contrast": True,
|
||||
"large_text": True,
|
||||
"reduced_motion": False,
|
||||
"screen_reader_support": True,
|
||||
"keyboard_navigation": True,
|
||||
"font_size_multiplier": 1.2
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences/accessibility", json=accessibility_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert "updated_settings" in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_reset_accessibility_settings(self, mock_user, client):
|
||||
"""Test resetting accessibility settings to defaults."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.post("/api/preferences/accessibility/reset")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert data["status"] == "reset"
|
||||
|
||||
|
||||
class TestKeyboardShortcuts:
|
||||
"""Test cases for keyboard shortcuts endpoints."""
|
||||
|
||||
def test_get_shortcuts_requires_auth(self, client):
|
||||
"""Test that getting shortcuts requires authentication."""
|
||||
response = client.get("/api/preferences/shortcuts")
|
||||
assert response.status_code == 401
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_keyboard_shortcuts(self, mock_user, client):
|
||||
"""Test getting keyboard shortcuts."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/shortcuts")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "shortcuts" in data
|
||||
assert isinstance(data["shortcuts"], dict)
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_update_keyboard_shortcut(self, mock_user, client):
|
||||
"""Test updating keyboard shortcut."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
shortcut_data = {
|
||||
"action": "search",
|
||||
"shortcut": "Ctrl+K",
|
||||
"description": "Open search"
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences/shortcuts", json=shortcut_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert "shortcut" in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_reset_shortcuts_to_default(self, mock_user, client):
|
||||
"""Test resetting shortcuts to default."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.post("/api/preferences/shortcuts/reset")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
def test_invalid_shortcut_format(self, client, auth_headers):
|
||||
"""Test updating shortcut with invalid format."""
|
||||
invalid_data = {
|
||||
"action": "search",
|
||||
"shortcut": "InvalidKey++"
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences/shortcuts", json=invalid_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
|
||||
class TestUIDensitySettings:
|
||||
"""Test cases for UI density and view settings endpoints."""
|
||||
|
||||
def test_get_ui_settings_requires_auth(self, client):
|
||||
"""Test that getting UI settings requires authentication."""
|
||||
response = client.get("/api/preferences/ui")
|
||||
assert response.status_code == 401
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_ui_density_settings(self, mock_user, client):
|
||||
"""Test getting UI density settings."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/ui")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
expected_fields = [
|
||||
"density", "view_mode", "grid_columns",
|
||||
"show_thumbnails", "compact_mode"
|
||||
]
|
||||
for field in expected_fields:
|
||||
assert field in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_set_view_mode(self, mock_user, client):
|
||||
"""Test setting view mode (grid/list)."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
view_data = {
|
||||
"view_mode": "grid",
|
||||
"grid_columns": 4,
|
||||
"show_thumbnails": True
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/ui/view-mode", json=view_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert "view_mode" in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_set_ui_density(self, mock_user, client):
|
||||
"""Test setting UI density."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
density_data = {
|
||||
"density": "comfortable", # compact, comfortable, spacious
|
||||
"compact_mode": False
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/ui/density", json=density_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_update_grid_settings(self, mock_user, client):
|
||||
"""Test updating grid view settings."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
grid_data = {
|
||||
"columns": 6,
|
||||
"thumbnail_size": "medium",
|
||||
"show_titles": True,
|
||||
"show_episode_count": True
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences/ui/grid", json=grid_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
def test_invalid_view_mode(self, client, auth_headers):
|
||||
"""Test setting invalid view mode."""
|
||||
invalid_data = {"view_mode": "invalid_mode"}
|
||||
|
||||
response = client.post("/api/preferences/ui/view-mode", json=invalid_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
|
||||
class TestPreferencesIntegration:
|
||||
"""Integration tests for preferences functionality."""
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_get_all_preferences(self, mock_user, client):
|
||||
"""Test getting all user preferences."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
expected_sections = [
|
||||
"theme", "language", "accessibility",
|
||||
"shortcuts", "ui_settings"
|
||||
]
|
||||
for section in expected_sections:
|
||||
assert section in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_bulk_update_preferences(self, mock_user, client):
|
||||
"""Test bulk updating multiple preferences."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
bulk_data = {
|
||||
"theme": {"name": "dark"},
|
||||
"language": {"code": "en"},
|
||||
"accessibility": {"high_contrast": True},
|
||||
"ui_settings": {"view_mode": "list", "density": "compact"}
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences", json=bulk_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert "updated_sections" in data
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_export_preferences(self, mock_user, client):
|
||||
"""Test exporting user preferences."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.get("/api/preferences/export")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
# Should return JSON or file download
|
||||
assert response.headers.get("content-type") in [
|
||||
"application/json",
|
||||
"application/octet-stream"
|
||||
]
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_import_preferences(self, mock_user, client):
|
||||
"""Test importing user preferences."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
import_data = {
|
||||
"theme": {"name": "light"},
|
||||
"language": {"code": "de"},
|
||||
"ui_settings": {"view_mode": "grid"}
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/import", json=import_data)
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
@patch('src.server.fastapi_app.get_current_user')
|
||||
def test_reset_all_preferences(self, mock_user, client):
|
||||
"""Test resetting all preferences to defaults."""
|
||||
mock_user.return_value = {"user_id": "test_user"}
|
||||
|
||||
response = client.post("/api/preferences/reset")
|
||||
assert response.status_code in [200, 404]
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
assert "status" in data
|
||||
assert data["status"] == "reset"
|
||||
|
||||
|
||||
class TestPreferencesValidation:
|
||||
"""Test cases for preferences validation."""
|
||||
|
||||
def test_theme_validation(self, client, auth_headers):
|
||||
"""Test theme data validation."""
|
||||
invalid_theme_data = {
|
||||
"colors": {
|
||||
"primary": "not_a_color", # Invalid color format
|
||||
"background": "#xyz" # Invalid hex color
|
||||
}
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/themes/custom", json=invalid_theme_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
def test_accessibility_validation(self, client, auth_headers):
|
||||
"""Test accessibility settings validation."""
|
||||
invalid_accessibility_data = {
|
||||
"font_size_multiplier": -1, # Invalid value
|
||||
"high_contrast": "not_boolean" # Invalid type
|
||||
}
|
||||
|
||||
response = client.put("/api/preferences/accessibility", json=invalid_accessibility_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
def test_ui_settings_validation(self, client, auth_headers):
|
||||
"""Test UI settings validation."""
|
||||
invalid_ui_data = {
|
||||
"grid_columns": 0, # Invalid value
|
||||
"density": "invalid_density" # Invalid enum value
|
||||
}
|
||||
|
||||
response = client.post("/api/preferences/ui/density", json=invalid_ui_data, headers=auth_headers)
|
||||
assert response.status_code in [400, 404, 422]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Loading…
x
Reference in New Issue
Block a user