feat: Add application-level settings for CSS color management
Some checks failed
Run Tests / test (push) Failing after 1m51s
Some checks failed
Run Tests / test (push) Failing after 1m51s
- Introduced a new table `application_setting` to store configurable application options. - Implemented functions to manage CSS color settings, including loading, updating, and reading environment overrides. - Added a new settings view to render and manage theme colors. - Updated UI to include a settings page with theme color management and environment overrides display. - Enhanced CSS styles for the settings page and sidebar navigation. - Created unit and end-to-end tests for the new settings functionality and CSS management.
This commit is contained in:
137
tests/unit/test_settings_service.py
Normal file
137
tests/unit/test_settings_service.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from types import SimpleNamespace
|
||||
from typing import Dict
|
||||
|
||||
import pytest
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from models.application_setting import ApplicationSetting
|
||||
from services import settings as settings_service
|
||||
from services.settings import CSS_COLOR_DEFAULTS
|
||||
|
||||
|
||||
@pytest.fixture(name="clean_env")
|
||||
def fixture_clean_env(monkeypatch: pytest.MonkeyPatch) -> Dict[str, str]:
|
||||
"""Provide an isolated environment mapping for tests."""
|
||||
|
||||
env: Dict[str, str] = {}
|
||||
monkeypatch.setattr(settings_service, "os", SimpleNamespace(environ=env))
|
||||
return env
|
||||
|
||||
|
||||
def test_css_key_to_env_var_formatting():
|
||||
assert settings_service.css_key_to_env_var("--color-background") == "CALMINER_THEME_COLOR_BACKGROUND"
|
||||
assert settings_service.css_key_to_env_var("--color-primary-stronger") == "CALMINER_THEME_COLOR_PRIMARY_STRONGER"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"env_key,env_value",
|
||||
[
|
||||
("--color-background", "#ffffff"),
|
||||
("--color-primary", "rgb(10, 20, 30)"),
|
||||
("--color-accent", "rgba(1,2,3,0.5)"),
|
||||
("--color-text-secondary", "hsla(210, 40%, 40%, 1)"),
|
||||
],
|
||||
)
|
||||
def test_read_css_color_env_overrides_valid_values(clean_env, env_key, env_value):
|
||||
env_var = settings_service.css_key_to_env_var(env_key)
|
||||
clean_env[env_var] = env_value
|
||||
|
||||
overrides = settings_service.read_css_color_env_overrides(clean_env)
|
||||
assert overrides[env_key] == env_value
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_value",
|
||||
[
|
||||
"", # empty
|
||||
"not-a-color", # arbitrary string
|
||||
"#12", # short hex
|
||||
"rgb(1,2)", # malformed rgb
|
||||
],
|
||||
)
|
||||
def test_read_css_color_env_overrides_invalid_values_raise(clean_env, invalid_value):
|
||||
env_var = settings_service.css_key_to_env_var("--color-background")
|
||||
clean_env[env_var] = invalid_value
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
settings_service.read_css_color_env_overrides(clean_env)
|
||||
|
||||
|
||||
def test_read_css_color_env_overrides_ignores_missing(clean_env):
|
||||
overrides = settings_service.read_css_color_env_overrides(clean_env)
|
||||
assert overrides == {}
|
||||
|
||||
|
||||
def test_list_css_env_override_rows_returns_structured_data(clean_env):
|
||||
clean_env[settings_service.css_key_to_env_var("--color-primary")] = "#123456"
|
||||
rows = settings_service.list_css_env_override_rows(clean_env)
|
||||
assert rows == [
|
||||
{
|
||||
"css_key": "--color-primary",
|
||||
"env_var": settings_service.css_key_to_env_var("--color-primary"),
|
||||
"value": "#123456",
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_normalize_color_value_strips_and_validates():
|
||||
assert settings_service._normalize_color_value(" #abcdef ") == "#abcdef"
|
||||
with pytest.raises(ValueError):
|
||||
settings_service._normalize_color_value(123) # type: ignore[arg-type]
|
||||
with pytest.raises(ValueError):
|
||||
settings_service._normalize_color_value(" ")
|
||||
with pytest.raises(ValueError):
|
||||
settings_service._normalize_color_value("#12")
|
||||
|
||||
|
||||
def test_ensure_css_color_settings_creates_defaults(db_session: Session):
|
||||
settings_service.ensure_css_color_settings(db_session)
|
||||
|
||||
stored = {
|
||||
record.key: record.value
|
||||
for record in db_session.query(ApplicationSetting).all()
|
||||
}
|
||||
assert set(stored.keys()) == set(CSS_COLOR_DEFAULTS.keys())
|
||||
assert stored == CSS_COLOR_DEFAULTS
|
||||
|
||||
|
||||
def test_update_css_color_settings_persists_changes(db_session: Session):
|
||||
settings_service.ensure_css_color_settings(db_session)
|
||||
|
||||
updated = settings_service.update_css_color_settings(
|
||||
db_session,
|
||||
{"--color-background": "#000000", "--color-accent": "#abcdef"},
|
||||
)
|
||||
|
||||
assert updated["--color-background"] == "#000000"
|
||||
assert updated["--color-accent"] == "#abcdef"
|
||||
|
||||
stored = {
|
||||
record.key: record.value
|
||||
for record in db_session.query(ApplicationSetting).all()
|
||||
}
|
||||
assert stored["--color-background"] == "#000000"
|
||||
assert stored["--color-accent"] == "#abcdef"
|
||||
|
||||
|
||||
def test_get_css_color_settings_respects_env_overrides(
|
||||
db_session: Session, clean_env: Dict[str, str]
|
||||
):
|
||||
settings_service.ensure_css_color_settings(db_session)
|
||||
override_value = "#112233"
|
||||
clean_env[settings_service.css_key_to_env_var("--color-background")] = (
|
||||
override_value
|
||||
)
|
||||
|
||||
values = settings_service.get_css_color_settings(db_session)
|
||||
|
||||
assert values["--color-background"] == override_value
|
||||
|
||||
db_value = (
|
||||
db_session.query(ApplicationSetting)
|
||||
.filter_by(key="--color-background")
|
||||
.one()
|
||||
.value
|
||||
)
|
||||
assert db_value != override_value
|
||||
Reference in New Issue
Block a user